Accessing your self-hosted applications with an SSL certificate and .local domain name

There are several benefits to running your own recursive DNS server. I recently deployed my own internal DNS server primarily to access my self-hosted applications via a URL instead of an IP address with a specified port.

Using a recursive DNS server will also provide some privacy features since instead of querying a public DNS server, the DNS server will request the IP address from the authoritative name server and cache the requests. Initial requests will take a bit longer but load times will decrease as the DNS server will cache request made. This prevents your ISP from building a profile based on your DNS requests (as you won't be using their DNS servers).

Additional benefits include lower response times for DNS queries and filtered DNS queries.

Illustration of how my internal DNS server works.

I deployed my DNS server using my Proxmox server with an Alpine Linux LXC container, AdGuard, Unbound, and Nginx Reverse Proxy.

To begin, I deployed an LXC container based on Alpine Linux on my Proxmox server. I choose Alpine Linux because it is a lightweight distribution of Linux. Once the LXC container is deployed, I added a non root user, installed OpenSSH to manage the container remotely, and disabled password based authentication (I am using key-based authentication).

The next step is to install the DNS server. I choose to install a DNS forwarder that are able to block ads from specified domain names. Two popular options are Pi-Hole and AdGuard Home. I used AdGuard Home for my DNS server. You can see the setup instructions to install AdGuard Home on Alpine Linux in a post I made found here.

After the initial setup of AdGuard Home was completed, I installed Unbound and then configured AdGuard Home with it.

Next, I added DNS rewrites to my AdGuard Home instance. You can choose any domain you would like to use here. For a local only domain name, I chose the .local extension. Because the .local extension is not a fully qualified domain name, any attempts to access it from outside my local network would not be resolved. The .local domain name is reserved by the IETF so that it can't be used as a top level domain[1]. More information about the .local domain name can be found at the IETF RFC 6762 documentation found here.

Then, I added custom DNS entried on my Nginx Proxy Manger instance. I specified the IP address and port the web applications were hosted on, and choose a custom subdomain. The following screenshot shows a few of the proxied hosts added.

The next step is to generate a self-signed certificate so that the traffic is encrypted. Because I am using a .local domain name, getting an SSL certificate from LetsEncrypt is not possible as the internal applications are not publicly accessible.

To generate a self-signed certificate, I used openssl on a fresh LXC container.

First, I ran the following commands to generate the key and the certificate. I ran the following commands as root.

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./nginx.key -out ./nginx.crt

The "Common Name" is the only required information as it is a self-signed certificate. I created a wildcard certificate with the domain name *.sanchez.local.

Then I needed to access these files to upload them to Nginx Proxy Manger. I setup a quick web server by running the following command.

python3 -m http.server 80

The web server can be reached via its IP address. I downloaded the two files and uploaded them to Nginx Proxy Manager. You need to then add the self-signed SSL certificate and certificate key.

You will still receive an error that you have a self-signed certificate when you attempt to access self-hosted web applications via its URL. This can be removed by adding the certificate to the list of trusted certificates on the device accessing the web application.

Once the certificate is added to the list of trusted certificates, you will no longer recive the error and you can access your self-hosted applications securely!

Reference

[1]“.local,” Wikipedia, Jan. 30, 2021. https://en.wikipedia.org/wiki/.local