Disclaimer
This Article is a work in progress
Prerequisites
This guide assumes you already have:
- A Home server with atleast 1 service being served with docker
- Tailscale account and installed on the server and atleast 1 personal device
Introduction
Problem #1 When first starting in homelabing, your services like jellyfin will be accessable with a link that looks something 192.168.1.42:8080. Depending on your router you might me lucky enough to access with the hostname with something like myserver.local:8080, or with tailscale it might look like myserver.blue-apples.ts.net:8080. As you add more services like immich on port 8888 and paperless-ngx on 9000, you quickly have a phone book of ports you have to remember and remember which services they belong to.
But wait, this isn’t how the internet works. We go to google.com and youtube.com and sometimes we go to mail.google.com. Notice that first part. They’re both google.com but they go to different services. The “mail.” is a whats known as a subdomain and its a very elegant way of serving multiple services from one domain name.
When were done with this guide. You will be able to access all your services by urls that look something like:
- media.mydomain.com -> Jellyfin
- images.mydomain.com -> Immich
- paperless.mydomain.com -> Paperless-ngx
Buying a Domain Name
The first thing we need to do is purchase a domain name. You might think you could just use your hostname and use DNS rewrites in your local DNS to route traffic to your server with something like media.myserver.local. The importance of a publicly registered domain name will become apparent later in this tutorial when we get to SSL certificate for HTTPS connections.
Im personally cheap so I purchased my domain from Namecheap. There are other options like [hostinger] or squarespace. This domain name is only going to be used by you so you dont need to pay a premium for .com or .ca. You’ll notice less common TLDs like xyz are much cheaper and honestly, in my opinion, much more fitting for a home lab.
Connecting your domain with Cloudflare
Once you purchase the domain youll have to point the nameservers to cloudflare and to do that youll need a cloudflare account so go ahead a make that. Heres the link.
In the Namecheap Portal go to:
Manage > Domains > Nameservers and set the option to “Custom DNS”. And paste the nameservers you obtained from cloudflare. There will be 2 and theyll look like [name].ns.cloudflare.com
## Insert Image Here ##
Creating a DNS entry
In cloudflare, youll need to create a dns entry for you for newly aquired domain to point to your server. In cloudflare go to Domains > YourDomain.xyz > DNS Records
And create an wildcard “A” record using the tailscale IP for your home server. If your not familiar with this termonoly, an “A” record is simply when you associate a domain name to an IPv4 address and a wildcard is way of pointing all subdomains to the same server.
## Insert Image Here ##
Note Because your server is on your tailnet which only you (and maybe some friends or family) have access to, anyone who attempt to resolve your domain will not be able to access your services.
The Reverse Proxy
So now you have a domain and are pointing any request for that domain, and its subdomains, to your server. But what happens when the request gets to the server. How will the server know what service to return to you.
Enter the reverse proxy. In simple terms, the reverse proxy is a middle man between you and your services. It looks at the subdomain in the request and returns the service from the backend based on that. It does other thing but thats that the basics of it.
Again, I want to highlight that since the domain resolves to a tailscale ip only devices on your tailnet will be able to access the server. There is a caveat I would like to point out. This does not work for node sharing within tailscale as tailscale assigns different IP address for the persons the node is share with. So they IP they recieve from cloudflare will not be the same as the IP in their tailnet.
The specific reverse proxy I use is called Caddy. There are other like Nginx, Traefik, and one a recently came accross, Ferron which I plan to try and write about in the future.
Caddy is unqiue in that is handle SSL certificate automatically. SSL certificates are what allow you to have HTTPS. You might be wondering why HTTPS matters since were using tailscale and our traffic is already encrypted and secure. You’re correct, but the neither your webbrowser or your services know that and they will through errors all day without it.
To obtain the certificates from within your walled garden, that is your tailnet. We need to perform whats know as the DNS-01 challenge. This isnt the most modern or secure challenge but because Cloudflare cant reach our server as its in our tailnet, the DNS-01 challenge will prove to cloudflare that you own that domain by servering a TXT file that it placed as a record on your domain. See here for more on DNS-01.
I am using a caddy instance with 2 plugins. To enable this plugins you need to build a custom images
Dockerfile
|
|
The above docker file will build a custom caddy image.This image contains the cloudflare plugin which will handle the DNS-01 Challenge and “Caddy-Docker-Proxy” which will monitor our docker containers for labels which will allow the caddy configuration file to update automatically when containers are made.
Run the following command to build
docker build -t custom-caddy-proxy .
Creating your Caddyfile
Caddy configuration file is called a Caddyfile. This tells caddy how to handle incoming request. Caddy-Docker-Proxy reate a caddyfile in memory. It will watch your machine for containers containing specific labels and will update the caddy file as needed. This removes the hassle of creating a caddyfile entry for every service you create.
Below is the initial caddyfile. Place this in the data direcory of your caddy container and caddy will use this as the starting template for its “in memory” caddyfile. This is useful because we can predifine the block needed for cloudflares DNS-01 Challenge.
Caddyfile
|
|
compose.yaml
|
|
.env
|
|
Go an obtain your cloudflare API token and paste it to the environment file for caddy
Example Service
|
|
In the above example service, draw your attentions to:
- The Labels. This tells caddy docker proxy what blocks to create in the “in memory” caddyfile it is managing
- The Networks. This container is on an external network called
proxy. It is important that every service that is to be served by the reverse proxy is also assigned to this network.