Managing Traffic to Your Self-Hosted Services Without the Headache
Running multiple self-hosted services on a home server or VPS means dealing with one persistent problem: how do you expose them cleanly to the internet without opening a dozen different ports or memorizing IP addresses? Nginx Proxy Manager solves this by giving you a web-based GUI on top of Nginx, letting you route traffic by domain name, manage SSL certificates automatically, and keep your internal network tidy – all without touching a config file.

What Nginx Proxy Manager Actually Does
At its core, Nginx Proxy Manager is a reverse proxy. When a request hits your server on port 80 or 443, the proxy reads the domain name from that request and forwards it to whichever internal service you’ve mapped to that domain. So photos.yourdomain.com could point to a photo app running on port 2283, while cloud.yourdomain.com routes to something else entirely – all without the end user seeing any port numbers or internal IPs.
The tool is built on top of Nginx but wrapped in a Docker container with a clean admin interface. You get a dashboard for creating proxy hosts, redirect hosts, and stream hosts, plus built-in Let’s Encrypt integration that handles SSL certificate issuance and renewal automatically. This matters because running services over plain HTTP is a security problem, and manually managing certificates across five or six subdomains gets old fast.
Nginx Proxy Manager also supports access lists, which let you restrict certain services to specific IP ranges or require basic authentication before anyone reaches the proxied app. This is useful when you’re running internal tools that shouldn’t be publicly accessible but still need to be reachable over HTTPS. It’s a practical middle ground between exposing everything and locking everything behind a full VPN – though for truly sensitive services, pairing this with something like a WireGuard VPN adds another layer of protection.
The architecture is straightforward: one Docker container runs the Nginx engine and another runs the admin UI, both coordinated by Docker Compose. You map ports 80 and 443 from your host to the container, set up your DNS records to point at your server’s public IP, and the proxy handles everything from there. No manual Nginx config editing required unless you want to drop into advanced settings.
Installing and Configuring Nginx Proxy Manager
Before starting, you’ll need Docker and Docker Compose installed on your host machine. This works on a VPS, a home server, or even a Raspberry Pi running a 64-bit OS. Make sure ports 80 and 443 are open on your firewall or router, and that your domain’s DNS A records are already pointing to your server’s public IP address. DNS propagation can take time, so doing this step before installation saves frustration later.
Create a directory for the project and inside it create a docker-compose.yml file. The configuration below covers a standard deployment:
version: '3.8'
services:
npm:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '80:80'
- '443:443'
- '81:81'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
Port 81 is where the admin interface lives. Once the container is running, navigate to http://your-server-ip:81 in a browser. The default login credentials are admin@example.com for email and changeme for the password. You’ll be forced to update both on first login – do not skip this. Leaving default credentials on an internet-facing admin panel is an obvious security hole.
With the admin panel open, go to Proxy Hosts and click Add Proxy Host. In the dialog, enter the domain name you want to route (for example, photos.yourdomain.com), set the scheme to http or https depending on how your upstream app is configured, enter the internal IP or Docker network name of that app, and set the port it’s running on. Enable Websockets Support if your app uses them – many modern web apps do, and forgetting this option causes broken real-time features. Switch to the SSL tab, select Request a new SSL Certificate, check Force SSL and HTTP/2 Support, enter your email address for Let’s Encrypt, and save. The certificate will be issued automatically within seconds if your DNS is pointed correctly.

Repeat this process for each service you want to expose. If you’re running several containers on the same Docker host, it’s cleaner to put Nginx Proxy Manager and your services on a shared Docker network so you can reference them by container name instead of IP address. To do this, define a named network in your Compose file and attach all relevant containers to it. This way, instead of entering 192.168.1.x as the forward hostname, you enter the container’s service name directly – which stays stable even if internal IPs shift. This approach works especially well when you’re hosting apps like Immich, where multiple containers are already coordinated through Compose and need a consistent routing path.
Keeping It Running and Troubleshooting Common Issues
The two most common problems people hit are certificate failures and 502 Bad Gateway errors. Certificate failures almost always trace back to DNS – if your domain isn’t resolving to the correct IP when Let’s Encrypt tries to verify it, the request fails. Run a DNS lookup with dig or an online tool to confirm propagation before retrying. The 502 error means the proxy can reach the container but the upstream app isn’t responding on the expected port, which is usually a misconfigured forward port or a service that isn’t running. Check your upstream container’s logs and confirm the port with docker ps.
Nginx Proxy Manager stores all its configuration and certificate data in the ./data and ./letsencrypt directories you mapped as volumes. Back these up regularly. If you ever need to move the stack to a new server, copying those two directories and the Compose file is all it takes to restore your full configuration, certificates included – no re-issuing, no re-configuring proxy hosts from scratch.






