Local Domains with SSL: Nginx Proxy Manager in the Home Network
No more red browser warnings for internal services.
Why the DNS challenge?
Normally, Let's Encrypt verifies your domain ownership by attempting to reach your website via Port 80 from the internet (HTTP challenge). However, for purely internal services, we naturally **don't** want to open any ports in our router firewall!
The solution is called **DNS-Challenge**. Here, the Nginx Proxy Manager communicates via an API with your domain provider (e.g., Cloudflare) and temporarily stores a TXT record there. Let's Encrypt checks this record and issues the certificate. The local services remain securely hidden behind the firewall.
1. Requirements
- A running Docker setup (e.g., on a Raspberry Pi or Intel NUC).
- A custom domain (e.g., `mydomain.de`) whose nameservers are with a supported provider like Cloudflare.
- A router (e.g., OpenWrt, GL.iNet, FritzBox) or local DNS server where host entries can be customized.
2. Install Nginx Proxy Manager
We easily start NPM via docker-compose. Create a docker-compose.yml file with the following content and start it with docker-compose up -d:
version: '3.8'
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '80:80'
- '81:81'
- '443:443'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
3. Set local DNS entry (Split-Brain DNS)
To prevent requests to `nextcloud.meinedomain.de` from failing or routing to the actual web server, you must instruct your local router/DNS where to send them. All internal traffic must be redirected to the IP of your Nginx Proxy Manager.
**OpenWrt Example (e.g., GL.iNet Router):**
Log in to your router via SSH (or via Luci -> Network -> Hostnames). Simply add your services and the local NPM IP to the /etc/hosts file:
# /etc/hosts
192.168.8.50 nextcloud.meinedomain.de
192.168.8.50 homeassistant.meinedomain.de
After that, briefly restart the dnsmasq service (/etc/init.d/dnsmasq restart). Now the router forwards requests from your laptops and mobile phones to the internal NPM.
4. Request wildcard certificate
Log in to the admin interface. Go to **SSL Certificates** -> **Add SSL Certificate** -> **Let's Encrypt**.http://
- Enter `*.meinedomain.de` and `meinedomain.de` for Domain Names.
- Enable **Use a DNS Challenge**.
- Choose your DNS provider (e.g., Cloudflare).
- Enter your API token into the configuration field.
- Agree to the ToS and click Save.
NPM now automatically obtains the certificate. This takes approximately 30-60 seconds.
5. Create Proxy Host
Now all you have to do is link your services! Go to **Hosts** -> **Proxy Hosts** -> **Add Proxy Host**.
**Details Tab:**
Domain Names: `nextcloud.meinedomain.de`
Scheme: `http` or `https`
Forward Hostname / IP: The local IP of your actual service (e.g. `192.168.8.60`)
Forward Port: The port of your service (e.g. `8080`)
**SSL Tab:**
Select your newly created certificate from the dropdown menu. Enable "Force SSL" and "Websockets Support" (the latter is especially important for Home Assistant!). Click Save.
Done! If you now visit https://nextcloud.meinedomain.de in your browser, the longed-for green lock icon will appear.
Special case Home Assistant (400: Bad Request)
If you try to access Home Assistant via the Nginx Proxy Manager, you will very likely be greeted by a 400: Bad Request error. For security reasons, Home Assistant blocks all requests from reverse proxies it doesn't explicitly know.
To fix this, you need to add the IP address of your Nginx Proxy Manager as a "Trusted Proxy" in Home Assistant's configuration.yaml:
http:
use_x_forwarded_for: true
trusted_proxies:
- 192.168.8.50 # <-- IP of your NPM server
Save the file and fully restart Home Assistant. After that, the error will be gone and your smart home hub will be accessible via your green HTTPS domain!