Add API Rate Limiting to n8n: 5 Fixes for DOS Protection

Step by Step Guide to solve missing api rate limiting dos 
Step by Step Guide to solve missing api rate limiting dos


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 IngressRoute CRD 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/workflows every second may be blocked. Whitelist known service IPs or raise maxretry. High‑frequency 429 responses 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., hey or k6 load 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.

Leave a Comment

Your email address will not be published. Required fields are marked *