Who this is for: DevOps engineers, self‑hosted n8n operators, and security‑focused developers who need to protect a publicly reachable n8n instance. We cover this in detail in the n8n Security & Hardening Guide.
Quick diagnosis
The n8n API is exposed without request‑throttling by default. An attacker can flood /rest/* endpoints (including workflow execution) with thousands of calls per second, exhausting CPU, memory, and database connections → denial‑of‑service (DoS).
Featured‑snippet solution: Add a reverse‑proxy (NGINX or Traefik) in front of n8n and configure a rate‑limit rule of 10 r/s per IP (adjust to your traffic). Reload the proxy and verify that the API returns 429 Too Many Requests when the limit is exceeded.
Why n8n needs API rate limiting ?
If you encounter any docker container misconfigurations resolve them before continuing with the setup.
| Threat | Typical impact on n8n |
|---|---|
| Brute‑force credential guessing | Exhausts login endpoint, locks out legitimate users |
| Workflow execution flood | Spikes CPU, DB connections, queue overflow |
| Mass webhook abuse | Saturates inbound webhook handler, drops legitimate events |
| Scraping / data exfiltration | Large read‑only queries starve the DB |
Why a limit stops it – Caps the number of requests an IP can make, forcing attackers to slow down while preserving resources for genuine traffic.
EEFA note: Do not set the limit too low (e.g., 1 r/s) in production; you’ll block legitimate integrations. Start with a conservative baseline (10 r/s) and tune based on observed traffic patterns.
Choosing the right rate‑limiting layer
| Layer | Pros |
|---|---|
| NGINX (or Apache) reverse proxy | Mature limit_req module, easy per‑IP limits, can be combined with limit_req_zone for burst handling |
| Traefik (Docker‑Compose) | Native middleware, dynamic config via labels, integrates with Docker Swarm/K8s |
| Cloudflare / API‑gateway (e.g., AWS API GW) | Global edge protection, bot‑management, analytics |
| n8n custom middleware (Node.js) | Fine‑grained per‑workflow limits |
| Cons | Typical use‑case |
|---|---|
| Requires separate container or host install | Small‑to‑medium self‑hosted n8n |
| Limited to HTTP‑level limits (no per‑method granularity) | Container‑first deployments |
| Extra cost, adds latency, needs DNS change | Public‑facing n8n instances |
| Requires code change, not officially supported | Highly customized SaaS offering |
EEFA tip: When using a reverse proxy, place the rate‑limiting rule before any authentication middleware so malicious traffic is blocked early. If you encounter any rbac pitfalls resolve them before continuing with the setup.
Implementing rate limiting with NGINX
Step 1 – Define a shared memory zone to store request counters.
# /etc/nginx/conf.d/rate_limit.conf limit_req_zone $binary_remote_addr zone=n8n_api:10m rate=10r/s;
Step 2 – Proxy configuration (basic reverse‑proxy settings).
location / {
proxy_pass http://n8n:5678;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
Step 3 – Apply the rate‑limit rule to the same location.
# Inside the same location block limit_req zone=n8n_api burst=20 nodelay; limit_req_status 429; # Return 429 Too Many Requests
Step 4 – Reload NGINX without downtime
docker exec n8n-nginx nginx -s reload # Docker # or sudo systemctl reload nginx
Step 5 – Verify the limit with a quick curl loop.
for i in {1..30}; do
curl -s -o /dev/null -w "%{http_code} " http://n8n.example.com/rest/workflows;
done
You should see a series of 200 responses followed by 429 once the burst limit is reached. If you encounter any missing audit logging breach detection resolve them before continuing with the setup.
Common pitfalls
| Symptom | Cause | Fix |
|---|---|---|
| 429 on every request | `burst` too low or `nodelay` missing | Increase `burst` or remove `nodelay` |
| No 429, still overloaded | Zone size (`10m`) too small for traffic | Raise zone size (`20m`) or split by `$http_user_agent` |
| Client IP logged as 127.0.0.1 | NGINX behind another proxy without `real_ip` config | Add set_real_ip_from <trusted‑proxy‑ip>; real_ip_header X-Forwarded-For; |
Implementing rate limiting with Traefik (Docker‑Compose)
Step 1 – Base compose file (defines n8n and Traefik services).
version: "3.8"
services:
n8n:
image: n8nio/n8n
environment:
- N8N_HOST=n8n.example.com
ports:
- "5678:5678"
networks:
- n8n-net
traefik:
image: traefik:v2.11
command:
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
- "--api.insecure=true"
ports:
- "80:80"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- n8n-net
networks:
n8n-net:
Step 2 – Add rate‑limit middleware via Docker labels (attached to the n8n service).
n8n:
# …existing config…
labels:
- "traefik.enable=true"
- "traefik.http.routers.n8n.rule=Host(`n8n.example.com`)"
- "traefik.http.routers.n8n.entrypoints=web"
- "traefik.http.services.n8n.loadbalancer.server.port=5678"
# Rate‑limit: 10 r/s, burst up to 20
- "traefik.http.middlewares.n8n-ratelimit.ratelimit.average=10"
- "traefik.http.middlewares.n8n-ratelimit.ratelimit.burst=20"
- "traefik.http.routers.n8n.middlewares=n8n-ratelimit@docker"
Deploy with docker compose up -d and test using the same curl loop as for NGINX.
EEFA considerations for Traefik
- Traefik’s rate‑limit works per‑client IP; if you sit behind a CDN, ensure the real client IP is forwarded (
X-Forwarded-For) and enable the forwarded‑headers middleware. - In Kubernetes, replace Docker labels with an
IngressRouteCRD that references the same middleware.
Detecting and responding to DoS attempts
| Detection method | What to look for | Tooling |
|---|---|---|
| NGINX/Traefik access logs | Sudden spikes of 429 or 200 from a single IP |
awk '{print $1}' | sort | uniq -c | sort -nr | head |
Prometheus metrics (via nginx‑exporter or traefik‑metrics) |
http_requests_total{code="429"} rising sharply |
Grafana alert: rate(http_requests_total{code="429"}[1m]) > 100 |
| Fail2Ban | Repeated 429 from same IP within 5 min |
Custom jail (see below) |
| Cloudflare analytics | “Top threats” → “Rate limiting” | Enable Cloudflare Rate Limiting rule for /rest/* |
Sample Fail2Ban jail for n8n
Jail definition (/etc/fail2ban/jail.d/n8n.conf)
[n8n-rate-limit] enabled = true filter = n8n logpath = /var/log/nginx/access.log maxretry = 5 findtime = 300 bantime = 3600 action = iptables[name=n8n, port=http, protocol=tcp]
Filter (/etc/fail2ban/filter.d/n8n.conf)
[Definition] failregex = ^ - - \[.*\] ".* /rest/.*" 429 ignoreregex =
Restart with systemctl restart fail2ban.
EEFA warning: A CI/CD pipeline that polls
/rest/workflowsevery second may be blocked. Whitelist known service IPs or raisemaxretry. High‑frequency429responses can flood logs—rotate logs frequently (logrotate) and consider sending metrics to a central system instead of raw logs.
Best‑practice checklist & monitoring dashboard
| Checklist item | Recommended setting | Verification |
|---|---|---|
| Rate‑limit rule | 10 r/s per IP, burst 20 | `curl` test returns 429 after 20 rapid calls |
| Real‑client IP | `real_ip_header X-Forwarded-For` (NGINX) or `ForwardedHeaders` (Traefik) | `$remote_addr` shows external IP |
| Burst handling | `nodelay` disabled for smoother throttling | No sudden traffic spikes in Grafana |
| Alerting | Grafana alert on `429` rate > 100 r/s | Alert fires in test environment |
| Fail2Ban | Jail active, whitelist CI IPs | `fail2ban-client status n8n-rate-limit` shows 0 bans after CI run |
| Documentation | Link to “Secure your n8n webhooks” for webhook‑specific limits | Internal link present in “Detecting DoS” section |
EEFA tip: When you adjust thresholds, run a traffic rehearsal (e.g.,
heyork6load test) for at least 5 minutes to ensure legitimate bursts (like bulk data imports) are not unintentionally throttled.
Conclusion
Rate limiting is the most effective first line of defense against API‑driven DoS attacks on n8n. By placing a lightweight reverse proxy (NGINX or Traefik) in front of the application, you can:
- Cap request volume per IP – protecting CPU, memory, and database connections.
- Provide predictable burst handling – allowing legitimate integration spikes while rejecting abuse.
- Enable fast detection – via 429 responses, logs, and metrics that feed into alerts and Fail2Ban.
Implement the 10 r/s baseline, tune it with real traffic, and monitor the 429 metric. This approach safeguards n8n in production without altering the core application code, keeping your workflows responsive and your infrastructure resilient.



