LAN-only applications with TLS
2020-10-19 5 minutes #self-hosting
The internet is a wild place, filled with well, everything. There are many ways of exposing an application to the internet, but no matter how secure an application claims to be, or how confident you are with your infrastructure, sometimes you may just be more comfortable keeping it internal.
Historically, internal applications have been accessed with an IP and port:
192.168.1.200:32400. This works, but it’s far from nice as it’s hard to remember which port is which application (this is why we have DNS). For internet-facing applications, you’d add a DNS record for your domain, and point that to a reverse proxy which maps the domain to the port of the actual application. But what about internal-only applications? The
.local TLD is designed for use on local networks, allowing you to access machines using
hostname.local, but what if you wanted to use your own domain (
service.yourdomain.com)? And what about TLS?
# Internal DNS server
If you were to visit
service.yourdomain.com in a browser, you’d be presented with an error. The reason for this is simple: your computer has no idea where
service.yourdomain.com is, nor that it’s meant to be your home server at
192.168.1.200. You could get around this by adding a DNS record pointing to
192.168.1.200, but It’s considered bad practice to have internal IPs on public records. Instead, we’re going to need to override our DNS settings on our LAN so that all devices on our network know
service.yourdomain.com is actually available at
192.168.1.200, without needing to specify it manually.
The set up process for this varies slightly depending on your home network, but really there’s just 2 key steps:
# 1. Creating a custom DNS server
To run your DNS server, you’ll just need a device somewhere. In theory, it could be on the internet, but personally I like to keep these internal things inside my house (and if you’re reading this, so do you). Personally I use a Raspberry Pi 1A (yes really) but it could be your server, a VPS, anything. You’ll need to make sure it’s always available and reliable, as if it goes down your internet will feel much slower, and DNS queries will take far longer to complete.
For the server application itself, I use dnsmasq. Here’s an example dnsmasq configuration based on the one I’m using:
server=184.108.40.206 server=220.127.116.11 server=192.168.1.1 strict-order dns-loop-detect no-resolv no-poll host-record=service.yourdomain.com,192.168.1.200
Notice the final line adds a record for
service.yourdomain.com pointing to
192.168.1.200 - that’s the important bit. Now any DNS queries to this server for
service.yourdomain.com will point to your server - perfect! For domains dnsmasq doesn’t know, it forwards them through Cloudflare’s DNS servers (
18.104.22.168). I’ve added my gateway server here too (
192.168.1.1) so any other local records my router exposes (like mDNS) continue to work.
If you’re already running a service like pihole for your LAN, you can easily just add the required records there.
# 2. Deploying your custom DNS server
Unfortunately there’s no real standard for configuring a custom DNS server for your network. The gist of things is it’ll be somewhere in your router settings, but if you’re unsure it’s best to look up a guide based on your specific router. Be sure to set a secondary DNS server to something stable (eg
22.214.171.124), otherwise whilst your DNS server is offline, so is your internet.
# DNS Challenge
Now that devices on the LAN know that
service.yourdomain.com is your home server and can route traffic to it, we need to set up TLS so the connection is secure.
ACME, the protocol behind LetsEncrypt, supports 2 ways (challenges) to get an automated certificate: HTTP and DNS. Because of the way the DNS challenge works, in that it can prove ownership of an entire domain rather than a specific subdomain, LetsEncrypt can issue less specific certificates, because it can make more guarantees about the entire domain. These additional certificate features include wildcard certificates and what we need: Issuing certificates to internet inaccessible servers.
Traefik, my reverse proxy of choice, has built-in support for ACME. Other reverse proxies may have built in support (eg Caddy), else you can use Certbot, which integrates nicely with servers such as Nginx and Apache.
The only trouble with the DNS challenge is that it requires a supported DNS provider. The list of supported providers for both Certbot and Traefik are large, and likely covers 90% of users, but it’s not complete. I currently use Cloudflare for my DNS, which is one of the supported providers, so no issues there. You can of course run the DNS challenge manually, but this requires manual intervention every 90 days.
In theory, there are very few drawbacks of this approach. Obviously there are more moving pieces and thus more to maintain over sticking to IPs and ports. Once it’s up and running, there’s very little work to maintain. Certbot will keep renewing your certificates, and so long as you keep everything updated (which you should do anyway) it should keep working.
The largest drawback is that the services are only accessible to your LAN. If you leave your LAN, you leave with it your access. There are of course ways around that, namely using VPNs, but that’s a conversation for another time. If you’re reading this, that’s probably not a huge deal for you.
Check out exposing your homelab for some other ways of accessing your services.