If you run more than two or three self-hosted services in your homelab, you already know the problem. Every VM and container ends up with its own IP address and its own port, and you're the only one who can remember which is which. Pi-hole is on .15, your Ubuntu VM with Nextcloud is on .22:8080, and Home Assistant lives somewhere you wrote down on a sticky note six months ago.
Nginx Proxy Manager fixes that by giving every service a proper name and, if you want it, a free SSL certificate — without you having to hand-edit a single Nginx config file. On Proxmox VE, the easiest way to run it is inside its own lightweight LXC container, separate from everything else. Here's exactly how to set that up, from a clean Proxmox VE 9.2 host to your first working proxy host.
What You Will Learn
- What Nginx Proxy Manager actually does, and what a reverse proxy is if you've never used one
- Why running it in its own LXC container is the right call on Proxmox
- How to deploy the container using the community-scripts installer
- How to log in, change the default password, and create your first proxy host
- How to request a free Let's Encrypt certificate for that proxy host
- The errors people hit most often, and how to fix each one
What Is This Feature?
Nginx Proxy Manager, usually shortened to NPM, is a web dashboard built on top of Nginx that manages reverse proxy rules for you. Instead of memorizing IP addresses and port numbers, you type a hostname like nextcloud.yourdomain.com into a form, point it at an internal IP and port, and NPM writes the underlying Nginx configuration for you. It also handles requesting and renewing SSL certificates from Let's Encrypt, so your services get a padlock icon in the browser without you touching Certbot directly.
A reverse proxy, if the term is new to you, sits in front of your other servers and forwards incoming requests to the right one based on the hostname or path in the request. Your router forwards ports 80 and 443 to the proxy, and the proxy decides where the traffic actually goes next. One public entry point, many private services behind it.
LXC is the container technology Proxmox VE uses for lightweight guests that share the host's Linux kernel instead of running a full virtual machine. An LXC container boots in a second or two, uses a fraction of the RAM a VM would need, and is a perfect fit for a small, always-on service like NPM that doesn't need its own kernel or hardware emulation.
Why Would You Use It?
The honest answer is convenience. You could reverse proxy everything by hand-writing Nginx or Caddy configs, and plenty of admins do exactly that. But if you're new to Proxmox and just want your homelab services reachable by name with working HTTPS, NPM gets you there in about fifteen minutes with a web UI instead of a text editor.
It's also genuinely useful once your homelab grows past a handful of services. Instead of remembering that Sonarr lives on port 8989 and Radarr on 7878, you visit sonarr.home.lab and radarr.home.lab. If you ever move a service to a different VM or change its port, you update one entry in NPM instead of re-bookmarking everything.
One thing worth saying up front: NPM is not a firewall and it's not a VPN. It exposes whatever you point it at. If a service behind it has a weak login, putting it behind NPM with a nice domain name doesn't fix that. Treat it as a convenience and TLS layer, not a security boundary on its own.
Prerequisites
- A working Proxmox VE 9.x host with internet access (this guide was tested on 9.2)
- Root access to the Proxmox shell, either through the web console or SSH
- At least 8 GB of free storage and 2 GB of free RAM for the new container
- Basic comfort typing commands — you won't need to write any code, just copy and paste a couple of lines
- Optional: a domain name pointed at your public IP, if you want a real Let's Encrypt certificate instead of a self-signed one
Step-by-Step Tutorial
1. Open the Proxmox VE shell
Log into the Proxmox web interface, click your node's name in the left-hand tree, and choose Shell from the top toolbar. You can also SSH into the host directly if you'd rather use your own terminal.
2. Run the community-scripts installer
The community-scripts project maintains a large library of ready-made LXC installers for Proxmox, and Nginx Proxy Manager is one of them. Paste this into the shell:
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/nginxproxymanager.sh)"
You'll be dropped into a small text-based wizard. Choosing the default settings is fine for almost everyone — it creates an unprivileged container based on Debian 13 with 2 CPU cores, 2048 MB of RAM, and an 8 GB disk. That's more than enough headroom for NPM, which is a lightweight Node.js application under the hood.
The whole process — downloading the Debian template, creating the container, installing Node.js and NPM's dependencies, and starting the service — takes roughly two to three minutes on a decent internet connection. When it finishes, the script prints the container's IP address. Write that down.
3. Log in to the NPM dashboard
From a computer on the same network, open a browser and go to http://<container-ip>:81. That's port 81, not 80 — port 80 is reserved for the actual proxy traffic once you start using it.
The default login is:
- Email:
admin@example.com - Password:
changeme
NPM forces you to change both the email and password immediately after the first login. Don't skip this — those default credentials are public knowledge, and an NPM instance with the default password exposed to the internet is a genuinely bad idea.
4. Create your first proxy host
Once you're in, click Proxy Hosts in the top menu, then Add Proxy Host. Fill in the Domain Names field with the hostname you want to use, for example nextcloud.home.lab if you're staying local, or nextcloud.yourdomain.com if you own a real domain and want a trusted certificate.
Under Forward Hostname / IP, put the internal IP address of the VM or container running the actual service, and under Forward Port, the port that service listens on. Leave Scheme as http unless the backend service itself already uses HTTPS internally.
Turn on Block Common Exploits while you're on this screen — it's a free layer of filtering for obvious attack patterns, and there's no real downside to leaving it on.
5. Add an SSL certificate
Switch to the SSL tab on the same Add Proxy Host dialog. If you have a real domain pointed at your public IP with port 80 or 443 reachable from the internet, choose Request a new SSL Certificate, agree to the Let's Encrypt terms, and enable Force SSL. NPM handles the whole Let's Encrypt handshake and renewal for you from that point on.
If you're staying fully internal with no public domain, skip this tab. You can still use NPM's self-signed certificate option, but your browser will show a warning every time — that's expected and not a sign anything is broken.
Commands Explained
| Command | What it does |
|---|---|
bash -c "$(curl -fsSL <script-url>)" | Downloads the community-scripts installer and runs it immediately in the current shell — this is what creates the LXC container and installs NPM |
pct list | Run on the Proxmox host itself, this lists every LXC container and its current status, useful for finding the new container's ID |
pct enter <CTID> | Opens a root shell directly inside the container, handy if you need to check logs without going through the Proxmox GUI |
systemctl status npm | Run inside the container, shows whether the Nginx Proxy Manager service is currently running and its recent log output |
pct reboot <CTID> | Restarts the container from the Proxmox host, useful after the container seems stuck rather than pulling the plug on it |
Common Errors
"This site can't be reached" on port 81. Usually means the container is still booting, or you typed the wrong IP. Give it another thirty seconds, then double check the IP with pct list on the host.
502 Bad Gateway after adding a proxy host. NPM can't reach the backend service. Confirm the VM or container you're forwarding to is actually running, and that you typed the right internal IP and port — a surprisingly common mistake is forwarding to the Proxmox host's IP instead of the guest's IP.
Let's Encrypt certificate request fails. This almost always means port 80 or 443 isn't actually reaching your NPM container from the internet. Let's Encrypt needs to connect to your public IP on port 80 to verify you own the domain. Check your router's port forwarding rules and make sure nothing else on your network — including the Proxmox firewall — is blocking those ports.
Container won't start after a host reboot. Check Datacenter → <node> → <CTID> → Options and confirm Start at boot is enabled. It's off by default for containers created by some install scripts, and it's easy to forget.
Troubleshooting
If the dashboard loads but proxied sites don't, the fault is almost never NPM itself — it's usually the backend service or the network path to it. Start by opening the target service's own address directly (its own IP and port, bypassing NPM entirely). If that doesn't load either, the problem is with the backend, not the proxy.
If direct access works but the proxied domain doesn't, check DNS next. For a local hostname like nextcloud.home.lab, you need either a DNS entry in your router or Pi-hole, or a manual entry in your computer's hosts file — NPM doesn't create DNS records for you, it only answers requests once they arrive.
For anything stranger, pct enter <CTID> from the Proxmox shell, then journalctl -u npm -f to watch the service's logs live while you reproduce the problem in your browser. Nine times out of ten, the actual error message is more specific than what the web UI shows you.
Best Practices
Give the NPM container a static internal IP rather than relying on DHCP. If its address changes, your router's port forwards and any DNS entries pointing at it break silently, and that's a miserable thing to debug at midnight.
Back up the container regularly using Proxmox's built-in vzdump, or through Proxmox Backup Server if you run one. NPM stores all its proxy hosts, certificates, and access lists in its own SQLite database inside the container — lose the container without a backup, and you're rebuilding every proxy host by hand.
Don't expose the port 81 admin dashboard to the internet. Keep it reachable only from your local network, or behind a VPN like Tailscale or WireGuard if you need remote access. The proxy hosts it manages can absolutely be public; the admin panel that controls them shouldn't be.
Turn on two-factor authentication under Users in the NPM dashboard once you've got things working. It takes two minutes and it's one less thing to worry about if your password ever leaks.
Frequently Asked Questions
Do I need a domain name to use Nginx Proxy Manager?
No. You can run it entirely on your local network using hostnames like service.home.lab and self-signed certificates. You only need a real domain if you want trusted, browser-friendly SSL certificates from Let's Encrypt.
Can I run NPM in a VM instead of an LXC container?
Yes, and some people prefer it for the extra isolation. But for a service this lightweight, an LXC container starts faster, uses less RAM, and is easier to back up. There's no functional downside to the container approach for most homelabs.
Is Nginx Proxy Manager the same as the Nginx web server?
No. NPM uses Nginx internally to do the actual proxying, but it's a separate open-source project with its own web dashboard, database, and certificate management. You never need to edit an Nginx config file directly.
What happens if I lose the container?
You lose every proxy host, SSL certificate, and access list you configured, unless you restored from a backup. This is exactly why regular vzdump backups matter for this container specifically, even though it feels like "just a proxy."
Can I use NPM to proxy services running on other VMs and containers, not just Docker?
Yes. NPM doesn't care what's behind it — a bare-metal install, another VM, another LXC container, or a Docker service all work the same way, as long as NPM can reach the IP and port over the network.
Conclusion
Fifteen minutes and one command is a fair trade for never having to remember which port Sonarr runs on again. The community-scripts installer does the tedious part — provisioning the container and installing dependencies — so what's left is mostly clicking through NPM's dashboard and pointing it at the services you already run.
Start with one or two proxy hosts to get a feel for it before you migrate everything over. Once you trust it, and once your backups are in place, it becomes one of those small pieces of infrastructure you stop thinking about entirely — which, for a homelab, is exactly the goal.