One of the first things I set up in my Homelab is a reverse proxy.

What is a Reverse Proxy

As I spin up containers and virtual machines in my homelab, I want to be able to use domain names rather than IP addresses (and port numbers) to access them.

Bad 192.168.10.126:8006 Good proxmox.edgamat-homelab.com

A reverse proxy helps me achieve this. It is a service that sits between me and my homelab devices. when I make a request to the reverse proxy (e.g. https://proxmox.edgamat-homelab.com), it routes the traffic to port 8006 at IP address 192.168.10.126.

flowchart TD
    A([🌐 Internet/External client request])

    subgraph CF["☁️ Cloudflare"]
        B[Domain Registrar edgamat-homelab.com → your public IP Optional DNS proxy / CDN]
    end

    subgraph UNIFI["🔀 Unifi Router"]
        C[WAN Interface Port forward 80 / 443 → NGINX host Local DNS overrides for internal clients]
    end

    subgraph HOMELAB["🏠 Homelab LAN"]
        N["⚡ NGINX Reverse Proxy Terminates TLS — Let's Encrypt or Cloudflare origin cert Routes by hostname → upstream service"]

        S1[Home Assistant 192.168.1.x:8123]
        S2[Proxmox 192.168.1.x:8006]
        S3[Portainer 192.168.1.x:9000]
        S4[Other services custom ports]

        N --> S1
        N --> S2
        N --> S3
        N --> S4
    end

    A -->|"DNS lookup: edgamat-homelab.com"| CF
    CF -->|"Resolves to public IP HTTPS request"| UNIFI
    UNIFI -->|"Port forward 443"| N

NGINX Proxy Manager (NPM)

NGINX is honestly the only reverse proxy I know. There are others out there, but I’ll stick with what I know. I discovered NGINX Proxy Manager (NPM) which is a nice web-based GUI for managing the configuration of NGINX. As a bonus it integrates with Let’s Encrypt to set up free SSL/TLS certificates. With a registered domain name, this eliminates those SSL/TLS warning messages in browsers. Yay!

Hosting NPM in Docker

I decided to host NPM in a container using Docker. I am using a Raspberry Pi to host some light-weight services, so that’s where I am placing NPM. I am using the following Docker Compose file:

services:
  npm:
    container_name: npm
    image: jc21/nginx-proxy-manager:latest
    restart: always
    volumes:
      - /srv/docker/npm/data:/data
      - /srv/docker/npm/letsencrypt:/etc/letsencrypt
    ports:
      - 80:80
      - 443:443
      - 81:81  # Admin UI

networks:
  default:
    name: npm_network

I set up the local bind mounts using the following commands:

sudo mkdir /srv/docker
sudo chown $USER:docker /srv/docker
sudo chmod 770 /srv/docker
sudo chmod g+s /srv/docker
mkdir -p /srv/docker/npm/data /srv/docker/npm/letsencrypt

I then started the container:

docker compose up -d

With all this setup in place, I was ready to give things a try. I went to the NPM admin page:

http://192.168.10.125:81/

I created an account and everything was working!

Registering a Domain

I use GoDaddy to register the domain for my blog, but for my homelab I wanted to try something different. I chose Cloudflare, simply by reputation (and seemingly good support with NPM). I registered my homelab domain by creating an account and choosing a domain name: edgamat-homelab.com. I was able to register the domain for a reasonable cost but if it had been much more expensive I would have looked for another option.

Adding a Certificate

In NPM, I added the certificate using the “Let’s Encrypt via DNS” option:

Domain Names: *.edgamat-homelab.com
Key Type: ECDSA 256 (the default)
DNS Provider: Cloudflare

When I selected Cloudflare, I had to provide an API token:

# Cloudflare API token
dns_cloudflare_api_token=0123456789abcdef0123456789abcdef01234567

I was able to create a token within my Profile on the Cloudflare website. I selected the “Edit zone DNS” template from the list. Under “Zone Resources”, I selected my domain. I created the token and used it when creating the certificate in NPM.

Adding DNS Entries

In my router, I created a DNS rule for my first proxy host, NPM itself!

npm.edgamat-homelab.com =>  192.168.10.125

NOTE Originally I was using a single wildcard entry (*.edgamat-homelab.com). But I have moved to using separate entries for each service.

Adding Proxy Hosts

In NPM, I created a new proxy host for NPM:

Domain Names: npm.edgamat-homelab.com
Scheme: http
Forward Hostname / IP: 192.168.10.125
Port: 81

Under the SSL tab, I selected my certificate and enabled “Force SSL” and “Enable HTTP/2 Support”.

The Result

I gave the new proxy host a try:

https://npm.edgamat-homelab.com

I was successfully able to access NPM. I felt relieved that it all worked. I have also added 2 additional hosts for Portainer and Proxmox. With the Proxmox proxy, I also had to enable “Websockets Support” but otherwise it used the same setup as the others.

It has been great having a proxy server running right for the start of my homelab adventure. It is not a necessary service to have, but makes things so much easier.