Files
fail2ban-ui/docs/reverse-proxy.md

3.6 KiB

Reverse Proxy Deployment Guide

This guide provides production-redy guidance for running Fail2Ban UI behind a reverse proxy.

Why this matters

Fail2Ban UI includes administrative capabilities and callback endpoints. A reverse proxy lets you apply TLS, access controls, and standardized HTTP security policies before traffic reaches the UI.

Basic architecture

Browser / Fail2Ban hosts
          |
      HTTPS (443)
          |
 Reverse Proxy (TLS termination)
          |
HTTP (127.0.0.1:8080)
          |
      Fail2Ban UI

Recommended runtime settings for the above example:

  • BIND_ADDRESS=127.0.0.1 (when proxy and UI run on the same host)
  • PORT=8080 (or another local port)
  • OIDC_ENABLED=true for user authentication (optional but recommended)

Reverse proxy requirements

For correct UI behavior (including WebSocket live updates), the proxy must:

  1. Preserve Host and Origin consistency.
  2. Allow WebSocket upgrades on GET /api/ws.
  3. Forward client IP context (X-Forwarded-For, X-Forwarded-Proto).

Nginx reference configuration

Use this as a baseline and adapt to your hostnames and certificates.

server {
    listen 80;
    server_name fail2ban.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name fail2ban.example.com;

    ssl_certificate     /etc/letsencrypt/live/fail2ban.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/fail2ban.example.com/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
    ssl_session_timeout 1d;
    ssl_session_cache   shared:SSL:10m;

    # Optional strict transport security (don't forget to preload via -> https://hstspreload.org/)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options nosniff always;
    add_header X-Frame-Options DENY always;
    add_header Referrer-Policy no-referrer always;

    # Optional source allowlist
    # allow 10.0.0.0/8;
    # allow 192.168.0.0/16;
    # deny all;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 60s;
        proxy_send_timeout 60s;
    }

    # Proxy WebSocket endpoint
    location /api/ws {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}

Caddy reference configuration

fail2ban.example.com {
    encode zstd gzip

    header {
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        Referrer-Policy "no-referrer"
    }

    reverse_proxy 127.0.0.1:8080
}

Caddy automatically handles TLS and WebSocket upgrades for this basic setup.

Validation checklist / some tests

  1. Validate UI: curl -Ik https://fail2ban.example.com/
  2. Validate API reachability: curl -s https://fail2ban.example.com/api/version
  3. Validate WebSocket in browser dev tools:
    • status 101 Switching Protocols for /api/ws
    • live ban/unban events update without refresh
  4. Validate callback path from managed Fail2Ban hosts to configured CALLBACK_URL