RSS Amplifier

Binary Tech {LABS} · Aug 7, 2026

Reverse Proxies Explained: Nginx Proxy Manager vs Caddy vs Traefik

0
Sign in to vote or save

Binary Tech Labs · Binary Tech {LABS}

Home /Self-Hosted

Self-Hosted

Tired of remembering :8123, :3001, and :8971? A reverse proxy provides every service a clean name and free HTTPS. Here's how they work, plus an honest comparison of the big three for home labbers.

Binary Tech Labs

Binary Tech Labs

20 min read

Stop memorizing ports: reverse proxies for the home lab

Your home lab has a growing problem, and it probably looks like this:

192.168.1.50:8123
192.168.1.50:3001
192.168.1.50:8971
192.168.1.50:2283
192.168.1.50:8080
192.168.1.50:9091

At first, this feels normal. You install Home Assistant; it lives on port 8123. You install Immich; it lives on port 2283. You install Sonarr, Radarr, SABnzbd, Uptime Kuma, Portainer, Jellyfin, Paperless, and whatever else you are currently convincing yourself is "basically infrastructure," and suddenly your browser bookmarks look like the back of a broken router.

This is where a home lab starts feeling less like a clean little private cloud and more like a junk drawer with an IP address.

The real problem is not that the ports exist. Ports are fine. The problem is that humans are bad at remembering them, browsers complain about plain HTTP, and your family is absolutely not typing 192.168.1.50:2283 into a phone so they can look at photos.

That is a you problem. More specifically, it is a reverse proxy problem.

A reverse proxy turns this:

http://192.168.1.50:8123
http://192.168.1.50:2283
http://192.168.1.50:8989
http://192.168.1.50:7878

Into this:

https://home.yourdomain.com
https://photos.yourdomain.com
https://sonarr.yourdomain.com
https://radarr.yourdomain.com

Names beat numbers. Every time.

A split-screen illustration comparing a messy drawer of tangled network cables and port-number sticky notes to a pristine, glowing server rack with holographic labels
Network Chaos vs. Server Order

A reverse proxy is one of the best quality-of-life upgrades in self-hosting. It makes your services easier to use, easier to secure, easier to explain, and easier to hand off to normal people who do not want to participate in your networking side quest.

Today we are going to explain what a reverse proxy does, why your home lab probably needs one, and which one you should choose between Nginx Proxy Manager, Caddy, and Traefik.

Short version: if you are brand new, use Nginx Proxy Manager. If you want the best long-term home lab setup, use Caddy. If your lab is turning into a small hosting company with a caffeine problem, use Traefik.

Now let’s make that actually useful.

The port number mess

Every web service needs a way to listen for traffic. That usually means an IP address and a port.

Your server might have this IP address:

192.168.1.50 or 10.0.0.53 or some other numbers

Then each service listens on a different port:

Home Assistant: 192.168.1.50:8123
Immich:         192.168.1.50:2283
Sonarr:         192.168.1.50:8989
Radarr:         192.168.1.50:7878
Portainer:      192.168.1.50:9443
Uptime Kuma:    192.168.1.50:3001

This approach works, technically.

And "technically works" is the official motto of many home labs.

But it has problems:

  • You have to remember which service uses which port.
  • You end up with ugly bookmarks.
  • Some services run over HTTP instead of HTTPS.
  • Your browser complains that the connection is not secure.
  • Mobile apps sometimes hate weird ports.
  • Sharing access with family gets annoying.
  • Opening services safely to the outside world can quickly become messy.
  • Every container starts publishing ports like it is handing out flyers at a trade show.

The situation is manageable with three services.

It is annoying with ten.

It is cursed with twenty.

At some point you need a front door.

That front door is the reverse proxy.

What is a reverse proxy?

A reverse proxy is a web server that sits in front of your other web services.

Futuristic robot AI directs data streams towards 'Surveillance Feed' and 'Smart Home Hub' doorways in a glowing digital network
Robot AI Data Traffic Director

Instead of connecting directly to Home Assistant, Immich, Sonarr, or Portainer, your browser connects to the reverse proxy. The reverse proxy looks at the hostname you requested and forwards the traffic to the right internal service.

For example:

https://home.yourdomain.com

The reverse proxy sees home.yourdomain.com and sends that traffic to:

http://homeassistant:8123

Then:

https://photos.yourdomain.com

Gets sent to:

http://immich:2283

And:

https://uptime.yourdomain.com

Gets sent to:

http://uptime-kuma:3001

Your users never see the internal ports. They only see clean names.

The proxy is the traffic cop.

The browser comes in asking for photos.yourdomain.com.

Proxy says, "That one goes to Immich."

The browser asks for home.yourdomain.com.

Proxy says, "That one goes to Home Assistant."

That is the whole idea.

It sounds simple, because it is simple. The trick is doing it reliably, safely, and without turning your Docker Compose files into ancient forbidden scrolls.

Reverse proxy vs regular proxy

Many people get tangled up here, so let’s clear it up.

A regular forward proxy usually sits in front of clients.

Your computer asks the proxy to go fetch a website for you.

Your laptop → proxy → internet

A reverse proxy sits in front of servers.

The internet, or your LAN, asks the proxy to reach a service behind it.

Your browser → reverse proxy → Home Assistant

You do not need to remember the distinction forever. Just remember this:

A reverse proxy protects and organizes your services, and that's all we care about in the home lab.

The three jobs of a reverse proxy

A reverse proxy normally does three main jobs in a home lab.

1. Routing

Routing means the proxy looks at the hostname and forwards traffic to the right service.

Example:

photos.home.example.com → immich:2283
home.home.example.com   → homeassistant:8123
media.home.example.com  → jellyfin:8096

This lets you stop caring about random ports.

You care about names instead.

That matters because names are memorable. Furthermore, names survive change better than ports. If you move Immich from one machine to another, you can update the proxy behind the scenes and keep using the same address.

That is good infrastructure. It is boring, flexible, and not dramatic.

2. TLS termination

TLS (Transport Layer Security) is the industry standard protocol used to encrypt data and is the encryption method behind HTTPS.

When your browser shows the little padlock, TLS is involved.

Image of the padlock that shows the website is secure and using HTTPS
Padlock that secures the website.

Without a reverse proxy, each service may need to handle HTTPS on its own. Some services do this task well. Some barely do it. Some assume you are putting them behind a proxy and do not make the experience pleasant.

A reverse proxy can handle HTTPS centrally.

That means:

Browser → HTTPS → Reverse proxy → HTTP → Internal service
A technical illustration showing an HTTPS request traveling from the internet to a home lab, passing through a reverse proxy which then forwards the request unencrypted (HTTP) to an internal web service
Secure HTTPS Request Flow from Internet to Home Lab

From your browser to the proxy, traffic is encrypted.

Inside your private Docker network or LAN, the proxy may talk to the service over plain HTTP. That is usually fine inside a trusted local network, though you can tighten that up later if you like.

The important part is that your browser sees a proper secure site.

No more ugly warnings.

No more explaining to your spouse that "it says 'not secure,' but it’s fine, trust me."

That sentence has never made anyone feel better.

3. Certificate automation

HTTPS needs certificates.

You can create your own self-signed certificates, but then every browser and phone will complain unless you manually install your own certificate authority. That is a real treat if your idea of fun is ruining your Saturday and Sunday.

Most modern reverse proxies can request real certificates from Let’s Encrypt, and the best part is, Let’s Encrypt is free. The certificates are trusted by normal browsers, and your proxy can renew them automatically.

That means you get real HTTPS without manually copying certificate files around like it is 2009.

This is one of the best parts of using a proper reverse proxy.

The clean home lab pattern

The clean home lab pattern looks like this:

*.yourdomain.com → your reverse proxy

That * is called a wildcard DNS record.

It means that anything under *.yourdomain.com points to the same place.

So these all point to your proxy:

home.yourdomain.com
photos.yourdomain.com
media.yourdomain.com
uptime.yourdomain.com
paperless.yourdomain.com

Then the reverse proxy decides where each one goes. Yes, it feels a bit fancy the first time, and no, you don’t need to expose everything to the internet.

That part matters.

The magic trick: DNS-01 challenges

Let’s Encrypt needs to prove you control the domain before it gives you a certificate.

There are a few ways to prove your ownership.

The common one is HTTP-01. Let’s Encrypt connects to your server over the public internet and checks for a special file.

That works, but it means your proxy must be reachable from the internet. For a private home lab, that may not be what you want. The better home lab pattern is DNS-01.

With DNS-01, your proxy proves domain ownership by creating a temporary DNS record. Let’s Encrypt checks that DNS record. If it matches, you get the certificate.

The nice part: your services do not need to be exposed to the internet. A $10 to $20 per year domain and a free Cloudflare account can get you there.

Why not just use plain local DNS?

You can absolutely use local DNS.

For example, if you run Pi-hole, AdGuard Home, Unbound, or your router supports DNS overrides, you can make the following:

photos.home.arpa

Point to:

192.168.1.50

That works, but the issue is with the certificates. Browsers trust certificates for real domain names. They do not automatically trust random internal names unless you set up your own certificate authority and install it on every client.

That is doable, but it is more work, and for most home lab people, a real domain plus DNS-01 is easier and cleaner.

What your Docker setup should look like

Most self-hosted services are now running in Docker. A reverse proxy fits nicely into that world.

The simple pattern is:

  1. Create a shared Docker network.
  2. Place your reverse proxy on that network.
  3. Put your web services on that network.
  4. Stop publishing every service port to the LAN.
  5. Let the proxy be the only container exposing ports 80 and 443.

Example:

networks:
  proxy:
    external: true

Your reverse proxy joins the proxy network.

Your services join the proxy network too.

Then the proxy can reach them by container name:

immich:2283
homeassistant:8123
uptime-kuma:3001

This method is cleaner than routing everything through LAN IPs.

Instead of this approach:

192.168.1.50:2283

The proxy can use this:

immich:2283

That means you can move containers around more easily, and your config reads like a map instead of a police report.

Stop publishing every port

This is a big one. When you are new to Docker, every compose file seems to have a ports: section.

Something like this:

ports:
  - "2283:2283"

That means Docker publishes the service to the host machine. Anything on your LAN can reach it, and that is fine while testing. But once you have a reverse proxy, you usually do not need to publish every service port.

Instead, the service can expose the port only inside Docker, and the reverse proxy can reach it over the shared Docker network. This approach reduces clutter and shrinks your attack surface. It also helps you avoid accidentally exposing something weird later.

Do not blindly delete ports from every service without checking how it works. Some things need LAN access directly.

The contenders

There are many reverse proxies, but three dominate home lab conversations:

  • Nginx Proxy Manager
  • Caddy
  • Traefik

They all work. They all can get certificates. They all route traffic.

The difference is how they expect your brain to work.

Nginx Proxy Manager: the friendly face

Nginx Proxy Manager, often called NPM, is a web interface for Nginx.

Nginx itself is one of the most proven web servers on earth. It is fast, stable, and everywhere. Nginx Proxy Manager wraps it in a friendly UI so normal humans can use it without writing Nginx config files by hand.

You log into the NPM dashboard, add a proxy host, type the domain name, point it at an internal IP and port, request a certificate, and you are done.

Example:

Domain: photos.example.com
Forward hostname/IP: immich/192.168.1.56
Forward port: 2283
Request SSL certificate: yes
Force SSL: yes

Click save. Done. That is the appeal.

Why people like Nginx Proxy Manager

Nginx Proxy Manager is great because it gives beginners quick wins.

You do not need to understand routers, middlewares, labels, entrypoints, providers, or certificate resolvers. You add a host. You point it at a service. You get a certificate.

For many people, this is exactly right, and besides, the home lab already has enough places where you can fall into a hole. Your reverse proxy does not need to be another one.

NPM is especially good if:

  • You think in GUIs (Graphical User Interfaces).
  • You want to see all your proxy hosts in one place.
  • You are still learning Docker networking.
  • You would rather not write config files yet.
  • You need something that works now.

It also makes setting up SSL certificates fairly approachable. You can use HTTP validation for public services or DNS validation for providers it supports.

Where Nginx Proxy Manager gets annoying:

The catch is that NPM stores config in a database.

That is fine until you start caring about backups, Git, rebuilds, and infrastructure as code.

With a file-based proxy like Caddy, your config might be one simple text file. You can back it up, version it, review changes, and rebuild from scratch.

With NPM, your setup lives in its database. You can still back it up, but it is not as clean as committing a config file to Git. Advanced setups can also hit the edge of what is possible with the UI (User Interface.)

If you need unusual headers, advanced routing, custom logic, special authentication flows, or complex middleware, the UI starts to feel like training wheels welded to the bike.

That does not make NPM bad. It means NPM is best at the thing it is designed for: simple, friendly proxy management.

Best use case

Use Nginx Proxy Manager if you are just starting out or if you want a simple dashboard.

Caddy: the minimalist’s choice

Caddy is the cleanest option for most home lab people who like config files.

Its entire personality is "Tell me the hostname and where to send it." I’ll handle HTTPS."

A Caddy config can be this small:

photos.home.example.com {
    reverse_proxy immich:2283
}
home.home.example.com {
    reverse_proxy homeassistant:8123
}
uptime.home.example.com {
    reverse_proxy uptime-kuma:3001
}

That is it. Caddy automatically gets and renews certificates. HTTPS is not a feature you bolt on later. It is the default behaviour, and that is why people love it.

Why Caddy feels so good

Caddy has the best ratio of power to configuration pain.

It is file-based, which means your whole proxy config can live in Git:

Caddyfile
docker-compose.yml
.env

Back it up. Rebuild it. Review it. Copy it to a new machine. No database headaches.

It is also human readable. If you open a Caddyfile six months later, you can understand it quickly:

photos.home.example.com {
    reverse_proxy immich:2283
}

Such simplicity matters more than people admit. Your home lab will break at some point. When it does, you want a boring configuration that you can understand, even if you are mildly annoyed.

DNS-01 with Caddy

Here is the main Caddy speed bump: DNS-01 challenges usually need a DNS provider plugin. For Cloudflare, that means using a Caddy build that includes the Cloudflare DNS module. That can sound scarier than it is.

You might create a simple Dockerfile like this:

FROM caddy:builder AS builder
RUN xcaddy build \
    --with github.com/caddy-dns/cloudflare
FROM caddy:latest
COPY --from=builder /usr/bin/caddy /usr/bin/caddy

Then build your own Caddy image with Cloudflare DNS support. That is not hard, but it is one extra step. If you are new, it may feel overwhelming, but once it is completed, it tends to remain that way.

Example Caddy setup with Cloudflare DNS

Your Caddyfile might look like this:

{
    acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
    email [email protected]
}
photos.home.example.com {
    reverse_proxy immich:2283
}
home.home.example.com {
    reverse_proxy homeassistant:8123
}
uptime.home.example.com {
    reverse_proxy uptime-kuma:3001
}

Depending on your exact Caddy version and plugin, syntax may vary a little. The point is the same: Caddy can use Cloudflare DNS to prove domain ownership without exposing services publicly. Your .env file would hold the token:

Do not commit that .env file to Git. Instead, please commit an example file:

CLOUDFLARE_API_TOKEN=replace-me

That one tiny habit saves your future self from doing the "oh no, I pushed secrets" to a public Git repo.

Best use case

Use Caddy if you want the cleanest long-term setup. It is my overall pick for most home labs because:

  • The config is small.
  • HTTPS is automatic.
  • It is easy to read.
  • It is file-based.
  • It works beautifully with Docker.
  • It does not bury your setup in a database.
  • It feels boring in the best possible way.

Caddy is the one I would pick for a home lab I want to maintain instead of constantly babysitting.

Traefik: the automation powerhouse

Traefik is the reverse proxy for people who want the proxy to discover services automatically.

A detailed visualization of multiple advanced robotic arms processing glowing data cubes along conveyor belts marked "QUANTUM-NET," in a futuristic, multi-level facility with holographic interfaces and industrial machinery
Automated Quantum Network Data Hub with Robotic Arms

Instead of writing one central config file with every route, you add labels to each Docker container. Traefik watches Docker. When it sees a container with the right labels, it creates the route automatically.

Example:

services:
  immich:
    image: ghcr.io/immich-app/immich-server
    labels:
      - traefik.enable=true
      - traefik.http.routers.immich.rule=Host(`photos.example.com`)
      - traefik.http.routers.immich.entrypoints=websecure
      - traefik.http.routers.immich.tls.certresolver=cloudflare
      - traefik.http.services.immich.loadbalancer.server.port=2283

That is powerful. It is also a lot to handle if you are new.

Why Traefik is popular

Traefik shines when you have lots of services that come and go.

Each service carries its own routing config. That means your Immich compose file has the Immich route. Your Uptime Kuma compose file contains the Uptime Kuma route. Your paperless compose file has the paperless route.

That can be beautiful once your lab grows. You do not need to edit one central proxy config every time. Add labels, restart the container, and Traefik updates everything.

Traefik also has excellent support for:

  • Docker discovery
  • Kubernetes
  • middleware
  • authentication chains
  • multiple entrypoints
  • automatic certificates
  • dashboards
  • load balancing
  • complex routing rules

It is a serious tool.

Why Traefik confuses people

Traefik has its own vocabulary.

You will meet:

  • entrypoints
  • routers
  • services
  • middleware
  • providers
  • certificate resolvers

None of these are impossible, but they are a lot on day one.

A beginner expects to say the following:

photos.example.com goes to immich:2283

Traefik says:

Create a router using a Host rule, attach it to an entrypoint, enable TLS using a certresolver, then define the internal service load balancer port, possibly with middleware.

That is not wrong. It is just more machinery. Once you understand it, Traefik is elegant. Before you understand it, it feels like the homework your old math teacher used to hand out just before the end of the day.

The label problem

Traefik labels are both the best and worst part. They are fantastic because route config lives beside the service. They are annoying because your compose files can get busy.

A simple app that used to be:

services:
  app:
    image: example/app

Turns into:

services:
  app:
    image: example/app
    labels:
      - traefik.enable=true
      - traefik.http.routers.app.rule=Host(`app.home.example.com`)
      - traefik.http.routers.app.entrypoints=websecure
      - traefik.http.routers.app.tls=true
      - traefik.http.routers.app.tls.certresolver=cloudflare
      - traefik.http.services.app.loadbalancer.server.port=8080

That is manageable, but multiply it by twenty services, and your compose files start wearing tool belts. Some people love that. Some people hate it.

Best use case

Use Traefik if:

  • You already understand Docker networking.
  • You have lots of services.
  • You like labels.
  • You want automatic service discovery.
  • You are building something closer to a platform.
  • You are willing to climb the learning curve.

Do not use Traefik just because someone on Reddit made it sound more "professional." "Professional" does not mean complicated. "Professional" means reliable and maintainable. For many home labs, Caddy is more maintainable.

Quick comparison

Tool Best for Main strength Main catch
Nginx Proxy Manager Beginners Friendly web UI Config lives in a database
Caddy Most home labs Tiny config, automatic HTTPS DNS plugins may need custom image
Traefik Large Docker labs Auto discovery with labels Steepest learning curve

Here is the practical version:

If you want a dashboard, use Nginx Proxy Manager. If you want simple config files, use Caddy. Traefik is the right choice if you want your containers to define their own routes.

A safe home lab layout

Here is the pattern I recommend for most people.

1. Buy a domain

There are many providers out there; I recommend Namecheap. They have been good to me to use over the years, and I like the email service you can get with their domains, so you can have branded emails easily and stop using those @live or @gmail addresses. So, start with something simple:

example.com

Then create your home lab subdomains:

home.example.com
photos.example.com
media.example.com
uptime.example.com

2. Use Cloudflare DNS

You do not have to use Cloudflare, but it is common, well supported, and works with DNS-01 challenges.

Create an API token with only the permissions needed to edit DNS for that zone. Do not use your full Cloudflare global API key if you can avoid it. A narrow API token is safer.

3. Point wildcard DNS at the proxy

For internal-only setups, you have two common approaches.

Option A: The public DNS points to a private IP address.

This approach can work, but some DNS providers may not like private IP records. Cloudflare DNS-only records can handle this scenario, but do not proxy private IPs through Cloudflare.

Option B: split DNS using Pi-hole, AdGuard Home, or router DNS.

Only your LAN sees that answer. This is cleaner for private home labs.

4. Use DNS-01 for certificates

Your reverse proxy uses the DNS provider API to prove domain ownership. No public inbound port needed for certificate issuance.

5. Put the proxy on a shared Docker network

Create a network:

docker network create proxy

Then attach your proxy and web services to that network.

In Compose:

networks:
  proxy:
    external: true

Then each service can join it:

services:
  immich:
    networks:
      - proxy

6. Stop exposing every web port

For services behind the proxy, remove unnecessary ports: mappings.

Instead of the below: Use Docker networking and let the proxy reach the container internally.

ports:
  - "2283:2283"

Sometimes you may keep a port temporarily for troubleshooting. That is fine. Just do not let temporary become permanent by accident, which is basically the home lab curse.

Important security note

A reverse proxy is not magic armour. It organizes access. It can reduce exposed ports. It can centralize HTTPS. It can make your setup cleaner.

But if you expose a vulnerable service to the internet through a reverse proxy, it is still exposed. Do not confuse "behind a proxy" with "safe."

If a service is only for your house, keep it private. Use VPN access, Tailscale, WireGuard, Cloudflare Tunnel with access controls, or another proper remote access pattern.

A reverse proxy is a front door. You still need a lock. Sometimes you need a fence and a moat and some alligators too.

The Home Assistant gotcha

Home Assistant is picky about proxied traffic, and for good reason.

If you put Home Assistant behind a reverse proxy, you usually need to update configuration.yaml with trusted proxy settings.

Example:

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 172.18.0.0/16

That IP range depends on your network. If Home Assistant rejects traffic after you put it behind the proxy, do not panic. This is probably why.

Check the IP address range of your Docker network:

docker network inspect proxy

Look for the subnet. Then add the correct subnet to trusted_proxies.

Restart Home Assistant. Budget five minutes for the task now, or discover it at 11 PM when your lights suddenly feel very manual.

The Uptime Kuma gotcha

If your reverse proxy goes down, everything behind it looks down.

That means you should not only monitor your services through the proxy.

If Uptime Kuma monitors the following:

https://photos.example.com

If the proxy dies, Immich may still be fine, but Kuma will report it as down.

That is useful, but incomplete. You should monitor both:

https://photos.example.com

And, if appropriate:

http://immich:2283 or http://<ip-address>:2283

Or monitor the container directly.

Also, please avoid placing Uptime Kuma solely behind the proxy and relying on it to notify you when the proxy is down. That is like unplugging your smoke detectors and then starting a fire and wondering why you are not being alerted.

Better pattern:

  • Monitor the proxy itself.
  • Monitor key services through the proxy.
  • Monitor key services internally if you are concerned about the root cause.
  • Keep at least one way to reach your server directly for admin work.

Common mistakes

Mistake 1: exposing the proxy and every service

People set up a reverse proxy but often leave the old ports published.

So they have:

https://photos.example.com

But also:

http://192.168.1.50:2283

This is not a major issue on a private LAN, but it undermines part of the cleanup.

If the proxy is the front door, please ensure that side doors are not left open unless there is a specific reason to do so.

Mistake 2: using HTTPS publicly but HTTP locally without understanding it

This setup is common:

Browser → HTTPS → Proxy → HTTP → Service

That is usually fine inside Docker or a trusted LAN. But be aware of what is happening. The proxy terminates TLS. Your internal traffic may be plain HTTP.

If you have hostile devices on your LAN, bigger problems exist. But still, understand the trust boundary.

Mistake 3: exposing admin tools to the internet

Do not casually expose things like:

  • Portainer
  • Proxmox
  • router admin pages
  • database admin panels
  • Docker socket proxies
  • random dashboards with weak auth

If you need remote access, use a VPN or proper access control. "Nobody will discover it" is not a security plan.

Mistake 4: using one giant admin password everywhere

Your proxy is now important. Use strong passwords. Use MFA where available. Back up config. Keep the container updated. Do not treat the reverse proxy like a toy once everything depends on it.

Mistake 5: forgetting backups

For Nginx Proxy Manager, back up the database and config volume.

For Caddy, back up:

Caddyfile
docker-compose.yml
.env example
data volume
config volume

For Traefik, back up:

docker-compose.yml
dynamic config files
.env example
acme.json

That acme.json file is relevant for Traefik because it stores certificates. Protect it.

Example: Caddy home lab setup

Here is a simplified Caddy example.

Folder layout

reverse-proxy/
  docker-compose.yml
  Caddyfile
  .env

docker-compose.yml

services:
  caddy:
    build: .
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    environment:
      - CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN}
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - proxy
networks:
  proxy:
    external: true
volumes:
  caddy_data:
  caddy_config:

Caddyfile

{
    email [email protected]
}
photos.home.example.com {
    reverse_proxy immich:2283
}
home.home.example.com {
    reverse_proxy homeassistant:8123
}
uptime.home.example.com {
    reverse_proxy uptime-kuma:3001
}

If you need DNS-01 through Cloudflare, you will need the Cloudflare DNS plugin and the matching Caddyfile syntax. That is the one extra wrinkle.

Still, the day-to-day config stays beautifully small.

Example: Nginx Proxy Manager setup

NPM is usually a Docker Compose stack.

services:
  npm:
    image: jc21/nginx-proxy-manager:latest
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - "80:80"
      - "81:81"
      - "443:443"
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    networks:
      - proxy
networks:
  proxy:
    external: true

The admin UI is usually on:

http://<server-ip>:81

Then you add proxy hosts in the UI.

For each service:

Domain Names: photos.example.com
Scheme: http
Forward Hostname/IP: immich
Forward Port: 2283

Then request an SSL certificate.

Also enable:

Force SSL
HTTP/2 Support

Just remember to back up the data and letsencrypt folders.

Example: Traefik setup

Traefik is more involved.

A simplified Traefik service:

services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: unless-stopped
    command:
      - --api.dashboard=true
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --certificatesresolvers.cloudflare.acme.dnschallenge=true
      - --certificatesresolvers.cloudflare.acme.dnschallenge.provider=cloudflare
      - [email protected]
      - --certificatesresolvers.cloudflare.acme.storage=/letsencrypt/acme.json
    ports:
      - "80:80"
      - "443:443"
    environment:
      - CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt
    networks:
      - proxy
networks:
  proxy:
    external: true

Then a service gets labels:

services:
  immich:
    image: ghcr.io/immich-app/immich-server
    labels:
      - traefik.enable=true
      - traefik.http.routers.immich.rule=Host(`photos.home.example.com`)
      - traefik.http.routers.immich.entrypoints=websecure
      - traefik.http.routers.immich.tls.certresolver=cloudflare
      - traefik.http.services.immich.loadbalancer.server.port=2283
    networks:
      - proxy

This is very powerful. It is also why I do not recommend Traefik as the first reverse proxy for most people.

A quick word on remote access

A reverse proxy does not automatically mean public access.

You can use it for LAN only. If you want remote access, consider your options.

Good options include:

  • Tailscale
  • WireGuard
  • Cloudflare Tunnel with access controls
  • VPN into your home network
  • Reverse proxy plus proper authentication

Bad option:

Open every cool service to the internet and hope passwords are enough.

Some services are not designed to be internet-facing. Even if they have logins, that does not mean you should expose them. For family photo access, it may make more sense to use Immich behind a properly secured tunnel.

The bottom line

A reverse proxy turns your pile of ports into a clean, named, HTTPS-friendly platform. Your services become easier to remember, easier to secure, easier to share, and easier to maintain.

My recommendation:

  • Use Nginx Proxy Manager if you are new and want a friendly UI.
  • Use Caddy if you want the cleanest long-term setup.
  • Use Traefik if your lab is big enough that automatic Docker discovery actually solves a problem.

For most people, Caddy is the winner.

It is simple, file-based, Git-friendly, and boring in the good way. A tiny Caddyfile can replace a pile of weird bookmarks and browser warnings.

Set it up this weekend.

Your family still may not care about your home lab, but at least they will not need a cheat sheet for port numbers to use it.

💡 Affiliate Disclosure: This post contains affiliate links. If you make a purchase through them, I may earn a small commission at no extra cost to you. I only recommend tools and services I actually use and trust.

Join the Conversation: Got questions or ideas for a future build? Drop a comment below—I’d love to hear what you're working on.

Stay Updated: The best way to support the site is to subscribe to the newsletter. You can also still find my video archive over on YouTube. Thanks for reading, and happy building!

Binary Tech Labs

Binary Tech Labs

YouTube content creator that provides tech tutorials and reviews on Home Assistant, IoT devices, Raspberry Pi and other Single Board Computers

Read the original on binarytechlabs.com

Comments

Nothing yet. Say the first thing.

    Sign in to join the conversation.

    Reading · Binary Tech {LABS} · RSS Amplifier