Skip to content

NGINX Reverse Proxy & SSL/TLS Configuration

NGINX reverse proxy setup with SSL termination and WebSocket support.


Overview

The recommended production deployment runs Faraday behind NGINX for:

  • SSL/TLS termination — Encrypt client connections with HTTPS.
  • WebSocket proxying — Real-time notifications and agent communication via Socket.IO.
  • Static file serving — Serve the frontend directly from NGINX.
  • Security headers — Add HSTS, X-Frame-Options, and other protections.
  • Upload limits — Control maximum file upload size.

Architecture

Client (HTTPS :443)
    │
    ▼
┌──────────┐
│  NGINX   │  SSL termination, static files, security headers
│  :443    │
└────┬─────┘
     │ HTTP (internal)
     ├──────────────────► Faraday API    (localhost:5985/_api/)
     └──────────────────► Socket.IO      (localhost:5985/socket.io)

Prerequisites

  • A working Faraday Server installation (listening on localhost:5985).
  • Root or sudo privileges.
  • A domain name or FQDN configured for your server.
  • SSL certificate (self-signed for testing, CA-issued for production).

Install NGINX

Debian/Ubuntu:

sudo apt install nginx

RHEL/CentOS/Fedora:

sudo dnf install nginx

After installation, enable and start the service:

sudo systemctl enable nginx
sudo systemctl start nginx

SSL Certificate Setup

Self-Signed Certificate (Development/Testing)

# Generate private key
sudo openssl genrsa -out /etc/ssl/faraday.key 2048

# Create certificate signing request
sudo openssl req -new -key /etc/ssl/faraday.key -out /etc/ssl/faraday.csr

# Generate self-signed certificate (valid 365 days)
sudo openssl x509 -req -days 365 \
  -in /etc/ssl/faraday.csr \
  -signkey /etc/ssl/faraday.key \
  -out /etc/ssl/faraday.crt

# Set permissions
sudo chmod 600 /etc/ssl/faraday.key
sudo chmod 644 /etc/ssl/faraday.crt

Common Name

When prompted for the Common Name (CN), enter your exact FQDN (e.g., faraday.example.com). A mismatched CN will cause browser certificate warnings.

Production Certificate (Let's Encrypt)

For production, use a trusted Certificate Authority. With Certbot:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d faraday.example.com

Certbot automatically configures NGINX and sets up auto-renewal.


NGINX Configuration

Automatic Generation

Faraday includes a command to generate an NGINX configuration:

faraday-manage generate-nginx-config \
  --fqdn faraday.example.com \
  --port 5985 \
  --ssl-certificate /etc/ssl/faraday.crt \
  --ssl-key /etc/ssl/faraday.key

The command outputs the configuration to stdout. Review it, then save to your NGINX sites directory.

Manual Configuration

Create a configuration file at /etc/nginx/sites-available/faraday (Debian) or /etc/nginx/conf.d/faraday.conf (RHEL):

# Cache expiry map for static assets
map $sent_http_content_type $expires {
    default                    off;
    text/html                  max;
    text/css                   max;
    application/javascript     max;
    ~image/                    max;
}

server {
    server_name faraday.example.com;
    listen 443 ssl;

    # --- Security Headers ---
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options nosniff;

    # --- Upload Limit ---
    # Maximum file upload size (reports, evidence).
    # Increase if you upload large reports.
    client_max_body_size 500M;

    # --- SSL Configuration ---
    ssl_session_cache shared:SSL:50m;
    ssl_certificate     /etc/ssl/faraday.crt;
    ssl_certificate_key /etc/ssl/faraday.key;

    # --- Compression ---
    gzip on;
    gzip_types application/javascript text/css;
    expires $expires;

    index index.html index.htm;

    # --- Frontend Static Files ---
    # For bare-metal installations, serve the frontend directly.
    # Adjust the path to match your Python installation.
    location / {
        alias /opt/faraday/lib/python3.11/site-packages/faraday/server/www/;
        try_files $uri $uri/ /index.html;
    }

    # --- API Proxy ---
    location /_api {
        proxy_pass http://127.0.0.1:5985/_api;
        proxy_redirect http:// $scheme://;
        proxy_read_timeout 300;
        proxy_cookie_path / "/; secure";

        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Ssl on;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # --- WebSocket Proxy (Socket.IO) ---
    location /socket.io {
        proxy_set_header Host $http_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_http_version 1.1;
        proxy_buffering off;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://127.0.0.1:5985;
    }
}

# HTTP to HTTPS redirect
server {
    server_name faraday.example.com;
    listen 80;
    listen [::]:80;

    if ($host = faraday.example.com) {
        return 301 https://$host$request_uri;
    }

    return 404;
}

Enable the Configuration

Debian/Ubuntu (sites-available/sites-enabled):

sudo ln -s /etc/nginx/sites-available/faraday /etc/nginx/sites-enabled/faraday
sudo nginx -t          # Test configuration
sudo systemctl reload nginx

RHEL/CentOS (conf.d):

sudo nginx -t          # Test configuration
sudo systemctl reload nginx

Docker Deployments

When running Faraday in Docker, NGINX sits outside the container (or in a separate container) and proxies to the published port.

Key differences from bare-metal:

  • No static file serving — The Docker container serves the frontend on port
  • Change the location / block to proxy to the container:
location / {
    proxy_pass http://127.0.0.1:5985/;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}
  • Container hostname — Replace 127.0.0.1:5985 with the container's published address if not using host networking.

OpenAPI Swagger Configuration

After configuring NGINX with a domain, update the OpenAPI spec to reflect the HTTPS URL:

faraday-manage openapi-swagger --server https://faraday.example.com

This ensures the Swagger UI at /_api/v3/swagger uses the correct server URL.


Key Configuration Parameters

client_max_body_size

Controls maximum upload size. The NGINX template uses 150M; the Advanced guide uses 500M. Set according to your report sizes:

Use Case Recommended Value
Standard reports 150M
Large Nessus/Qualys scans 500M
Very large enterprise scans 1G

proxy_read_timeout

Time in seconds NGINX waits for a response from Faraday. Default is 300 (5 minutes). Increase for long-running API operations:

proxy_read_timeout 600;  # 10 minutes for large imports

WebSocket Timeouts

The WebSocket proxy should not have a proxy_read_timeout set, or it should be set very high, to keep long-lived connections open. The Faraday server handles its own ping/pong with socketio_ping_interval=60 and socketio_ping_timeout=220.


Multitenant Configuration

For multitenant deployments, Faraday supports a URL prefix. The NGINX template (nginx_config.j2) supports an optional multitenant_url variable:

# With multitenant prefix "tenant1":
location /tenant1/ {
    try_files $uri $uri/ /index.html;
}

location /tenant1/_api/ {
    proxy_pass http://localhost:5985/_api/;
    # ... same proxy headers
}

location /tenant1/socket.io {
    # ... same WebSocket proxy
    proxy_pass http://localhost:5985;
}

Troubleshooting

502 Bad Gateway

Faraday Server is not running or not accessible on port 5985:

# Check server status
systemctl status faraday-server

# Check if port is listening
ss -tlnp | grep 5985

WebSocket connection failed

Verify the /socket.io proxy block includes proxy_http_version 1.1 and the Upgrade / Connection headers. Also check that the server's socketio_ping_timeout (default 220s) is not being interrupted by an intermediate proxy or firewall.

413 Request Entity Too Large

The uploaded file exceeds client_max_body_size. Increase the value in the NGINX configuration:

client_max_body_size 500M;

Mixed content warnings

Ensure X-Forwarded-Proto is set to $scheme and X-Forwarded-Ssl is on. The server uses these headers to generate correct URLs in responses.

DNS resolution for local FQDN

If using a local FQDN (e.g., faraday.local), add it to /etc/hosts:

127.0.0.1    faraday.local

NGINX configuration test

Always test before reloading:

sudo nginx -t