LAN HTTPS Everywhere
The aim of this investigation was to find a way to deploy HTTPS certificates on my LAN. This might seem over the top, but a) Troy Hunt thinks it is a good idea and b) I was getting fed up of the ‘insecure’ messages.
After much fiddling and experimenting I have settled on this process.
Things to note:
- You do not need any web server on the internet. You just need to be able to edit your domain DNS record.
- Use a subdomain for each certificate/server – these do not need to actually exist on the DNS.
- I’m not going to go into detail about things that are easily found with Google search.
Prerequisites
- Domian – you need to have one available – I bought mine for $10 from Google Domains.
- Host the DNS for the domain where you can edit the records – I was going to use Google Domains (hence the purchase) but ended up with the domain on CloudFlare DNS servers.
For me I am using Lighttpd so some of this is that server specific and my OS is DietPi.
Set Up DNS Access
Assuming you have got your CloudFlare account all setup, go to your profile page, scroll down and click on ‘View’ next to Global API Key. You will need it in the next step.
Install & Configure certbot
You may need sudo for these commands if not on DietPi as root. Also remember that any scripts need to be made executable chmod +x .
First thing is to install certbot with the right plugin.
If like me you use DietPi, then dietpi-software install 92 else apt-get install certbot . Then:
apt-get install python3-certbot-dns-cloudflare
Create a folder called .secrets and create /edit a file called cloudflare.ini . Include the following lines from setting up access to CloudFlare DNS above. Treat this like a password so chmod 600
1 2 |
dns_cloudflare_email = xyz@nowhere.com dns_cloudflare_api_key = 11111111111111111111111111 |
Now create a small script to generate the certificate (you will need to change the domain and the path to match your ini file) – you will only need this once (hopefully):
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#!/bin/sh MY_DOMAIN="yourdomain.net" certbot certonly \ --dns-cloudflare \ --dns-cloudflare-credentials /user/.secrets/certbot/cloudflare.ini \ -d $MY_DOMAIN cat /etc/letsencrypt/live/$MY_DOMAIN/cert.pem /etc/letsencrypt/live/$MY_DOMAIN/privkey.pem > \ /etc/letsencrypt/live/$MY_DOMAIN/web.pem systemctl restart lighttpd.service |
You can run this script, answer the questions and the certificate should be generated.
Note the cat command in the script. certbot does not generate the right combined certificate for lighttpd so this needs to be done manually. That is a bit of a pain and requires a little more setting up to get renewal to work automatically.
Setting Up Renewal
To get a new combined certificate on renewal a small script is needed that will execute once the certificate has been renewed and deployed.
1 |
nano /etc/letsencrypt/renewal-hooks/deploy/combine.sh |
and in the file place the following code (no modification necessary):
1 2 3 4 5 6 7 8 9 10 |
#!/bin/sh for domain in $RENEWED_DOMAINS do # Combine the certificate and private key file cat /etc/letsencrypt/live/$domain/cert.pem /etc/letsencrypt/live/$domain/privkey.pem > \ /etc/letsencrypt/live/$domain/web.pem done systemctl restart lighttpd.service |
The only way to test this is to force the renewal
1 |
certbot renew --force-renewal |
A modern install of certbot will install systemd timer for you so it should just renew. To check the timer
1 |
systemctl list-timers --all |
Lighttpd Configuration
This is included for me more than anything, as it can easily be found, but this is the addition to the standard /etc/lighttpd/lighttpd.conf file that I find works.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$SERVER["socket"] == ":443" { ssl.engine = "enable" ssl.pemfile = "/etc/letsencrypt/live/your.domain.net/web.pem" # Combined Certificate ssl.ca-file = "/etc/letsencrypt/live/your.domain.net/chain.pem" # Root CA server.name = "your.domain.net" # Domain Name OR Virtual Host Name accesslog.filename = "/var/log/lighttpd/domain_access.log" } $HTTP["scheme"] == "http" { # This should be always true for insecure incomming connections: $HTTP["host"] =~ ".*" { # redirect to https, port 443: url.redirect = (".*" => "https://%0$0") } } |
Restart lighttpd (and clear cache).
Setting up an internal FQDN
Outside the scope of this but, if you have PiHole installed simply add the domain and IP to the /etc/hosts file on the PiHole, restart PiHole and you should be able to just type in the domain name and be directed to a secure https address.
HTH
by