The end goal is to be able to expose apps deployed locally on homelab publicly. I don’t want to expose multiple ports to the Internet for several reasons:

  • I have to create multiple port-forwarding rules.
  • The address not memorable because I need to remember the ports. Eg: homeip.example.com:32400 for Plex, homeip.example.com:1194 for VPN, and so on…

The alternative is to use reverse proxy.

  • setup reverse proxy
  • setup port forward (80 & 443) for reverse proxy
  • config reverse proxy to proxy the local apps

Reverse proxy

I would have gone with nginx but I want to tinker with Caddy. I have never used Caddy in production and this seems like a good excuse to learn about it (That’s what homelab is for right?). Caddy comes with HTTPS by default via Lets Encrypt. It’s perfect for home usage.

I was wondering if it’s possible to proxy upstream to Docker host. Turns out it’s possible. You just have to use host.docker.internal as upstream address. (ref)

docker run -d -p 1880:80 -p 18443:443  --network home-net \
    -v $(pwd)/Caddyfile:/etc/caddy/Caddyfile \
    -v $(pwd)/site:/usr/share/caddy \
    -v $(pwd)/data:/data \
    -v $(pwd)/config:/config \
    caddy/caddy caddy run -config /etc/caddy/Caddyfile --watch

Notice that I run Caddy in home-net network there, so that I can easily proxy other containers.

Dynamic DNS

You need to setup

  • an A record for your home IP (eg: homeip.example.com)
  • multiple CNAME records for each of your apps (eg: plex.example.com CNAME to homeip.example.com).

I covered this topic in a previous post of mine here.

Port forwarding

You need to do port forwarding (80 & 443) for your Reverse proxy. The setting is different, largely depends on your lab equipment and your ISP.

I was stuck for a day debugging why port forwarding didn’t work and it turned out, my ISP use NAT public IP address.

port forwarding

Verify

To test this, I create an nginx container with

docker run --name nginx --network home-net -d nginx

And edit the Caddyfile to this

example.com {
    reverse_proxy / nginx:80
}

And it should show nginx default page

Also, you should see the page in HTTPS.