For the complete documentation index, see llms.txt. This page is also available as Markdown.

Optional TLS offloading and filtering

Optional nginx reverse-proxy example that offloads TLS from Curio, keeps Curio hosts private, and adds a place to filter traffic. Curio already serves HTTPS via Let's Encrypt when HTTP.DomainName is s

Curio's HTTP server already terminates TLS. When you set HTTP.DomainName to a real public hostname and leave DelegateTLS = false, Curio obtains and renews a Let's Encrypt certificate and serves HTTPS on the market HTTP endpoint (including PDP routes on that same server). You do not need a reverse proxy to get HTTPS.

This page is an optional reverse-proxy example. Put nginx (or another proxy) in front of Curio when you want to:

  • Offload TLS — certificates and HTTPS live on the proxy, not on every Curio node.

  • Keep Curio boxes otherwise private — only the proxy is on the public internet; Curio listens on the LAN and is not reachable from outside.

  • Increase configurability, including filtering — IP allow/deny lists, rate limits, path rules, and similar controls belong on the proxy, where they are easier to change than in Curio itself.

Set DelegateTLS = true in this mode so Curio serves plain HTTP on ListenAddress and does not try to issue its own certificate.

The nginx config below is deliberately minimal: large-file/streaming settings plus forwarding headers only. Tuning directives such as timeouts and ssl_session_cache are omitted on purpose; add them if you need them. Filtering is also add-on-demand — see Filtering.

This walkthrough uses Ubuntu 22.04, Certbot, and the placeholder domains pdp.example.com and pdp2.example.com. Replace hostnames, internal IPs, and paths with your own.

Before making any configuration changes, back up your existing nginx configuration and validate every change with sudo nginx -t before reloading. This catches syntax errors before they take down the service.

For the two TLS modes (DelegateTLS false vs true), see Curio HTTP Server.


🗺️ Overview

This setup uses nginx as a reverse proxy with TLS termination:

  • Nginx is public-facing on ports 80 and 443 and manages certificates.

  • Backend Curio services listen on internal IPs only, serving HTTP (DelegateTLS = true).

  • Communication between nginx and Curio is unencrypted HTTP over a trusted LAN. Do not expose that hop to the internet.


🚀 Prerequisites

  • Root or sudo access.

  • Domain name(s) pointing to the reverse-proxy server's public IP (not to the Curio node).

  • Curio HTTP server running on the internal network. For PDP, see Enable PDP.

  • Ports 80 and 443 open on the proxy firewall. Curio itself should not need public 80/443.


1️⃣ Install Nginx

Verify the installation:

Start and enable nginx:


2️⃣ Install Certbot for SSL Certificates

Verify the installation:


3️⃣ Configure the Virtual Host

Create a configuration file for your domain. Replace pdp.example.com with your domain and 192.168.1.160 with your Curio service IP.

Create the file:

Add this initial configuration (before SSL setup):

Enable the site:

Test the configuration and reload nginx:


4️⃣ Obtain an SSL Certificate

Run Certbot with the nginx plugin:

Follow the prompts:

  • Enter your email address.

  • Agree to the terms of service.

  • Choose whether to redirect HTTP to HTTPS (recommended: yes).

Certbot will automatically:

  • Obtain the certificate from Let's Encrypt.

  • Configure nginx to use the certificate.

  • Set up automatic renewal.


5️⃣ Configure the Reverse Proxy

After Certbot completes, edit your site configuration:

Replace the contents with the following. Substitute YOUR_DOMAIN and YOUR_CURIO_IP with your own values. YOUR_CURIO_IP must be a private address; Curio's ListenAddress should bind there, not on a public interface.

This example is deliberately minimal: unlimited body size, unbuffered streaming, gzip off, and forwarding headers. It does not set proxy timeouts, ssl_session_cache, worker tuning, or request filters. Add those only if you need them.

Test and reload:

⚙️ Configuration breakdown

HTTP server block (port 80)

  • location /.well-known/acme-challenge/: allows Certbot to renew certificates.

  • location /: redirects all other HTTP traffic to HTTPS.

HTTPS server block (port 443)

  • listen 443 ssl: listen on the HTTPS port with SSL.

  • ssl_certificate / ssl_certificate_key: paths to your SSL certificate and private key.

  • include /etc/letsencrypt/options-ssl-nginx.conf: Certbot's SSL settings.

  • ssl_dhparam: Diffie-Hellman parameters for security.

Large file settings (needed for piece/PDP uploads)

  • client_max_body_size 0: no limit on upload size.

  • proxy_request_buffering off: stream uploads directly to the backend (reduces memory usage).

  • proxy_buffering off: stream downloads directly to the client (reduces memory usage).

  • gzip off: don't compress binary data (saves CPU; piece data doesn't compress).

Proxy settings

  • proxy_pass http://YOUR_CURIO_IP:443: forward to Curio over plain HTTP on the LAN. With DelegateTLS = true, Curio does not terminate TLS. Keep this hop private. If Curio's ListenAddress is not port 443, change the port in proxy_pass to match.

  • proxy_set_header directives: preserve client information (original host, real IP, forwarded chain, and scheme). Curio honours X-Forwarded-For for rate limiting when the proxy connects over loopback; forwarding headers from non-loopback peers are ignored. See Curio HTTP Server.


Filtering (add on demand)

The example above proxies all paths. The reason to run a reverse proxy — beyond TLS offload — is that you can add filtering here without changing Curio.

Examples you might add later (not included in the minimal config):

  • IP allow/deny lists (allow / deny) so only known clients, partners, or your LAN reach certain paths.

  • Rate limiting (limit_req) in front of expensive upload or API routes.

  • Path rules that expose /piece and PDP routes publicly while restricting other paths.

Add filters only for the traffic you actually need to constrain. Over-filtering can break Let's Encrypt renewal (/.well-known/acme-challenge/) and client uploads.


6️⃣ Configure Curio for DelegateTLS

On your Curio machine (for example, 192.168.1.160), set DelegateTLS in the HTTP section of the layer that enables the HTTP server. Curio then serves HTTP on ListenAddress and expects the reverse proxy to terminate TLS.

Bind ListenAddress to an internal address. Do not publish Curio's HTTP port on the public internet in this mode.


7️⃣ Test Your Setup

Test the HTTPS connection:

You should see a response from your Curio service through nginx.

Check the SSL certificate:

Confirm that Curio is not reachable from the public internet on its ListenAddress (the proxy should be the only public HTTPS entry point).


📊 Monitoring and Logs

View nginx access logs:

View nginx error logs:

Check nginx status:


🛠️ Troubleshooting

Certificate renewal fails

  • Ensure port 80 is accessible from the internet on the proxy.

  • Check that the /.well-known/acme-challenge/ location is configured in the HTTP block.

  • Verify the /var/www/html directory exists.

Proxy connection fails

  • Verify the Curio service is running on the internal IP.

  • Check that Curio is configured with DelegateTLS = true.

  • Ensure Curio is listening on the port in proxy_pass.

  • Verify network connectivity between the nginx and Curio machines.

502 Bad Gateway

  • The Curio service is down or not responding.

  • Wrong IP address or port in the proxy_pass directive.

  • Curio not configured for DelegateTLS mode.

Configuration test fails

This will show specific syntax errors in your configuration.


🎉 Summary

  • Curio already provides HTTPS on the market HTTP endpoint via Let's Encrypt when DomainName is set. This reverse proxy is optional.

  • Use it to offload TLS, keep Curio hosts private, and add filtering or other proxy policy.

  • The nginx example is minimal (streaming + forwarding headers). Timeouts, ssl_session_cache, and filters are add-on-demand.

  • DelegateTLS = true makes Curio serve HTTP on the LAN while nginx is the public TLS terminator.

  • Multiple domains are supported (one per Curio HTTP instance, each with its own server block).

Last updated