Tech Digest

Calculator

Reverse proxy generator

One hostname per service, real certificates, and the two settings people forget until an upload returns 413 or a live view stops updating.

Last reviewed Runs entirely in your browser

Choose the services you want on real hostnames, give it a base domain, and this emits a complete Caddyfile, a set of Traefik v3 labels, nginx server blocks, or a table you can type into Nginx Proxy Manager. It also lists the DNS records to create and points out that one wildcard replaces all of them.

The value is not the boilerplate, which you could write. It is the two per service settings that are only obvious after they have already cost you an evening: which services need a websocket upgrade, and which ones need the body-size limit raised because they move large files. Get the first wrong and a page loads perfectly and then never updates again. Get the second wrong and an upload fails with a 413 that looks exactly like an application bug.

The port for each service comes from the same dataset as its profile, so the generated config points at the port the project actually ships. Everything is assembled in your browser; no domain name, hostname or service list is sent anywhere.

1. Pick what you want to run

2. Your domain and proxy

How it works#

Each selected service becomes <slug>.<your domain>, routed to the host you specify on the first port in its profile. Two lookups then modify the output. A websocket list marks services that hold a live connection, which sets proxy_http_version 1.1, the upgrade headers and a one hour read timeout in nginx, and a note in the other outputs. A body-size list marks the services that move large files, which raises the limit to 50 GB for Immich, 10 GB for Nextcloud and Seafile, and 1 GB for Paperless-ngx and Kavita.

The certificate choice changes the output too. HTTP challenge is the default and needs port 80 reachable from the internet. DNS challenge adds the comments for a provider module, and it is the only route to a wildcard or to a certificate for a name that never resolves publicly.

The Caddy output is the shortest because Caddy handles certificates and websockets without being asked. The nginx output is the longest, and it deliberately does not pretend to manage certificates: it points at certbot paths you have to create separately.

What it deliberately does not model#

  • Your subdomain scheme. It uses the tool slug. If you want photos rather than immich, edit it, and remember the DNS record has to match.
  • Services with several ports. It takes the first. Frigate publishes four and only one of them is the web UI, so check before you paste.
  • Subpath hosting. Everything here is one hostname per service. Serving an app under /jellyfin breaks a large fraction of self-hosted software in ways the proxy cannot fix.
  • Authentication. No forward auth, no basic auth, no IP allowlists. That is a deliberate omission because it is a decision, not a default.
  • The proxy container itself. No compose file for Caddy or Traefik, no ACME email beyond the placeholder, no DNS provider credentials.

What to do with the answer#

Create the DNS records first, ideally the single wildcard, and confirm they resolve before the proxy tries to get a certificate: a failed challenge that is really a DNS propagation delay wastes an hour and can hit rate limits. Then paste the config, reload, and check the websocket services by leaving a live view open for a minute.

After that, decide the access question properly. Reverse proxy and TLS covers certificates and the split between internal and public names, Remote access without port forwarding covers reaching this from outside without opening a port at all, and Single sign-on for self-hosters covers putting one login in front of the lot.

Questions#

Why do I get 502 Bad Gateway from my reverse proxy?

The proxy started fine and cannot reach the backend. In order of likelihood: the container name in the config does not match the actual service name, the proxy and the service are not on the same Docker network, the app binds to 127.0.0.1 inside its container so nothing outside can reach it, or you pointed at the host port while the service no longer publishes one. Test from inside the proxy container: docker compose exec caddy wget -qO- http://jellyfin:8096 tells you in one line which side is wrong.

Why does an Immich upload fail with 413 Request Entity Too Large?

The proxy is rejecting the body before the application sees it. The nginx default is client_max_body_size 1m, which no photo or video survives, and Nginx Proxy Manager inherits nginx behaviour here. The generator sets client_max_body_size 50000m for Immich, request_body max_size in the Caddyfile, and a buffering middleware for Traefik. In Nginx Proxy Manager the setting goes in the Advanced tab of the proxy host, because the UI has no field for it.

Do I need a wildcard certificate?

Not for it to work, but it is the better default. A wildcard covers every hostname in the generated table and every one you add later without touching the certificate, and it keeps the names of your services out of public Certificate Transparency logs, which per-service certificates publish for anyone to search. The cost is that wildcards require the DNS-01 challenge and therefore a DNS provider API token on the server. Scope that token to the one zone.

Can I use a reverse proxy without a public domain name?

Yes, and it is the setup most self-hosters should want. Register a real domain, never point it at a public address, and use the DNS-01 challenge to get certificates for names that only resolve on your LAN or over your VPN. You get valid HTTPS with no browser warnings and nothing exposed to the internet. What does not work is a certificate for a .local or invented name: no public CA will issue one, so that route means an internal CA and installing a root certificate on every device.

Caddy, Traefik, nginx or Nginx Proxy Manager?

Caddy for almost everyone: automatic certificates, websockets passed through by default, and a working site is three lines. Traefik when containers come and go weekly and you want routes to appear from labels, accepting that the routing table then exists only at runtime. nginx when you already know nginx. Nginx Proxy Manager when somebody else in the house needs to add a host through a UI, and knowing its v3 rewrite has been pending for years.

Why does my dashboard load but never update?

The websocket upgrade is not being passed. The page is served over normal HTTP requests, so it renders, and then the live channel fails silently. In nginx that means proxy_http_version 1.1, the Upgrade and Connection headers, and a proxy_read_timeout well above the 60 second default. Caddy does it without configuration. The generator marks which of your selected services need it, including Home Assistant, Uptime Kuma, Dozzle and code-server.

Published . Last reviewed . Found something out of date? Tell us and we will fix it and log the change.