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.
Architecture
Section titled “Architecture”- Nginx handles HTTPS on port 443 (public-facing) and terminates TLS.
- Curio runs on an internal IP, serving HTTP on port 443 with
DelegateTLSenabled. - Traffic between Nginx and Curio is unencrypted HTTP over the LAN.
Prerequisites
Section titled “Prerequisites”- 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
-
Install Nginx and start it:
Terminal window sudo apt updatesudo apt install nginxnginx -vsudo systemctl start nginxsudo systemctl enable nginx -
Install Certbot for Let’s Encrypt certificates:
Terminal window sudo apt install certbot python3-certbot-nginxcertbot --version -
Configure a virtual host. Create a config file for your domain. Replace
calib.ezpdpz.netwith your domain:Terminal window sudo nano /etc/nginx/sites-available/calib.ezpdpz.netStart 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 -tsudo systemctl reload nginx -
Obtain the SSL certificate with the Nginx plugin:
Terminal window sudo certbot --nginx -d calib.ezpdpz.netFollow 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.
-
Configure the reverse proxy. Edit the site config again:
Terminal window sudo nano /etc/nginx/sites-available/calib.ezpdpz.netReplace its contents with the following. Substitute
YOUR_DOMAINandYOUR_CURIO_IP:# HTTP server - redirect to HTTPSserver {listen 80;server_name YOUR_DOMAIN;# Let's Encrypt challenge locationlocation /.well-known/acme-challenge/ {root /var/www/html;}# Redirect everything else to HTTPSlocation / {return 301 https://$server_name$request_uri;}}# HTTPS server - proxy to Curioserver {listen 443 ssl;server_name YOUR_DOMAIN;# Let's Encrypt certificatesssl_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;# Loggingaccess_log /var/log/nginx/YOUR_DOMAIN.access.log;error_log /var/log/nginx/YOUR_DOMAIN.error.log;# Large file upload/download settingsclient_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 -tsudo systemctl reload nginx -
Configure Curio for DelegateTLS. On the Curio machine, set
DelegateTLS = truein 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. -
Test the setup.
Terminal window curl -I https://calib.ezpdpz.netopenssl s_client -connect calib.ezpdpz.net:443 -servername calib.ezpdpz.netYou should see a response from Curio through Nginx, and a valid certificate chain.
Configuration Breakdown
Section titled “Configuration Breakdown”HTTP Server Block (Port 80)
Section titled “HTTP Server Block (Port 80)”location /.well-known/acme-challenge/lets Certbot renew certificates.location /redirects all other HTTP traffic to HTTPS.
HTTPS Server Block (Port 443)
Section titled “HTTPS Server Block (Port 443)”ssl_session_cache shared:SSL:100mcaches roughly 400K SSL sessions to avoid “could not allocate new session” errors under load.ssl_certificateandssl_certificate_keypoint to the Let’s Encrypt certificate and key.include /etc/letsencrypt/options-ssl-nginx.confapplies Certbot’s SSL settings, andssl_dhparamsupplies Diffie-Hellman parameters.
Large File Settings (Critical for PDP)
Section titled “Large File Settings (Critical for PDP)”client_max_body_size 0removes the upload size limit.client_body_timeout 600sandsend_timeout 600sallow up to 10 minutes for slow uploads and responses.proxy_request_buffering offandproxy_buffering offstream data straight through, reducing memory use.gzip offskips compression of binary PDP data, which does not compress.
Proxy Settings
Section titled “Proxy Settings”proxy_pass http://YOUR_CURIO_IP:443forwards to Curio over HTTP. Curio handles TLS internally only when not delegating, so with DelegateTLS this stays HTTP.proxy_http_version 1.1withproxy_socket_keepalive onandproxy_set_header Connection ""keeps upstream connections alive during large transfers.- The
proxy_set_headerdirectives preserve client information, and theproxy_*_timeout 600svalues allow long-running transfers.
Monitoring
Section titled “Monitoring”sudo tail -f /var/log/nginx/calib.ezpdpz.net.access.logsudo tail -f /var/log/nginx/calib.ezpdpz.net.error.logsudo systemctl status nginxTroubleshooting
Section titled “Troubleshooting”- 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/htmlexists. - 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_passIP is wrong, or Curio is not in DelegateTLS mode. - Config test fails. Run
sudo nginx -tto see the specific syntax error.
Summary
Section titled “Summary”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.