Why can Nginx Proxy Manager apply SSL to local network addresses?

The short answer is: because SSL certificates are issued based on a domain name, not a network location. The certificate authority (like Let’s Encrypt) only cares that you prove you control the domain, which is done via a public DNS record.

Here’s a detailed breakdown of why and how this works:

1. The Core Principle: Domain Name vs. IP Address

SSL/TLS certificates are bound to domain names (e.g., myhomeserver.example.com), not to public or private IP addresses (e.g., 192.168.1.100). A Certificate Authority (CA) like Let’s Encrypt issues a certificate for a domain after verifying you own it. It doesn’t matter if that domain name resolves to a public IP (203.0.113.10) or a private one (192.168.1.100).

2. The Validation Method: How NPM “Proves” Ownership

To get a certificate, NPM must prove to the CA that it controls the domain. It does this using one of the ACME protocol challenges. For internal networks, the DNS-01 challenge is the most common and reliable method:

  • How it works: The CA gives NPM a unique token. NPM instructs you (or an automated API script) to create a specific TXT record in your domain’s DNS zone (e.g., _acme-challenge.myhomeserver.example.com. IN TXT "gfj8X7...").
  • Why it works for local networks: The CA checks the DNS record from the public internet. This validation happens entirely in DNS, completely independent of your internal network’s IP scheme. Once validated, the certificate is issued.

3. How Your Devices Trust the Certificate

Once NPM has the certificate, it presents it to any client (web browser, app) that connects to it.

  • The client checks if the domain name in the URL matches the domain name in the certificate.
  • The client then checks if the certificate is signed by a trusted CA (like Let’s Encrypt).
  • Since Let’s Encrypt is trusted by virtually all operating systems and browsers, the connection is secured with a green padlock, even though the traffic is only going to your local router.

The Practical Setup: A Typical Example

Let’s say you have a server at 192.168.1.100. Here’s how you set it up:

  1. Buy a Domain: You own a domain (e.g., example.com).
  2. Create a DNS Record: In your domain’s DNS settings (at your registrar like Cloudflare or Namecheap), you create an A record pointing your chosen subdomain to your home’s public IP address.
    • Record Type: A
    • Name: myserver (or home, nas, etc.)
    • Value: Your.Public.IP.Address
  3. Port Forwarding: On your home router, you forward ports 80 (HTTP) and 443 (HTTPS) to the internal IP of your Nginx Proxy Manager server (192.168.1.100).
  4. Configure NPM:
    • Add a Proxy Host in NPM.
    • Domain Names: myserver.example.com
    • Scheme: http
    • Forward IP/ Hostname: 192.168.1.50 (the actual IP of your internal service, like WordPress or Jellyfin).
  5. Request SSL Certificate:
    • In the SSL tab for that proxy host, request a new certificate.
    • Use the DNS Challenge and provide your DNS provider’s API credentials. NPM will automatically create and delete the required TXT record to prove ownership.
    • Enable “Force SSL” and “HTTP/2”.

What Happens When You Visit?

  • From Outside Your Network: You go to https://myserver.example.com. Your DNS resolves this to your public IP. Your router forwards the HTTPS request to NPM on 192.168.1.100. NPM presents the valid certificate for myserver.example.com and proxies the request to your internal service.
  • From Inside Your Network: The process is exactly the same! Your device makes a DNS request for myserver.example.com, which resolves to your public IP. Your router sees that the traffic is going to its own public IP (a loopback) and handles it internally, sending the request back to itself and then to NPM. This is called NAT Loopback or Hairpin NAT. NPM again presents the valid certificate.

Important Considerations

  • NAT Loopback Requirement: For this to work seamlessly from inside your network, your router must support NAT Loopback. Most modern consumer routers do, but some don’t. If yours doesn’t, you can work around it by configuring local DNS on your network (e.g., using Pi-hole) to resolve myserver.example.com directly to NPM’s local IP (192.168.1.100), bypassing the public IP entirely.
  • Security: You are exposing a entry point to your internal network. It is critical to:
    • Keep NPM and your services updated.
    • Use strong passwords.
    • Consider adding additional authentication layers (like the built-in Access Lists in NPM) for sensitive services.

In summary, NPM applies SSL from the local network because the trust is established by a public DNS record and a certificate from a globally trusted authority, not by the network path the request takes.

Leave a Reply