Putting a real domain in front of a Docker container takes more than one nginx proxy_pass line. The proxy needs to know whether the container speaks HTTP or HTTPS, whether the app is actually answering, whether an SSL certificate exists for the domain — and what to do if the new configuration breaks the web server. This post explains each of those steps, why they exist, and how Panelica performs the whole chain automatically when you link a domain or subdomain to a container.
The problem: containers live on ports, visitors live on domains
A deployed container publishes something like your-server:8096. That works for testing, but nobody ships http://203.0.113.7:8096 to users. You want media.example.com — port 443, valid certificate, no port number in sight. The bridge between the two is a reverse proxy: the web server accepts the request for the domain and forwards it to the container's port on localhost.
The concept is simple. The failure modes are not, and they are worth understanding even if a panel handles them for you.
Failure mode 1: the container speaks HTTPS, not HTTP
Most web apps listen on plain HTTP inside the container and let the proxy do TLS. But a meaningful minority — Portainer, many VNC-based web desktops, some admin UIs — serve HTTPS on their internal port, usually with a self-signed certificate. Point a plain proxy_pass http://... at one of those and you get an instant 502 Bad Gateway, because the backend answers the HTTP request with a TLS handshake.
The fix is to probe before configuring: try the port over HTTP, try it over HTTPS (accepting self-signed certificates), and write the proxy config with the scheme that actually answered. Panelica does this probe automatically when you link a domain — the generated nginx config connects to the container with whichever of http:// or https:// the container really speaks.
Failure mode 2: proxying to an app that is not up
Linking a domain to a container that is still initializing — or crashed two minutes ago — produces a proxy that forwards every visitor to a dead socket. A health check before activation catches this: make a real request to the container's port and require an answer before the link goes live. If the app is not answering, you want an error at link time, when you are watching, instead of 502s at midnight, when your visitors are.
Failure mode 3: SSL that half-exists
The domain-side certificate has its own decision tree. If a valid certificate already exists for the domain, the proxy should terminate TLS with it and serve the app on 443. If it does not exist yet, the proxy must still work over HTTP so the certificate can be issued afterwards. A config that hard-codes 443 with a missing certificate file will fail the web server's config test — which brings us to the last failure mode.
Panelica checks whether the domain's certificate files are present and generates the appropriate config: HTTPS termination when the certificate exists, clean HTTP otherwise, ready to upgrade when you issue the certificate from the SSL page.
Failure mode 4: one bad config takes down every site
This is the one people learn the hard way. nginx loads all site configurations together — a syntax error or a missing certificate path in one vhost file means nginx -t fails and a reload would leave every site on the server serving from the old process, or worse if the process restarts. Any tool that writes proxy configs must:
- Back up the current configuration before touching it.
- Write the new configuration.
- Run the web server's config test.
- Reload only if the test passes — and restore the backup automatically if it fails.
Panelica's domain linking runs exactly this transaction. If the generated config fails the nginx test for any reason, the previous config is restored and the link operation reports an error — your other sites never notice.
What linking looks like in practice
In Panelica's Docker Manager, the flow is: pick a container, pick one of its published ports, pick a domain or subdomain you host on the panel, and link. Behind the click:
- The container's port is probed to detect HTTP vs HTTPS.
- A health check confirms the app answers.
- The current vhost config is backed up.
- A reverse proxy config is generated — with WebSocket headers included, so apps like terminals, live dashboards, and chat UIs work without extra flags.
nginx -truns; on success nginx reloads, on failure the backup is restored.
Subdomains work the same way, which is the pattern most people actually want: keep example.com on your website, and put analytics.example.com, wiki.example.com, and media.example.com each on their own container. A walkthrough of that setup with real apps is in our subdomain routing guide.
Doing it by hand instead
If you manage nginx yourself, the equivalent checklist is short but unforgiving: probe the backend scheme with curl -k, write the server block, include proxy_set_header Upgrade and Connection for WebSockets, run nginx -t before every reload, and keep a copy of the last working config. Our general nginx reverse proxy guide covers the raw configuration in detail.
Frequently asked questions
Do I need to open the container's port to the internet?
No — and you should not. The reverse proxy connects to the container locally on the server. Only ports 80 and 443 need to face the internet; the app's own port can stay firewalled.
Can one domain serve multiple containers?
The clean pattern is one hostname per container: use subdomains (app1.example.com, app2.example.com) rather than path-based routing. Many self-hosted apps generate absolute URLs and behave badly under a path prefix.
What about WebSockets?
WebSocket connections need the Upgrade and Connection headers passed through, or live features silently fail while normal pages work. Panelica includes these headers in every generated proxy config by default.
What happens if I unlink the domain?
Unlinking regenerates the domain's normal vhost configuration, so the domain goes back to serving its regular document root. The same backup-test-reload transaction protects that direction too.
The takeaway
"Just add a proxy_pass" is the happy path. The real path has four failure modes — wrong backend scheme, dead backend, half-configured SSL, and a config error cascading to every site on the server. Whether you write nginx configs yourself or let Panelica's domain linking do it, make sure all four are handled: probe, health check, certificate detection, and test-before-reload with automatic rollback.