Caddy as a Proxmox Reverse Proxy

If you are:

  • Running Proxmox
  • Annoyed by having to address port 8006 in your browser’s URL bar to access the GUI
  • Disinterested in doing all this NGINX configuration for a reverse proxy solely for this purpose
  • Already using Proxmox’s built-in ACME certificate requisition via DNS
    (Proxmox built–in standalone ACME won’t work for this because it needs to ephemerally bind port 80; it MUST be DNS)

Then read on, and we’ll have an easy Caddy reverse proxy configured in just three steps.

Install Caddy

Open a shell on the host via the Proxmox GUI and run:

apt update && apt install caddy

Add configuration

Move the default Caddyfile out of the way and write our new Caddyfile:

mv /etc/caddy/Caddyfile{,.bak}
nano /etc/caddy/Caddyfile

Now paste in the following config:

/etc/caddy/Caddyfile
pve.example.com {
  tls /etc/pve/local/pveproxy-ssl.pem /etc/pve/local/pveproxy-ssl.key
  reverse_proxy https://:8006 {
    transport http {
      tls_server_name pve.example.com
    }
  }
}

Make sure you change both instances of pve.example.com to the actual domain name you’re already using for Proxmox and have ACME DNS-validated certificates for. Finally, reload Caddy:

service caddy reload

Edit systemd unit

Caddy should be working right now, but the systemd service will fail at startup. This is because it requires the /etc/pve/local/pveproxy-ssl.* files, which don’t exist at boot - these are provided just a little later on during the startup process. We need to delay the Caddy service until after we know the certificate is available for Caddy to load.

The Wiki post linked above (for NGINX) explains that you can predicate the systemd unit on pve-cluster.service, which provides /etc/pve. You can also predicate it on pveproxy.service, which is the actual GUI web server itself. By doing that, we know not only that the certificate is available, but that the upstream web server is also available.

To fix this, run:

systemctl edit caddy

And add the following lines in the space provided:

[Unit]
PartOf=pveproxy.service
After=pveproxy.service

PartOf= is used instead of Requires= as this allows systemd to restart Caddy whenever pveproxy restarts as well, ensuring that we pick up fresh certificates when they’re loaded.

When you finish editing, systemd will install this tweak as an override for the Caddy service, and Caddy should now start at boot without issue.

2 Likes