How to Use Nginx Proxy Manager + Pi-hole for HTTPS Internal Services Behind an ISP Modem#

If you’re stuck with the awful modem/router your ISP gave you and thought that meant you were doomed to ugly local IPs, weird ports, and browser certificate warnings forever… good news: you are absolutely not stuck.

You can use Nginx Proxy Manager Pi-hole HTTPS internal services with a totally basic ISP router and still get clean, real HTTPS URLs like:

  • proxmox.home.example.com
  • grafana.home.example.com
  • jellyfin.home.example.com

…with valid Let’s Encrypt certificates.

And the best part?
You do not need:

  • an enterprise firewall
  • manual DNS entries on the ISP router
  • inbound port forwarding for cert validation
  • hairpin NAT to magically work
  • a “real” router before you’re allowed to build a clean homelab

Honestly, this is one of those setups that sounds like it should be way more complicated than it actually is.


The Problem Everyone Assumes Requires Better Hardware#

A lot of people hit the same wall:

  • You want clean URLs for your homelab
  • You want real HTTPS
  • You want browser warnings gone
  • You want your services to feel finished instead of “temporary lab chaos”

Then reality shows up:

  • Your ISP modem/router is locked down
  • It doesn’t support manual local DNS entries
  • Maybe it barely supports DHCP settings
  • Maybe you’re behind double NAT
  • Maybe NAT loopback/hairpin NAT is flaky or nonexistent

So most people assume:

“Cool. Guess I need a better router before I can do this properly.”

Nope.

That assumption is wrong.


The Fast Payoff: The Simple Version#

Here’s the simple version before we go deep:

You can absolutely run Nginx Proxy Manager behind an ISP modem/router and still get valid HTTPS for internal services by combining four things:

  1. A real domain (or subdomain)
  2. Let’s Encrypt DNS-01 validation (not HTTP-01)
  3. Pi-hole for internal DNS / split DNS
  4. Nginx Proxy Manager as your reverse proxy

That’s it.

The flow looks like this:#

  • Public DNS is only used so Let’s Encrypt can verify domain ownership with a TXT record (_acme-challenge)
  • Pi-hole local DNS makes your internal service hostnames resolve to the local IP of Nginx Proxy Manager
  • Nginx Proxy Manager receives the request and routes it to the correct internal service

So instead of this:

  • https://192.168.1.20:8006
  • http://192.168.1.30:3000
  • http://192.168.1.40:8096

You get this:

  • https://proxmox.home.example.com
  • https://grafana.home.example.com
  • https://jellyfin.home.example.com

Clean. Valid. No browser tantrums.


Why Normal Let’s Encrypt Setups Fail Behind ISP Modems or Double NAT#

This is where a lot of people get burned.

Most beginner reverse proxy guides assume you’re using the HTTP-01 challenge for Let’s Encrypt.

That means Let’s Encrypt wants to reach your server over the internet on port 80 (sometimes with redirects to 443 depending on setup) and verify a token over inbound HTTP.

That’s fine if:

  • your ports are forwarded correctly
  • you’re not behind weird ISP restrictions
  • your router isn’t locked down
  • you’re not dealing with double NAT
  • you actually want to expose that path publicly

But if you’re running behind a basic ISP modem/router, this is where it gets messy fast.

Why it breaks:#

  • You may not be able to forward ports cleanly
  • You may be behind carrier weirdness or double NAT
  • You may not want to expose internal services at all
  • Hairpin NAT might fail if you try to resolve public DNS back into your LAN
  • Some ISP gear is… let’s be polite… aggressively unhelpful

So if you try to copy a “normal” reverse proxy tutorial, it can feel like the whole idea is impossible.

It’s not impossible.
You’re just using the wrong challenge type.


Why DNS-01 Changes Everything#

This is the key.

If you remember one thing from this entire post, remember this:

DNS-01 is what makes this work.

With the DNS-01 challenge, Let’s Encrypt does not need inbound access to your homelab.

It does not need port forwarding.

It does not need your ISP router to behave.

Instead, Let’s Encrypt validates ownership by checking for a public DNS TXT record that looks like this:

  • _acme-challenge.home.example.com

So the validation happens in public DNS, not by hitting your server over the internet.

That means:

  • No HTTP validation endpoint needed
  • No port 80 requirement for cert issuance
  • No dependence on your ISP modem’s firewall rules
  • No need to expose Proxmox, Grafana, Jellyfin, or anything else just to get a cert

This is the aha moment#

The certificate is validated through public DNS, but the service itself can stay completely internal.

That’s the whole trick.

That’s why this works even when your ISP router is mediocre.


Public DNS vs Internal DNS (This Needs to Be Crystal Clear)#

This is where people get confused, so let’s make it stupidly simple.

You have two totally different DNS jobs happening here.


Public DNS = Only for Certificate Validation#

Your public DNS provider (Cloudflare is the easiest for most people) is used for one main purpose in this setup:

  • proving to Let’s Encrypt that you control the domain

That happens by creating a TXT record for the DNS-01 challenge.

Example:

  • _acme-challenge.home.example.com → temporary TXT record created during validation

This does not mean your internal services need to be publicly reachable.

It does not mean proxmox.home.example.com needs to point to your home IP.

It does not mean you need to publish your homelab to the internet.

For internal-only services, the public DNS role is basically:

“Yes, I own this domain. Please issue the certificate.”

That’s it.


Internal DNS = How Your Devices Find the Reverse Proxy#

Now we switch to the LAN side.

Inside your house, your devices need to know where:

  • proxmox.home.example.com
  • grafana.home.example.com
  • jellyfin.home.example.com

…should actually go.

That is Pi-hole local DNS.

Pi-hole acts as your internal resolver and says:

  • proxmox.home.example.com192.168.1.10
  • grafana.home.example.com192.168.1.10
  • jellyfin.home.example.com192.168.1.10

Where 192.168.1.10 is the internal IP of Nginx Proxy Manager.

Important:#

All service hostnames should resolve to the Nginx Proxy Manager IP.
Not directly to each app.

That part matters a lot.

Because the reverse proxy is the front door.


Why Pi-hole Is the Missing Piece#

If your ISP router doesn’t support local DNS overrides (and a lot of them don’t), Pi-hole becomes the missing piece that makes the whole thing feel “real.”

Pi-hole is not just an ad blocker here.

In this setup, it’s doing something arguably even more valuable:

  • Split DNS / local DNS for your homelab

That means your LAN devices resolve internal service names differently than the public internet would.

Example:#

Inside your network:

  • proxmox.home.example.com192.168.1.10 (NPM)
  • grafana.home.example.com192.168.1.10 (NPM)
  • jellyfin.home.example.com192.168.1.10 (NPM)

Externally:

  • Those records can be nonexistent
  • Or only exist where needed
  • Or be handled differently if you later expose selected apps

That’s the clean split.

And it means your internal traffic never has to leave the LAN just to come back in again.


Why This Avoids Hairpin NAT / NAT Loopback Problems#

Cheap ISP routers love to make this annoying.

If you rely on public DNS pointing to your home’s public IP, and then try to access that service from inside your own network, you’re depending on hairpin NAT (also called NAT loopback).

Some routers handle it.

Some handle it badly.

Some don’t handle it at all.

Some act like they do until they don’t.

That’s why people end up with weird behavior like:

  • works on cellular, fails on Wi-Fi
  • works externally, fails internally
  • cert is fine, but the app won’t load at home
  • random redirect loops
  • “why is this only broken on my laptop?”

With Pi-hole local DNS, you bypass that nonsense completely.

Instead of:

  • proxmox.home.example.com → public IP → router loopback magic → maybe works

You do:

  • proxmox.home.example.comNginx Proxy Manager internal IP → works normally on LAN

That’s cleaner, faster, and way less dependent on whether your ISP hardware deserves rights.

Don’t make your LAN traffic leave the house just to come back in through a confused modem.


How Nginx Proxy Manager Ties It All Together#

Once DNS is doing the right thing, Nginx Proxy Manager (NPM) becomes the clean front-end for all your internal services.

Every friendly hostname points to NPM.

Then NPM decides where to send it.

Example architecture#

Let’s say your domain is:

  • home.example.com

You issue a wildcard certificate:

  • *.home.example.com

Then in Pi-hole local DNS, you create:

  • proxmox.home.example.com192.168.1.10
  • grafana.home.example.com192.168.1.10
  • jellyfin.home.example.com192.168.1.10

Where:

  • 192.168.1.10 = Nginx Proxy Manager

Then in Nginx Proxy Manager, you create proxy hosts:

NPM routes#

  • proxmox.home.example.com192.168.1.20:8006
  • grafana.home.example.com192.168.1.30:3000
  • jellyfin.home.example.com192.168.1.40:8096

Now the request flow is:

  1. Your laptop asks for https://grafana.home.example.com
  2. Pi-hole resolves it to 192.168.1.10
  3. The request hits Nginx Proxy Manager
  4. NPM presents the valid TLS certificate
  5. NPM proxies the request to 192.168.1.30:3000

That’s the pattern.

Repeat it for basically every internal service you care about.


Real-World Example Homelab Layout#

Here’s what this looks like in a normal, practical home lab.

Core stack#

  • ISP modem/router (basic, locked down, annoying)
  • Pi-hole for local DNS (and maybe DHCP)
  • Nginx Proxy Manager running in Docker or a VM/LXC
  • Cloudflare DNS for public DNS management + DNS-01 support
  • Proxmox hosting the rest of the stack

Example services#

  • proxmox.home.example.com
  • grafana.home.example.com
  • homeassistant.home.example.com
  • jellyfin.home.example.com
  • nextcloud.home.example.com
  • portainer.home.example.com

Internal DNS (Pi-hole)#

  • proxmox.home.example.com192.168.1.10
  • grafana.home.example.com192.168.1.10
  • homeassistant.home.example.com192.168.1.10
  • jellyfin.home.example.com192.168.1.10
  • nextcloud.home.example.com192.168.1.10
  • portainer.home.example.com192.168.1.10

Reverse proxy routes (NPM)#

  • proxmox.home.example.com192.168.1.20:8006
  • grafana.home.example.com192.168.1.30:3000
  • homeassistant.home.example.com192.168.1.50:8123
  • jellyfin.home.example.com192.168.1.40:8096
  • nextcloud.home.example.com192.168.1.60:443
  • portainer.home.example.com192.168.1.70:9443

This is such a solid setup for a Proxmox-heavy homelab because it makes everything feel consistent.

And once you do it once, adding new services becomes easy.


Why Cloudflare Is Usually the Easiest Choice for DNS-01#

If you’re choosing a DNS provider for this setup, Cloudflare is usually the easiest path.

Why?

  • Easy DNS management
  • Commonly supported by automation tools
  • Works well with DNS API-based validation
  • Widely documented
  • Great for homelabbers who want the least friction possible

For Nginx Proxy Manager Cloudflare DNS workflows, the big win is simple:

  • NPM can use DNS challenge automation (depending on your deployment/plugins/workflow)
  • Or you can handle cert issuance via a companion method and import into NPM
  • Either way, Cloudflare tends to be the path of least resistance

If you’re new to this, reducing moving parts matters.


Wildcard Certificates Are Convenient… But They’re Broad#

A wildcard cert like:

  • *.home.example.com

…is super convenient.

It means one certificate can cover:

  • proxmox.home.example.com
  • grafana.home.example.com
  • jellyfin.home.example.com
  • nextcloud.home.example.com

That’s great for internal homelabs.

But it’s worth saying out loud:

Wildcards are broad in scope#

If that private key is compromised, it covers a lot of internal hostnames.

So yes, wildcard certs are convenient.
Also yes, they deserve basic respect.

Practical take:#

  • Store certs securely
  • Keep NPM updated
  • Don’t scatter cert material everywhere
  • Consider whether some services should use individual certs instead

For most home labs, wildcard is fine.
Just don’t treat “home lab” as a synonym for “security doesn’t matter.”


DHCP / DNS Gotchas If Your ISP Router Is Stubborn#

This is the one place where the ISP gear can still be annoying.

For Pi-hole local DNS to work consistently, your clients actually need to use Pi-hole as DNS.

If your ISP router lets you hand out custom DNS via DHCP, great.

If it doesn’t, here are the realistic workarounds.

Best option: Disable ISP DHCP and let Pi-hole handle DHCP#

If your ISP modem/router allows you to disable DHCP:

  • turn off DHCP on the ISP box
  • enable DHCP on Pi-hole
  • let Pi-hole hand out:
    • IP addresses
    • gateway
    • DNS (itself)

This is usually the cleanest workaround.

Good option: Manually point important clients at Pi-hole#

If you can’t change DHCP cleanly:

  • desktops
  • laptops
  • media devices
  • phones/tablets you care about
  • admin workstations

…can all be pointed at Pi-hole manually.

Not perfect, but it works.

Long-term option: Add a real downstream router/firewall later#

Eventually, sure:

  • OPNsense
  • pfSense
  • OpenWrt
  • UniFi gateway
  • your favorite box of nerd happiness

That gives you better control.

But the whole point of this post is:

You do not need that on day one to get clean HTTPS for internal services.


Proxmox Note: Keep It Internal-Only#

Since this comes up a lot:

Proxmox should generally stay internal-only.

Yes, giving Proxmox a clean URL like:

  • https://proxmox.home.example.com

…is fantastic.

Yes, it’s nicer than https://192.168.1.20:8006

But that does not mean it should be publicly exposed.

Best practice for Proxmox in a home lab:

  • access it over LAN
  • or access it over VPN
  • keep it behind your internal reverse proxy if you want the nice URL
  • do not casually publish it to the public internet because you got excited about certificates

Clean URL ≠ public exposure.

That distinction matters.


The Mental Model That Makes This Click#

If you’re still mentally untangling this, here’s the model:

Public DNS answers:#

“Do you own this domain?”

That’s for Let’s Encrypt DNS-01.

Pi-hole answers:#

“Where should devices on my LAN send this hostname?”

That’s your internal split DNS.

Nginx Proxy Manager answers:#

“Which actual app should get this request?”

That’s your reverse proxy routing.

Once you separate those three jobs, the whole setup suddenly stops feeling mysterious.

And honestly, that’s the part most tutorials do a bad job explaining.


Pull-Quote-Worthy Truths#

Here are the truths I wish more people heard sooner:

You don’t need enterprise gear to build a clean HTTPS homelab.

DNS-01 validates domain ownership through DNS—not by reaching into your network.

Pi-hole isn’t just for ad blocking. It’s the missing piece for split DNS in a home lab.

Every internal hostname should point to the reverse proxy, not directly to the app.

Stop depending on hairpin NAT when local DNS solves the problem cleanly.


What This Setup Is Perfect For#

This pattern is especially good for:

  • Proxmox homelabs
  • Self-hosted dashboards
  • Grafana
  • Home Assistant
  • Jellyfin
  • Nextcloud
  • Portainer
  • Internal admin panels
  • Services you want clean access to but do NOT want publicly exposed

It’s a clean, practical middle ground between:

  • “everything is raw IPs and weird ports”
  • and
  • “I guess I need to rebuild my entire network before I can do this properly”

No. You don’t.


Final Thoughts: This Is the Clean Workaround for People Stuck With ISP Gear#

If there’s one thing I want people to take away from this, it’s this:

Your ISP router is annoying, but it is not a hard blocker.

You can still build a genuinely clean setup.

You can still run Nginx Proxy Manager Pi-hole HTTPS internal services without a fancy firewall.

You can still get:

  • real URLs
  • valid certificates
  • clean reverse proxy routing
  • no browser warnings
  • no dependence on hairpin NAT
  • no need for manual DNS entries on the ISP modem

The winning combo is simple:

  • real domain
  • Let’s Encrypt DNS-01
  • Pi-hole local DNS / split DNS
  • Nginx Proxy Manager as the internal front door

That’s it.

And honestly? For a lot of home labs, that’s more than enough.

You do not need enterprise gear to make your self-hosted stack feel polished.

You just need the right pieces in the right places.


Want the Step-by-Step Version?#

If you want, I can do a full follow-up walkthrough next with the exact implementation:

  • setting up the domain/subdomain
  • Cloudflare DNS setup
  • Let’s Encrypt DNS-01 in Nginx Proxy Manager
  • Pi-hole local DNS records
  • proxy host configs for Proxmox, Grafana, Jellyfin, and Home Assistant
  • the common mistakes that cause redirect loops or broken certs