Skip to content

Nginx Reverse Proxy Setup

This guide sets up Nginx on Ubuntu 22.04 to provide HTTPS access to a Curio PDP node using Let’s Encrypt certificates. Nginx terminates TLS on the public side and forwards plain HTTP to Curio over the LAN, so Curio does not manage certificates itself.

The example serves calib.ezpdpz.net from a Curio instance at 192.168.1.160. Substitute your own hostnames, internal IP addresses, and paths throughout.

  • Nginx handles HTTPS on port 443 (public-facing) and terminates TLS.
  • Curio runs on an internal IP, serving HTTP on port 443 with DelegateTLS enabled.
  • Traffic between Nginx and Curio is unencrypted HTTP over the LAN.
  • Root or sudo access
  • One or more domain names pointing at your server’s public IP
  • A Curio PDP node running on the internal network
  • Ports 80 and 443 open in the firewall
  1. Install Nginx and start it:

    Terminal window
    sudo apt update
    sudo apt install nginx
    nginx -v
    sudo systemctl start nginx
    sudo systemctl enable nginx
  2. Install Certbot for Let’s Encrypt certificates:

    Terminal window
    sudo apt install certbot python3-certbot-nginx
    certbot --version
  3. Configure a virtual host. Create a config file for your domain. Replace calib.ezpdpz.net with your domain:

    Terminal window
    sudo nano /etc/nginx/sites-available/calib.ezpdpz.net

    Start with a minimal config so Certbot can validate the domain:

    server {
    listen 80;
    server_name calib.ezpdpz.net;
    location / {
    return 200 "Server is ready for certbot";
    }
    }

    Enable the site, test the config, and reload:

    Terminal window
    sudo ln -s /etc/nginx/sites-available/calib.ezpdpz.net /etc/nginx/sites-enabled/
    sudo nginx -t
    sudo systemctl reload nginx
  4. Obtain the SSL certificate with the Nginx plugin:

    Terminal window
    sudo certbot --nginx -d calib.ezpdpz.net

    Follow the prompts: enter your email, agree to the terms, and choose to redirect HTTP to HTTPS. Certbot obtains the certificate, wires it into Nginx, and sets up automatic renewal.

  5. Configure the reverse proxy. Edit the site config again:

    Terminal window
    sudo nano /etc/nginx/sites-available/calib.ezpdpz.net

    Replace its contents with the following. Substitute YOUR_DOMAIN and YOUR_CURIO_IP:

    # HTTP server - redirect to HTTPS
    server {
    listen 80;
    server_name YOUR_DOMAIN;
    # Let's Encrypt challenge location
    location /.well-known/acme-challenge/ {
    root /var/www/html;
    }
    # Redirect everything else to HTTPS
    location / {
    return 301 https://$server_name$request_uri;
    }
    }
    # HTTPS server - proxy to Curio
    server {
    listen 443 ssl;
    server_name YOUR_DOMAIN;
    # Let's Encrypt certificates
    ssl_session_cache shared:SSL:100m;
    ssl_certificate /etc/letsencrypt/live/YOUR_DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/YOUR_DOMAIN/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
    # Logging
    access_log /var/log/nginx/YOUR_DOMAIN.access.log;
    error_log /var/log/nginx/YOUR_DOMAIN.error.log;
    # Large file upload/download settings
    client_max_body_size 0;
    client_body_timeout 600s;
    send_timeout 600s;
    proxy_request_buffering off;
    proxy_buffering off;
    gzip off;
    # Proxy everything to Curio (HTTP with DelegateTLS)
    location / {
    proxy_pass http://YOUR_CURIO_IP:443;
    proxy_http_version 1.1;
    proxy_socket_keepalive on;
    proxy_set_header Connection "";
    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_connect_timeout 600s;
    proxy_send_timeout 600s;
    proxy_read_timeout 600s;
    }
    }

    Test and reload:

    Terminal window
    sudo nginx -t
    sudo systemctl reload nginx
  6. Configure Curio for DelegateTLS. On the Curio machine, set DelegateTLS = true in the HTTP section of your PDP configuration layer. This tells Curio to serve HTTP on port 443 and let Nginx handle TLS termination. Restart Curio after the change.

  7. Test the setup.

    Terminal window
    curl -I https://calib.ezpdpz.net
    openssl s_client -connect calib.ezpdpz.net:443 -servername calib.ezpdpz.net

    You should see a response from Curio through Nginx, and a valid certificate chain.

  • location /.well-known/acme-challenge/ lets Certbot renew certificates.
  • location / redirects all other HTTP traffic to HTTPS.
  • ssl_session_cache shared:SSL:100m caches roughly 400K SSL sessions to avoid “could not allocate new session” errors under load.
  • ssl_certificate and ssl_certificate_key point to the Let’s Encrypt certificate and key.
  • include /etc/letsencrypt/options-ssl-nginx.conf applies Certbot’s SSL settings, and ssl_dhparam supplies Diffie-Hellman parameters.
  • client_max_body_size 0 removes the upload size limit.
  • client_body_timeout 600s and send_timeout 600s allow up to 10 minutes for slow uploads and responses.
  • proxy_request_buffering off and proxy_buffering off stream data straight through, reducing memory use.
  • gzip off skips compression of binary PDP data, which does not compress.
  • proxy_pass http://YOUR_CURIO_IP:443 forwards to Curio over HTTP. Curio handles TLS internally only when not delegating, so with DelegateTLS this stays HTTP.
  • proxy_http_version 1.1 with proxy_socket_keepalive on and proxy_set_header Connection "" keeps upstream connections alive during large transfers.
  • The proxy_set_header directives preserve client information, and the proxy_*_timeout 600s values allow long-running transfers.
Terminal window
sudo tail -f /var/log/nginx/calib.ezpdpz.net.access.log
sudo tail -f /var/log/nginx/calib.ezpdpz.net.error.log
sudo systemctl status nginx
  • Certificate renewal fails. Ensure port 80 is reachable from the internet, the /.well-known/acme-challenge/ location is present in the HTTP block, and /var/www/html exists.
  • Proxy connection fails. Verify Curio is running on the internal IP, has DelegateTLS = true, and is listening on port 443. Check network connectivity between the Nginx and Curio machines.
  • 502 Bad Gateway. Curio is down or not responding, the proxy_pass IP is wrong, or Curio is not in DelegateTLS mode.
  • Config test fails. Run sudo nginx -t to see the specific syntax error.

Nginx handles all SSL complexity, including automatic certificate renewal and centralized certificate management, while Curio focuses on PDP operations. The setup supports unlimited upload sizes, forwards client IPs to the backend, redirects HTTP to HTTPS, and serves multiple domains, one per Curio instance.