Reverse proxy config generator: Caddy, Traefik and nginx
List your sites, or read them from a Compose file, and get the configuration for Caddy, Traefik or nginx: HTTPS with Let's Encrypt, HTTP redirected to HTTPS and basic security headers. Everything stays in this browser, and a password never goes in: basic auth takes a hash only.
Start from a Compose file (optional)
Paste the text, or choose a file from your computer. Up to 512 KiB.
0 of 512 KiB
What it does
It writes the reverse proxy configuration for services that run with Docker Compose, in Caddy's, Traefik's or nginx's own format, with the same behaviour in all three: each domain gets a Let's Encrypt certificate, HTTP is redirected to HTTPS, every response carries basic security headers, and the request goes to the service by its Compose name. You add WebSockets, an upload limit and basic authentication per site.
How it works
- Enter each site by hand, or paste a Compose file: services whose image is in our catalog take the port the catalog documents; the others take their first TCP port from ports or expose. Databases, services under a profile and services without a port are skipped, with the reason.
- The same settings are written in each proxy's own language. The output is deterministic: the same sites always give the same bytes, and our tests check every sample with caddy validate and nginx -t.
- Nothing is sent anywhere: the Compose file, the domains and the hash stay on this page.
What each setting does
- TLS
- Caddy and Traefik get and renew a Let's Encrypt certificate per domain on their own, over the HTTP challenge on port 80. With nginx, certbot does it with the webroot method, and nginx reads the files from /etc/letsencrypt/live/<domain>/.
- HTTP to HTTPS
- Every request on port 80 is redirected to HTTPS, except the ACME challenge that the certificate needs.
- Security headers
- Strict-Transport-Security for a year (browsers then refuse plain HTTP), X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin and X-Frame-Options: SAMEORIGIN. An app that sets its own keeps working; check one that must be framed by another site.
- WebSockets
- Caddy and Traefik pass them on their own. nginx needs HTTP/1.1 and the Upgrade and Connection headers, and a longer read timeout so idle connections stay open.
- Request size limit
- Larger requests are refused before they reach the app (413). nginx refuses anything over 1 MB unless you set it, which breaks uploads in WordPress or Nextcloud; Caddy and Traefik have no limit by default.
- Basic authentication
- A user name and password in front of a site that has no login of its own. The files hold the bcrypt hash only. Without HTTPS it would be sent readable, so it is never written without TLS.
Example
Two sites: n8n on port 5678 (with WebSockets) at n8n.example.org, and WordPress on port 80 with a 64 MB upload limit at blog.example.org. For Caddy and for nginx:
# Generated by the ANAROQ Reverse Proxy Generator: https://anaroq.com/tools/reverse-proxy-generator
# Engine @anaroq/compose, reverse proxy 1.0.0, caddy.
# Caddy gets and renews each site's certificate on its own (automatic HTTPS).
n8n.example.org {
header {
Strict-Transport-Security "max-age=31536000"
X-Content-Type-Options "nosniff"
Referrer-Policy "strict-origin-when-cross-origin"
X-Frame-Options "SAMEORIGIN"
-Server
}
reverse_proxy n8n:5678
}
blog.example.org {
header {
Strict-Transport-Security "max-age=31536000"
X-Content-Type-Options "nosniff"
Referrer-Policy "strict-origin-when-cross-origin"
X-Frame-Options "SAMEORIGIN"
-Server
}
request_body {
max_size 64MiB
}
reverse_proxy wordpress:80
}
# Generated by the ANAROQ Reverse Proxy Generator: https://anaroq.com/tools/reverse-proxy-generator
# Engine @anaroq/compose, reverse proxy 1.0.0, nginx.
# Server blocks for the http context: mount this file at /etc/nginx/conf.d/anaroq-proxy.conf.
# Certificates: certbot --webroot with /var/www/certbot, one per domain.
# WebSocket upgrades: Connection is 'upgrade' only when the client asked for one.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# n8n.example.org → n8n:5678
server {
listen 80;
server_name n8n.example.org;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name n8n.example.org;
ssl_certificate /etc/letsencrypt/live/n8n.example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/n8n.example.org/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
server_tokens off;
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Frame-Options "SAMEORIGIN" always;
location / {
proxy_pass http://n8n:5678;
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_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 1h;
}
}
# blog.example.org → wordpress:80
server {
listen 80;
server_name blog.example.org;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name blog.example.org;
ssl_certificate /etc/letsencrypt/live/blog.example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/blog.example.org/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
server_tokens off;
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Frame-Options "SAMEORIGIN" always;
client_max_body_size 64m;
location / {
proxy_pass http://wordpress:80;
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;
}
}
Limits
- No certificate management: Caddy and Traefik renew on their own, and for nginx you run certbot and its renewal yourself.
- No deployment: the tool writes files and does not start or reload a proxy.
- One upstream per site, with no load balancing, health checks or path-based routing.
- nginx without HTTP/2: the http2 directive needs nginx 1.25.1 or later, and Ubuntu 24.04 ships 1.24. Add it if yours is newer.
- Domains are checked for form only: DNS, the firewall and the app's own base URL setting are yours to check.
Methodology: how the numbers are worked out
Sources
- Caddy Documentation: reverse_proxy
- Caddy Documentation: basic_auth
- Caddy Documentation: request_body
- Traefik Documentation: ACME certificate resolvers
- Traefik Documentation: Docker provider
- Traefik Documentation: BasicAuth middleware
- Traefik Documentation: Buffering middleware
- nginx: WebSocket proxying
- nginx: client_max_body_size (default 1m)
- nginx: the http2 directive (since 1.25.1)
- Certbot User Guide: webroot
- Let's Encrypt: challenge types (HTTP-01)
- MDN: Strict-Transport-Security
Related
Next step
A free public tool by ANAROQ, a company building compute infrastructure. What ANAROQ is building