Docs
Skip to content

Firewall

Actions_

Learn Firewall actions in Appwrite: deny, bypass, challenge, rate limit, and redirect, including status codes and rate-limit behavior.

7 min read

Raw

When a request matches a rule's conditions, Appwrite applies the rule action. Only one action runs per request, because evaluation stops at the first matching enabled rule. See Priority.

There is no separate Allow action. Use Bypass to allowlist traffic that should skip later deny or rate limit rules.

Available actions

ActionClient outcome
Deny403 with an access-denied error
BypassRequest continues, and later Firewall rules are skipped
ChallengeClient must pass a challenge before the request continues
Rate limitUnder quota: continue and stop further rules. Over quota: 429 with Retry-After
RedirectHTTP redirect (300 to 399) to the configured location

Response headers

When Firewall stops a request, the response carries two headers that name the rule and the action it applied:

Plain text
X-Appwrite-WAF-Rule: 6f2c1b9a
X-Appwrite-WAF-Action: deny

A challenge adds X-Appwrite-WAF-Challenge-Type. The headers arrive with the response. The traffic overview updates later.

Only API rules add the headers to allowed requests.

Deny

Deny rejects matching requests before they reach your application logic. Use it to block abusive IPs, lock down sensitive paths, or reject traffic from specific countries.

Bypass

Bypass allows the request and stops Firewall evaluation. Later rules (including deny and rate limit) do not run for that request.

Typical uses:

  • Allowlist a trusted office IP before a broader deny rule
  • Exempt health-check user agents or monitoring paths from rate limits

Give bypass rules a lower priority number than the deny or rate limit rules they override, so they run first.

Challenge

Challenge verifies matching requests before allowing them through. Clients that pass the challenge reach your application. Clients that fail do not.

Use challenge instead of deny on paths that attract abuse, such as sign-in and sign-up, where a deny rule would also block legitimate users.

SettingPurposeLimits
DifficultyClient-side proof-of-work cost. Higher values slow automated clients more, and also slow the challenge for legitimate users1 (easiest) to 5 (hardest), Console default 3
TTL (seconds)How long a visitor stays cleared after they pass the challenge900 (15 minutes) to 86400 (24 hours), Console default 1800 (30 minutes)

Only browser navigation gets a challenge page

Appwrite serves the challenge page only for GET requests that accept HTML. Form posts, fetch calls, requests for a site's CSS and images, and every request matched by an API rule get 403 with a challenge-required error instead.

See Challenge automated traffic for a worked example.

Known bots are denied, not challenged

Appwrite denies obvious automated clients before it issues a challenge, including requests with no User-Agent and those containing a marker such as curl/, python-requests, go-http-client, or headlesschrome.

They count as Denied and never as Challenged, so a challenge rule aimed at them does nothing. Use Deny for clients you already know are scripts, and Challenge for traffic that might be a browser.

Clearance lasts for the whole site

Once a visitor solves a challenge, they stay cleared for the length of the TTL across every challenge rule on that hostname, not just the rule that challenged them.

To challenge every visitor to a site without building a rule by hand, use Attack mode.

Rate limit

Rate limit throttles matching requests that go over a quota. Each rule counts its own quota, separately for every client.

SettingPurposeLimits
Request limitRequests allowed per interval1 to 1000000 (Console default 100)
Interval (seconds)Length of the window the request limit applies over1 to 86400 (Console default 60)
Limit byWhat counts as one clientIP address (ip) or User ID (userId), Console default IP address
StrategyHow the quota is enforced over time (see Rate limit strategies)fixedWindow, slidingWindow, or tokenBucket (Console default fixedWindow)
Max bucket sizeToken bucket only: the largest burst allowed. The other strategies ignore it1 to 1000000 (Console default 50)

Appwrite allows a matching request under the quota and skips later rules, the same as a bypass. A request over the quota gets 429 with a Retry-After header.

Treat that header as a minimum wait. With sliding window or token bucket, a client that retries the moment it expires may still be throttled.

If the rate limiter itself is unavailable, Appwrite allows the request. A rule can therefore look inactive during an outage.

You choose the strategy when you create the rule and cannot change it afterward. Through the API, an update that sends a different strategy is ignored without an error.

Per-user quotas

With Limit by set to User ID, each signed-in user gets their own quota, regardless of IP address.

An API rule uses the user already signed in on the request. A Functions or Sites rule reads a user JWT from the x-appwrite-user-jwt header, so your client has to send one.

A request with no signed-in user skips the rule and continues to the rules below it. Every other action stops evaluation on a match. This skip is the only exception.

If signed-out traffic also needs a quota, add a second rule limited by IP address.

Rate limit strategies

All three strategies hold a client to the same rate over time. They differ in how they treat bursts.

Fixed window

5 requests per 15s0 / 5 used11:42:1511:42:30

Requests are counted in back-to-back windows of the interval length, and the count resets at each boundary. Windows follow the clock, not a client's first request, so every client resets at the same moment.

A client can send a full quota at the end of one window and another at the start of the next, so brief bursts of up to twice the limit get through. Choose fixed window when that is acceptable. It is the default.

Sliding window

60 requests per 120s11:42:31first request+120swindow slides with time

The previous window's count fades out instead of resetting, so no boundary burst gets through. Choose sliding window when you want an even rate.

Token bucket

+10 tokens per 60sMax bucket size250 tokensburst spendssaved tokenseach request takes one token

A bucket refills at Request limit per Interval, up to Max bucket size. Each request spends one token, and requests are throttled once the bucket is empty.

A client that has been quiet spends its saved tokens in a burst, while its sustained rate stays at the limit. Choose token bucket for clients that legitimately burst, such as batch writes or retries after a reconnect. Set Max bucket size to the largest burst you are willing to serve, since a misbehaving client can spend it too.

Redirect

Redirect sends matching clients to another URL without running later Firewall rules.

SettingPurpose
Redirect locationAbsolute or path location (for example https://example.com or /maintenance). Default /.
Status codeHTTP redirect status from 300 to 399 (default 302)

Use redirects for maintenance pages and deprecated paths, or to move traffic off a path without denying it.

Was this page helpful?

Share what worked or what we should fix. Once approved, our agents automatically apply suggested updates to the docs.