New: the Homelab Planning Bundle. Both planners together for $19.99 instead of $27.98Save $7.99GET THE BUNDLE

Homelab Addiction
Security

Homelab HTTPS Setup: Certificates, DNS, and Local Access Without Browser Warnings

Set up HTTPS for a homelab by pairing a reverse proxy, certificate challenge path, and local DNS override so internal traffic stays local without browser warnings.

HomelabAddiction Research Desk12 min read

FTC disclosure: This article contains affiliate links. If you purchase through these links, we may earn a commission at no additional cost to you.

Documentation basis: This rewrite is grounded in the Let's Encrypt challenge documentation, the Caddy automatic HTTPS documentation, and the Traefik ACME documentation. The goal is to explain certificate issuance, reverse-proxy placement, and local DNS behavior without implying hands-on testing stories.

HTTPS matters in a homelab because certificate trust and hostname consistency affect both security warnings and day-to-day usability. The practical problem is not just obtaining a certificate once; it is keeping browser trust, external access, and local-path routing aligned after the certificate exists.

A stable setup usually has three moving parts: one reverse proxy that terminates TLS, one challenge path that proves domain control to the certificate authority, and one local DNS override or split-DNS pattern that keeps internal traffic from hairpinning out to the public internet.

This page helps a homelab operator choose that flow deliberately so certificates renew cleanly and local access still feels fast and predictable after HTTPS is enabled.

Why HTTPS matters in a homelab

Before the commands, here is the plain-English version.

HTTPS does three jobs for you:

1. It encrypts the connection so credentials and session cookies are not sent around in the clear.

2. It proves your browser reached the service you intended to reach.

3. It lets modern apps behave normally, because many self-hosted tools assume secure origins for logins, cookies, OAuth redirects, and WebSockets.

Why this matters in a homelab:

  • Browser warnings train you to click through bad security habits.
  • Some apps behave strangely or refuse features when they are behind plain HTTP.
  • If family members use your services, certificate warnings destroy trust immediately.
  • Clean hostnames like jellyfin.example.com are much easier to remember than 192.168.1.50:8096.

If you already read our broader Homelab DNS guide, this is the next layer on top of that foundation. DNS gives things names. TLS makes those names trustworthy.

What you are building

For this beginner path, the architecture looks like this:

  • Public DNS for app.example.com points at your home internet edge
  • Your router forwards ports 80 and 443 to one reverse proxy host
  • Caddy terminates TLS and forwards traffic to the internal app
  • Your internal DNS server overrides app.example.com to the proxy's LAN IP so local devices stay local

That last bullet is the piece many first-timers miss.

Without the internal DNS override, your laptop on Wi-Fi asks public DNS for app.example.com, gets the public answer, exits through your router, and may hairpin back in through the WAN path. That can work, but it is clumsy. With an override, local devices go straight to the proxy on your LAN while still using the exact same hostname.

Before you start

Use these assumptions for the rest of the guide:

  • You own a domain, such as example.com
  • You have one service to publish, such as Jellyfin on 192.168.1.50:8096
  • You have a Linux Docker host for the reverse proxy
  • You run Pi-hole or another local DNS resolver for the home network
  • You are willing to forward only ports 80 and 443 to the reverse proxy host

If you do not already have a local DNS service, set that up first. Pi-hole and AdGuard Home are both fine choices. If you are still deciding between them, our Pi-hole vs AdGuard Home comparison will help you choose the one that fits your network.

> What could go wrong: Do not start with Proxmox, your NAS admin UI, your router, or anything else that controls the rest of the lab. Pick a low-risk service first. Media apps and dashboards are much safer first targets than management planes.

transmission signup

article_topic // Homelab HTTPS Setup

Don't leave without the setup notes.

Get practical homelab guides, failure logs, and beginner-friendly build notes in your inbox.

Enter your email address to receive the Homelab Addiction newsletter.

Weekly only. No spam. Unsubscribe anytime.

Step 1: Pick one safe service and one hostname

Why this matters:

Beginners get in trouble when they try to front five services at once. If you start with one app, you will know whether failures come from DNS, certificates, routing, or the application itself.

For this example, we will publish Jellyfin like this:

  • Service: Jellyfin
  • Internal address: 192.168.1.50:8096
  • Public hostname: jellyfin.example.com
  • Reverse proxy host LAN IP: 192.168.1.20

If your app already runs in Docker on the same host as Caddy, the backend target can be a container name instead of a raw IP.

Step 2: Run Caddy in Docker

Why this matters:

Caddy is the shortest path I know from "I have an app" to "I have working HTTPS." It handles certificate requests and renewals automatically, so you do not need a separate Certbot schedule or hand-built Nginx config just to get your first service online.

Create a working directory:

mkdir -p ~/homelab/caddy\ncd ~/homelab/caddy

Create docker-compose.yml:

services:\n  caddy:\n    image: caddy:2\n    container_name: caddy\n    restart: unless-stopped\n    ports:\n      - "80:80"\n      - "443:443"\n      - "443:443/udp"\n    volumes:\n      - ./Caddyfile:/etc/caddy/Caddyfile\n      - caddy_data:/data\n      - caddy_config:/config\n\nvolumes:\n  caddy_data:\n  caddy_config:

Create Caddyfile:

jellyfin.example.com {\n    reverse_proxy 192.168.1.50:8096\n}

Start Caddy:

docker compose up -d

Check the container:

docker compose ps\ndocker logs caddy --tail 50

Expected behavior:

  • The container should stay up
  • Caddy will wait for traffic and attempt certificate management once the hostname resolves correctly and ports 80/443 reach the proxy

If your backend app is on the same Docker network, you can use a service name instead of an IP:

grafana.example.com {\n    reverse_proxy grafana:3000\n}

That is often cleaner long term because the hostname stays stable even if the container IP changes.

Step 3: Open only the ports you actually need

Why this matters:

This is where HTTPS can either improve your security or quietly make things worse. The reverse proxy should be the front door. Your backend apps should not each get their own public port just because the proxy makes them easier to reach.

If you use UFW on the proxy host, allow only web traffic:

sudo ufw allow 80/tcp\nsudo ufw allow 443/tcp\nsudo ufw status

Then configure your router to forward:

  • TCP 80 -> 192.168.1.20
  • TCP 443 -> 192.168.1.20

That is it.

Do not forward:

  • 8096 for Jellyfin
  • 8006 for Proxmox
  • 5000/5001 for NAS admin
  • random app ports "just in case"

If you want to understand when a public port is justified and when a tunnel or VPN is safer, read Cloudflare Tunnel vs VPN vs Port Forwarding.

Step 4: Create the public DNS record

Why this matters:

TLS certificates depend on names resolving correctly. Before your browser can trust jellyfin.example.com, the ACME process needs a working DNS answer and a reachable path back to the reverse proxy.

In your DNS provider's panel, create an A record:

  • Name: jellyfin
  • Value: your home WAN IP or your dynamic DNS target pattern

Then verify from the shell:

dig +short jellyfin.example.com

You should see the public IP you expect.

If your ISP changes your WAN IP often, use dynamic DNS or a DNS provider API-backed workflow later. For the first pass, a stable manual record is enough to prove the pattern.

> What could go wrong: If dig still shows an old value, do not keep troubleshooting Caddy. Fix DNS first. HTTPS setup always feels mysterious when the real problem is stale DNS.

Step 5: Let Caddy obtain the certificate

Why this matters:

At this point, you have all the ingredients for a valid certificate: a hostname, a reachable proxy, and ports 80/443 mapped correctly. Caddy handles the actual ACME flow for you.

Once DNS and port forwarding are in place, request the site:

curl -I http://jellyfin.example.com\ncurl -I https://jellyfin.example.com

Then watch the logs:

docker logs caddy --tail 100 -f

What you want to see:

  • Caddy provisioning a certificate
  • no endless retry loop for ACME validation
  • successful HTTPS response headers from the app

If you hit certificate failures, check these in order:

1. Public DNS resolves correctly

2. Your router forwards 80/443 to the proxy host

3. Your ISP is not blocking inbound traffic on those ports

4. The hostname in your Caddyfile exactly matches the public DNS record

For background on why HTTP-01 and DNS-01 work differently, the official Let's Encrypt challenge types documentation is worth bookmarking.

Step 6: Add the internal DNS override so local traffic stays local

Why this matters:

This is the step that turns "I got HTTPS working" into "this actually feels good to use every day."

Without internal DNS, local clients may still resolve jellyfin.example.com to your public path. That means extra hops, possible hairpin NAT weirdness, and inconsistent behavior.

If you use Pi-hole, create a local DNS override on the Pi-hole host.

For a dnsmasq-based Pi-hole setup, create a custom file:

echo 'address=/jellyfin.example.com/192.168.1.20' | sudo tee /etc/dnsmasq.d/99-homelab-override.conf\nsudo pihole restartdns

Now test resolution from a client that uses Pi-hole:

nslookup jellyfin.example.com

You want the answer to be 192.168.1.20, which is the proxy's LAN IP.

If you use AdGuard Home instead, create an equivalent DNS rewrite in the UI:

  • Domain: jellyfin.example.com
  • Answer: 192.168.1.20

This is a good point to mention one naming rule that saves headaches: use real public names you control, not .local names. .local often collides with mDNS behavior, which is a polite way of saying it can waste your Saturday.

If your homelab uses multiple internal-only subdomains, you may later want a broader split-horizon pattern or a home.arpa plan. For a first tutorial target, one explicit override is simpler and easier to debug.

Step 7: Test both the local path and the remote path

Why this matters:

A lot of people only test on Wi-Fi, assume everything is done, and then discover remote access is broken later. Others test only remotely and never notice their local clients are still hairpinning out through the WAN path.

Test from inside the LAN:

curl -I https://jellyfin.example.com

Test the DNS answer locally:

nslookup jellyfin.example.com

If you want to force a local test from the shell without waiting on client DNS, use:

curl -I --resolve jellyfin.example.com:443:192.168.1.20 https://jellyfin.example.com

Then test from outside your network:

  • turn off Wi-Fi on your phone
  • browse to https://jellyfin.example.com
  • confirm the certificate is valid and the page loads normally

That local-versus-remote pair is the whole goal. Same hostname. Same certificate. Different network path depending on where you are.

From the lab

Step 8: Harden the setup before you add more apps

Why this matters:

HTTPS is not the same thing as safe exposure. A reverse proxy is like the lobby in an apartment building. It can make entry cleaner and more controlled, but it does not mean every room should have a door directly onto the street.

Before you add the next service:

1. Keep admin apps private.

- Proxmox, NAS admin, router UI, and backup dashboards should stay LAN-only or VPN-only.

2. Harden host access.

- If you have not locked down SSH yet, follow our SSH hardening guide.

3. Add identity protection for public services.

- For family-facing apps that need internet access, an auth layer matters. Our Authelia SSO guide is a good next step.

4. Keep backups boring and regular.

- Your proxy config, DNS overrides, and app data should all be backed up. If the reverse proxy host dies, recovery should be routine, not archaeology.

5. Add more services one at a time.

- Reuse the same pattern: new hostname, new reverse proxy entry, new internal DNS override if needed.

When Nginx Proxy Manager makes more sense

Caddy is a strong command-first option because the configuration stays short and automatic HTTPS is built in. Nginx Proxy Manager is a reasonable alternative when a GUI-first workflow fits better.

Use Nginx Proxy Manager when:

  • you prefer forms over config files
  • you want certificate management from the browser
  • you are helping family members or teammates who will maintain it later

Use Caddy when:

  • you want fewer moving parts
  • you like versioning configs in files
  • you want the easiest path to repeatable setups

Neither choice is morally superior. Pick the one you will actually maintain.

Common Mistakes

1. Exposing the app port and the proxy

This defeats the point of centralizing traffic. Publish the proxy, not the backend.

2. Testing only on your home Wi-Fi

You need one local test and one cellular or remote test.

3. Forgetting the internal DNS override

This is the classic "HTTPS works, but local performance still feels weird" mistake.

4. Using .local hostnames for everything

That often collides with mDNS and creates confusing name-resolution behavior.

5. Putting Caddy on a different Docker network from the backend

If Caddy cannot reach the app, cert issuance may succeed while the service still fails at runtime.

6. Starting with Proxmox or your NAS admin panel

Start with a low-risk service. Public exposure is a privilege, not a default setting.

7. Treating HTTPS as the whole security plan

TLS protects the connection. It does not replace updates, auth, backups, segmentation, or sane exposure decisions.

What to learn next

Once this first service works cleanly, the next good topics to learn are:

  • split-horizon DNS patterns for multiple services
  • wildcard certificates with DNS challenge for internal-only apps
  • SSO in front of public services
  • network segmentation so your proxy can reach only what it needs
  • better service inventory and backup discipline

If you want a smooth progression, use this order:

1. DNS fundamentals - Homelab DNS: 9 Rules

2. reverse proxy GUI alternative - Nginx Proxy Manager on Docker

3. edge security - SSH Hardening Guide

4. identity layer - Authelia SSO for your homelab

Frequently Asked Questions

Can I use HTTPS for a homelab service that stays on my local network?

Yes. The simplest beginner path is to use a real hostname you control, terminate TLS at a reverse proxy like Caddy, and point local DNS at the proxy's LAN IP. That gives you a valid certificate and keeps local traffic on the LAN.

Do I need a reverse proxy for homelab SSL/TLS?

Usually, yes. A reverse proxy centralizes certificates, gives you clean hostnames, and keeps individual app ports off the public internet. You can run certificates per app, but it gets messy quickly.

What is split-horizon DNS in a homelab?

Split-horizon DNS means local clients get an internal answer for a hostname while external clients get the public answer. It lets the same URL work both at home and away from home without changing bookmarks.

Should I use Caddy or Nginx Proxy Manager for my first homelab HTTPS setup?

Use Caddy if you want the simplest file-based setup. Use Nginx Proxy Manager if you prefer a web UI. Both are good choices. The right answer is the one you will keep updated and understand six months from now.

If you have been avoiding HTTPS in your homelab because every guide seemed to assume you were ready to become your own certificate authority, I hope this one felt more grounded. Start with one service, get the pattern working cleanly, and then expand. Once the first hostname works both locally and remotely, the rest of the setup stops feeling like magic and starts feeling like a system you actually understand.

transmission signupstatus: open channel

article_topic // Homelab HTTPS Setup

Start building a smarter homelab.

Join readers learning Proxmox, networking, storage, backups, and self-hosting without breaking everything.

Enter your email address to receive the Homelab Addiction newsletter.

Beginner-friendly

No gatekeeping. Just clear, actionable guides.

1 useful email / week

Practical tips, real-world setups, and lessons learned.

Zero hype, practical only

What works, what breaks, and how to fix it.

Reply to any email with what you're building.
I read and reply to as many as I can.

— The Homelab Addiction Operator

support // the lab

Found this guide useful?

If it saved you time or a rebuild, you can support more practical homelab guides.

Support the lab