If you've ever typed https://192.168.1.50:8006 into a browser for the tenth time this week, you already know the annoyance. It works, but it looks wrong, your browser throws a certificate warning every single time, and good luck remembering that IP address when you're on your phone away from home. There's a fix for this, and it doesn't involve touching Proxmox's own port configuration at all.

This tutorial walks you through putting the Proxmox VE web interface behind Nginx, so you can reach it at a normal address like https://proxmox.yourdomain.com on the standard HTTPS port, 443. No :8006, no memorizing an IP, and one less thing to explain to anyone else who needs access.

What You Will Learn

By the end of this guide you'll have Nginx installed on a small helper VM or LXC container, configured to forward traffic to your Proxmox host, and serving the web interface on port 443. Specifically, you'll learn:

  • What a reverse proxy actually does, in plain terms
  • Why Proxmox's noVNC console needs special handling in the proxy config (and what breaks if you skip it)
  • How to write and test an Nginx config built specifically for Proxmox VE
  • The exact errors people run into with this setup, and how to read them

What Is This Feature?

A reverse proxy is a server that sits in front of another server and passes requests through to it. Instead of your browser talking to Proxmox directly, it talks to Nginx, and Nginx quietly forwards the request to Proxmox's own web server (called pveproxy) running on port 8006. Your browser never sees port 8006 at all — as far as it's concerned, it's just talking to Nginx on port 443.

This is different from a VPN or SSH tunnel, which change how you connect to your network. A reverse proxy changes what happens once you're already able to reach the server. You still need some way to route traffic to it — a router port forward, a Tailscale network, whatever you're already using — this just cleans up the last mile.

One thing worth calling out early: Proxmox's console feature (the black terminal window you get when you click Console on a VM) uses WebSockets, not plain HTTP. A reverse proxy that doesn't know how to pass WebSocket connections through will load the Proxmox dashboard just fine and then fail silently the moment you try to open a console. Most of the config below exists specifically to avoid that.

Why Would You Use It?

A few reasons come up over and over in the Proxmox forums, and they're worth being honest about:

  • A real domain name instead of an IP. Typing pve.mylab.net is just nicer than 10.0.0.12:8006, especially if that IP ever changes.
  • Getting a trusted SSL certificate. Proxmox ships with a self-signed certificate, so your browser flags it every time. Once you're behind Nginx on a domain you control, you can layer Let's Encrypt on top (a separate topic, but this reverse proxy setup is the prerequisite for it).
  • Only exposing one port to the outside world. If you're forwarding ports from your router for remote access, forwarding just 443 instead of 8006 looks a lot less suspicious to anyone scanning your public IP, and it's one less nonstandard port to keep track of.
  • Fronting multiple services on one IP. If you're already running Nginx or Nginx Proxy Manager for other self-hosted apps, adding Proxmox to the same reverse proxy means one entry point for everything.

I'll say this plainly: if you only ever access Proxmox from inside your own network, you don't strictly need any of this. It's a convenience and a certificate fix, not a security requirement. But if you're tired of the browser warning, or you want a proper hostname, it's a fifteen-minute job.

Prerequisites

Before you start, make sure you have:

  • A working Proxmox VE install (this guide was tested on 9.2, but the config works unchanged back through 7.x and 8.x — pveproxy hasn't changed in a way that matters here)
  • A separate place to run Nginx. Don't install it directly on the Proxmox host — use a small LXC container or VM instead. Running extra services on the hypervisor itself is a habit that causes problems later, especially during upgrades.
  • Root or sudo access on that LXC/VM
  • A domain name pointed at the IP address of your Nginx box (or, at minimum, an entry in your local DNS or /etc/hosts if you're just testing on your home network)
  • Network access from the Nginx box to the Proxmox host's port 8006

A Debian 13 LXC container with 512 MB of RAM and 2 GB of disk is more than enough for this. You're not running anything heavy — Nginx idles at almost nothing.

Step-by-Step Tutorial

Step 1: Install Nginx

Log into your LXC container or VM and run:

apt update
apt install nginx -y

This pulls in Nginx and starts it automatically. You can confirm it's running with systemctl status nginx — you should see active (running) in green.

Step 2: Remove the default site

Nginx ships with a default "Welcome to nginx" page enabled, and it'll conflict with the config you're about to add. Remove it:

rm /etc/nginx/sites-enabled/default

On older Debian-based installs you might instead find it at /etc/nginx/conf.d/default — check which one exists on your system before deleting anything.

Step 3: Create the Proxmox proxy config

Create a new config file:

nano /etc/nginx/conf.d/proxmox.conf

Paste in the following, replacing proxmox.yourdomain.com with your real hostname and 10.0.0.12 with the actual IP address of your Proxmox host:

upstream proxmox {
    server 10.0.0.12:8006;
}

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name proxmox.yourdomain.com;
    rewrite ^(.*) https://$host$1 permanent;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name proxmox.yourdomain.com;

    ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
    ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;

    proxy_redirect off;

    location / {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_pass https://proxmox;
        proxy_buffering off;
        client_max_body_size 0;
        proxy_connect_timeout 3600s;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        send_timeout 3600s;
    }
}

A couple of things about this file matter more than they look like they should. The proxy_set_header Upgrade and proxy_set_header Connection "upgrade" lines are what let the noVNC console tunnel through — without them, the dashboard loads but every console window just spins forever. The long 3600-second timeouts stop Nginx from killing an idle console session after a minute of inactivity, which is a real thing that happens with Nginx's one-minute default.

I used the self-signed snakeoil certificate that ships with every Debian install here, just to keep this guide focused on the proxy itself. If you want a real trusted certificate, that's a job for Certbot or the ACME client built into Proxmox — worth doing once this base setup is working, not before.

Step 4: Test the config before restarting

Never restart Nginx blind. Test the syntax first:

nginx -t

A good result looks like this:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

If you see an error instead, it'll usually point you straight to the line number that's wrong — a missing semicolon or an unmatched brace is the usual culprit.

Step 5: Restart Nginx

systemctl restart nginx

Then check it's still up:

systemctl status nginx

Step 6: Make sure DNS actually points where you think it does

From another machine, run:

dig proxmox.yourdomain.com +short

The IP it returns needs to match the machine running Nginx, not your Proxmox host. This trips people up constantly — they point the domain at Proxmox's IP directly instead of the Nginx box, and then wonder why the certificate looks wrong or the page never loads.

Step 7: Test it in a browser

Open https://proxmox.yourdomain.com. You should land on the normal Proxmox login page, on port 443, with no :8006 anywhere in the address bar. Log in, open a VM, click Console, and confirm the terminal actually connects. That last check matters — this is exactly the step that fails if the WebSocket headers got typo'd or dropped.

Step 8 (optional): Start Nginx after Proxmox's cluster service

On a fresh boot, there's a small race condition: Nginx can start before pve-cluster has finished bringing up the certificates Proxmox uses. It's rare, but if you ever see Nginx fail right after a reboot, add a startup dependency:

systemctl edit nginx.service

In the editor that opens, add:

[Unit]
Requires=pve-cluster.service
After=pve-cluster.service

Save and exit, then run systemctl daemon-reload. This only matters if you're running Nginx directly on the Proxmox host, which — as mentioned above — I'd generally avoid anyway. If Nginx lives in its own container, this step doesn't apply to you.

Commands Explained

CommandWhat it does
apt install nginx -yInstalls the Nginx web server and its default config files, and starts the service automatically.
nginx -tChecks your config files for syntax errors without applying them. Always run this before restarting.
systemctl restart nginxStops and starts the Nginx service so it picks up your new config.
systemctl status nginxShows whether the service is currently running, and prints recent log lines if it isn't.
dig domain +shortLooks up the IP address a domain currently resolves to. Useful for confirming DNS is pointed correctly.
systemctl edit nginx.serviceOpens an override file for the Nginx systemd unit, letting you add extra startup rules without editing the original unit file.

Common Errors

502 Bad Gateway. Nginx can't reach Proxmox on port 8006. Usually means the IP in your upstream block is wrong, a firewall is blocking the connection between the two machines, or pveproxy itself isn't running on the Proxmox host.

The dashboard loads but the console won't connect. This is almost always the WebSocket headers. Double-check that proxy_set_header Upgrade $http_upgrade; and proxy_set_header Connection "upgrade"; are both present and spelled exactly right — a stray missing quote here fails silently instead of throwing an obvious error.

"duplicate default server" error on nginx -t. This means the old default site wasn't actually removed in Step 2, and both it and your new config are trying to claim port 80 or 443 as the default. Check /etc/nginx/sites-enabled/ and /etc/nginx/conf.d/ for leftovers.

Certificate warning still shows up. If you used the snakeoil certificate as shown above, this is expected — it's self-signed, same as Proxmox's own default cert. The browser warning goes away once you swap in a real Let's Encrypt certificate.

Troubleshooting

When something isn't working, check things in this order — it saves a lot of guessing:

  1. Confirm Nginx is actually running: systemctl status nginx. If it's not, run journalctl -xeu nginx to see why it failed to start.
  2. Confirm Nginx can reach Proxmox directly: from the Nginx box, run curl -k https://10.0.0.12:8006 (using your actual Proxmox IP). If that hangs or times out, the problem is network routing or a firewall rule, not Nginx.
  3. Confirm DNS resolves to the right box, as covered in Step 6 above.
  4. Check the Nginx error log for specifics: tail -f /var/log/nginx/error.log, then reload the page in your browser and watch what gets logged in real time.
  5. If the console specifically fails, open your browser's developer tools, go to the Network tab, and look for a WebSocket connection that's failing or never upgrading — that confirms it's the Upgrade header, not something else.

Best Practices

Keep Nginx off the Proxmox host itself. Running it in a small dedicated LXC container means an Nginx crash, a bad config push, or a package update gone wrong never takes down your actual hypervisor's management interface.

Don't skip the nginx -t check before restarting, even for a one-line change. It takes two seconds and it's the difference between a clean reload and locking yourself out of the web UI because of a typo.

If you're exposing this to the internet through a router port forward, consider adding IP allowlisting or at minimum keeping Proxmox's two-factor authentication turned on — the reverse proxy hides the port, but it doesn't replace actual access controls.

Once this base setup is solid, layering a real Let's Encrypt certificate on top is the natural next step. Don't try to do both at once on your first attempt — get the plain HTTP-to-8006 proxy working first, confirm the console connects, and only then add certificate automation.

Frequently Asked Questions

Does this replace Proxmox's built-in SSL certificate?

No. Proxmox still generates and uses its own certificate on port 8006 internally. Nginx is just the thing your browser actually talks to on port 443; what certificate Nginx itself presents is a separate, independent setting.

Will this work with a Proxmox cluster?

Yes, but you'll want to point the upstream block at whichever node you access most often, or set up a proper load balancer in front of all nodes if you want automatic failover between them. For a single-node homelab, pointing at one IP is fine.

Can I run Nginx Proxy Manager instead of raw Nginx config files?

Yes, and the WebSocket settings translate directly — NPM has a toggle for "Websockets Support" on the proxy host that does the same job as the Upgrade/Connection headers above. The custom location config option in NPM is where you'd add the buffering and timeout settings.

Why not just change Proxmox's port instead of using a reverse proxy?

You can change the port pveproxy listens on, but Proxmox's own documentation and most experienced admins advise against it — some internal cluster communication and API calls assume 8006, and future upgrades are more likely to catch you off guard if you've deviated from the default. A reverse proxy gets you the same result without touching Proxmox's own configuration at all.

Does this slow down the web interface?

Not in any way you'd notice. Nginx adds a tiny amount of latency, well under a millisecond on a local network, and with buffering disabled for the Proxmox location, the console stays just as responsive as connecting directly.

Conclusion

What you've got now is a Proxmox web interface that's reachable at a real address, on a normal port, without anything about Proxmox itself having changed. The hypervisor doesn't know or care that Nginx is in front of it — pveproxy is still doing exactly what it always did on port 8006, quietly, in the background.

From here, the obvious next move is a real Let's Encrypt certificate so the browser stops flagging the connection entirely, but that's worth its own dedicated pass rather than rushing it. Get comfortable with this setup first — restart Nginx a few times, break the config on purpose and fix it, watch the error log while you do it. That's the kind of familiarity that makes the next step easier.