Easily Encrypt your Home Network services with Lets Encrypt (for free)
Following a recent post on how I use Tailscale and NextDNS to manage my home network
I had an interesting conversation on Reddit about managing certificates on various servers and providing a method for putting services I've got running like Teleport, Plex and Graylog under nice https:// protected URLs with the certificates managed centrally and pulled down from LetsEncrypt
💡 I also had an additional need that I have no ports open from the internet to my home. So there was no method to do the standard LetsEncrypt checks.
This is how I set this all up.
Services Used
Cloudflare - External DNS
NextDNS - Internal/Home DNS server
Nginx Proxy Manager - Running on an Ubuntu (Linux) server on your Homelan/Tailscale Network
Tailscale - Providing IPs for Internal/Home Network
Diagram
The How
There is a lot of back and forward while setting this up initially, however once setup the only interface you should need to use it the Nginx Proxy Manager
💡 DNS changes can take time and some parts of this if you are moving nameservers to Cloudflare for example can take up to 24hrs.
Setup Cloudflare Free Account
Create a new account if you don't already have one at https://cloudflare.com
This won't cost anything.
Login when done.
Point existing DNS to Cloudflare
💡 The DNS names I want to use for this are currently registered with hover.com.
I want to use davidfield.co.uk as my domain for my internal services to use. This is currently registered with hover.com. The first step is to let Cloudflare take control of the domain
💡 If you have public-facing services like www.davidfield.co.uk accessible from the internet, you may find access is lost for a maximum of 24hrs (but realistically an hour) while the nameservers transfer to Cloudflare.
You may also see the Browser complain of certificate errors, this will pass shortly.
From the Cloudflare dashboard Click on Add site then enter the name of the site you'd like to move to Cloudflare under Enter your site.
Click on Add site and you'll be taken to the payment page, depending on your screensize and setup you might be greeted by something like this and ask "you said this was free"
It is, scroll down
Click on Free and Click on Continue
You'll be taken to a review of the DNS Records page
Scroll down the page and check the details listed match those on your existing DNS provider.
Click on Continue when you are happy
💡 I didn't change the proxy status as we won't be using the traditional method of checking LetsEncrypt validity later
You'll be displayed dome information relating to the migration of Nameservers
Scroll down the page
You'll be displayed a set of information on how to change the nameserver on your existing DNS Providers site
In my case, I hopped over to hover.com and applied the new Nameserver information
to
So the new Nameservers are listed in hover.com
Head back over to Cloudflare
Click on Done, check nameservers
You'll be taken (quite unexpectedly considering the previous button) to a Quick Start Guide
Click on Get started
You'll be asked if you want to enable
Automatic HTTPS Rewrites
Always Use HTTPS
Brotli - Speeds up pageloads
I enabled and saved each of these
Click on Finish
You'll be taken back to Complete your nameserver setup
Click on Check Nameservers
A message will dsiplayed
I did also within this process get a mail from Cloudflare
Heading back to the Overview page this was displayed
At this point, Cloudflare thinks it's doing its thing and you're all setup
💡 If you run the command "dig NS davidfield.co.uk" you may see that your local DNS provider is still stating the address is pointing to the old name servers.
This is OK, it will take a while for the rest of the internet to catch up. about 24hrs.
This stage is complete
Install Nginx Proxy Manager
While the internet is catching up with Cloudflare, the next step is to install Nginx Proxy Manager
To proceed with the following steps you'll need an Ubuntu 22.04 server with 2Gb Ram, 1 vCPU and a 50Gb HDD as a minimum spec.
💡 I'm running mine as a Virtual server on Proxmox
Install Docker-CE on the server, the instructions to do this are out of the scope of this post. However these work. It takes about 5 minutes.
💡 Install Tailscale to make the Ubuntu server part of the Tailnet. This is needed later on when the Internal DNS is setup
Once Docker is installed and running, head over to the Nginx Proxy manager site
On the getting started page the instructions are listed as follows, these are the basic install instructions and make use of a local SQLite database.
Create a docker-compose.yml file similar to this:
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
This is the bare minimum configuration required. See the documentation for more.
Bring up your stack by running
docker-compose up -d
# If using docker-compose-plugin
docker compose up -d
Log in to the Admin UI
When your docker container is running, connect to it on port 81
for the admin interface. Sometimes this can take a little bit because of the entropy of keys.
Default Admin User:
Email: admin@example.com
Password: changeme
Immediately after logging in with this default user you will be asked to modify your details and change your password.
The Nginx PRoxy manager also works with MySQL so if you have a MySQL database setup already on your infrastructure
You will need to do the following
Make sure you can access the MySQL server from your docker server (public access)
Create a database called npm
Create a user called npm which can be accessed globally (%) with a secure password
Grant the user privileges to the npm database
💡 I noted when I first created the user, the Docker container was unable to connect to the user, I had to explicitly use "mysql_native_password "
CREATE USER 'npm'@'%' IDENTIFIED WITH mysql_native_password BY 'SuperSecretPassword';
Create a docker-compose.yaml which looks like this
version: '3.8'
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
# These ports are in format <host-port>:<container-port>
- '80:80' # Public HTTP Port
- '443:443' # Public HTTPS Port
- '81:81' # Admin Web Port
# Add any other Stream port you want to expose
# - '21:21' # FTP
environment:
# Mysql/Maria connection parameters:
DB_MYSQL_HOST: "<address of your SQL server>"
DB_MYSQL_PORT: 3306
DB_MYSQL_USER: "npm"
DB_MYSQL_PASSWORD: "SuperSecretPassword"
DB_MYSQL_NAME: "npm"
# Uncomment this if IPv6 is not enabled on your host
# DISABLE_IPV6: 'true'
volumes:
- ./opt/docker/npm/data:/data
- ./opt/docker/npm/letsencrypt:/etc/letsencrypt
💡 Make sure ports 80, 443 and 81 (all TCP) are free on the docker server, use "ss -plnt" to check. If the ports are not free maybe use 8080:80 for example.
Bring up your stack by running
Log in to the Admin UI
docker-compose up -d
# If using docker-compose-plugin
docker compose up -d
When your docker container is running, connect to it on port 81
for the admin interface. Sometimes this can take a little bit because of the entropy of keys.
http://<tailscale IP address>:81
Default Admin User:
Email: admin@example.com
Password: changeme
Immediately after logging in with this default user you will be asked to modify your details and change your password.
Once Logged in, this step is complete.
Create an API Token on Cloudflare
We will use a DNS Challenge to setup the Certificate in Nginx Proxy Manager, to do this we need to grab an API key from Cloudflare which allows us to bypass the usual checks LetsEncrypt does on public open ports.
Login to Cloudflare
Head to the Overview page for the Domain setup earlier
Scroll down the page, on the right you should see the API section
Click on Get your API token.
Click on Create Token
Here templates can be used to create an API, Click on Use Template next to Edit zone DNS.
Under Create Token make sure permissions are set to DNS and Edit and Zone Resources are set to All Zones.
Click on Continue to summary
You'll be provided with a basic summary, click on Create Token.
💡 DO NOT SHARE THESE TOKENS
Take a copy of the API token, and save it in your password safe, we will use it to create the wild card certificate
Close the page
Create a Wildcard Certificate in Nginx Proxy Manager
Next, we will create the Wildcard certificate for the domain migrated to Cloudflare using the API token we just created
Log back into your Nginx Proxy Manager server and Open SSL Certificates at the top
Click on Add SSL Certificate and choose LetsEncrypt as the Certificate Type
There is a lot going on on the next screen
Domain Name: Enter the wildcard for the domain name setup in Cloudflare using the *.<domainname> format.
Email Address: Enter a working email address LetsEncrypt can contact you on.
Use a DNS challenge: Select this to use it
DNS Provider: Select Cloudflare from the list of DNS providers
Credentials File Content: Edit whats in this field under Cloudflare API token and put the Cloudflare API Token generated in the last step
dns_cloudflare_api_token = 0123456789abcdef0123456789abcdef01234567
to
dns_cloudflare_api_token = <your Cloudflare API token>
Propagation Seconds: Leave Blank
I Agree: Select to agree
Click on Save
After a couple of minutes, a wildcard certificate should be generated
💡 I just blanked the name it's actually this website.
Setup a Proxy Host in Nginx Proxy Manager
Having set up the Certificate on the Nginx Proxy server the next step is to create a proxy entry to the internal server.
In this example I have a knowledge base
Running on http://faq.net:9080/ internally which I'd like to run as https
Within Nginx Proxy Manager go to Hosts -> Proxy Hosts.
Click on Add Proxy Host
Add the Domain Name and complete the Forward Hostname/IP and Forward Port then click on the SSL tab
Select the wildcard certificate generated earlier under SSL Certificate.
Click on Save
The new host will now be listed in the proxy host list.
Point a DNS Entry on NextDNS to Nginx Proxy Manager
For the final stage, the internal DNS server will need to point faq.davidfield.co.uk to the Tailscale IP Address of the Nginx Proxy Manager Server.
💡 I'm using nextdns.io as my internal LAN's DNS server. This is connected to my Tailscale account as the Global Nameserver for my Tailnet.
Any device which is connected to Tailscale is able to reference this DNS Server.
Login to the NextDNS account at https://my.nextdns.io and open Settings.
💡 Accounts are Free
Scroll down the page to the rewrites section.
Click on New Rewrite.
Add the DNS name the forward host on Nginx Proxy Manager was created for and the Tailscale IP Address of the Nginx Proxy Manager Server.
Test
Changes on rewrites are almost immediate and we are able to open
https://faq.davidfield.co.uk
My non internet facing, internal only Knowledgebase is now protected on my Tailscale network using a LetsEncrypt SSL cert
Renew Certificate
To Renew the certificate Login to Nginx Proxy Manager and head over to SSL Certificates.
Click on the three dot menu and click Renew Now.
Thoughts
I've been looking for an easy method to manage my internal lan certificates, I've worked through a few different methods and CA servers. Although its a bit of a time sync to move my DNS over to Cloudflare and there are a few hoops to jump through, Nginx Proxy Manager is however low volume and maintenance and NextDNS as an internal DNS server is really powerful and simple to use.
This works well for me