Building my first Homelab
Hey ! In my first blog post I wanted to talk about how I've set up my personal Homelab
This blog post is NOT A TUTORIAL. It rather explains my journey and the tools I used for my setup. I hope this will help you learn new tools, and maybe guide your journey to make your own Homelab :)
t's been a while since I wanted to break out from the centralized web and be the owner of my own data. Besides, having your own data-center in your house is pretty sick right ?
But, I was also happy with my Google account, I knew it was reliable. Despite being used for profiling, my data was safe and accessible from anywhere at any time. So, if I wanted to start self-hosting everything, it had to be reliable.
To achieve this goal, I firstly wanted to access my local network securely. I had several options.
*1Exposing the local network to the internet
Option A: Opening ports on my ISP router
It's an easy task, I just needed to connect to my router and set up each port for each services individually. But it felt unsafe:
Each service were exposed to the web. If a CVE dropped while I wasn't home or sleeping. I was cooked.
Option B: Running a Cloudflare tunnel
At least, with Cloudflare, everything is protected from DDOS attacks and bot connections. But it was the same level of uncertainty as option A, exposing a service with an active CVE is dangerous.
At least, the service could be stopped via the Cloudflare dashboard. But it defeats a key purpose... I'm not self-hosting anymore ! What if Cloudflare is down ? I wouldn't be able to access my data anymore (and the whole Internet too).
I wanted to be the one managing my network.
Option C: Hosting a Wireguard *2"server"
I've decided to work with Wireguard, mostly because I had a microcomputer lying around that could serve as an entrypoint. But Wireguard also has some additional quirks:
- Primarily, it solved the main issue: it uses a key pair to establish a connection. So all my services were still only accessible by me and no one else, no more CVE attacks possible.
- It's fast, because it uses UDP, so there is no packet acknowledgment.
- It's a single *3entrypoint, it can be shut down and logged easily, and because of the key pair principle, each connection can be identified. So if a key is leaked, it's easy to quickly disable it.
On top of it all, It's what people are using the most to access their home network from anywhere, so there are ton of tutorial for setting it up online.
The only thing I needed to do was to open a port on my ISP router and redirect the connection to the microcomputer. It's only one port, so it is easily manageable, and it's not directly connected to a vulnerable and complex service, Wireguard is pretty straight forward so vulnerabilities are rare.
Now that this decision was made and I could access my home network, I had to deploy services. What's cool is that, since I have access to my home network... I just needed to deploy the services on my home network !
But I still had a problem... How do I deploy a service quickly and reliably...
Deploying reliably
At first, I wanted to have a main server running NixOS. I thought the idea of a declared system was great for a server, since it could be rebuilt instantly system in case of a disaster.
Unfortunately, I quickly resigned. I didn't have the time to learn how to properly set everything up, and the learning curve was steep. But I really was enjoying a "configuration based deployment". That's where Docker Compose comes in clutch.
My love story for Docker
Docker is amazing, it creates containers, a type of virtual machine that runs directly on the kernel of the host machine. This in turn makes it very lightweight, and allows you to create an environment that works the same on every machine (assuming you have a compatible Linux kernel)
Docker Compose is a module of Docker that can create such containers using a YAML-based configuration. This allows for great readability and fast deployment changes.
I'm not going to make a full tutorial here, especially since there are plenty online for you to check. But here's, for instance, the configuration I use for stirling-pdf, a tool for modifying pdf files.
services:
# We can add multiple container here
stirling-pdf:
# We start declaring a container here
image: stirlingtools/stirling-pdf:latest # Docker image
container_name: stirling-pdf # We can call it whatever
ports:
# Port fowarding [Port on host]:[Port in container]
- 6565:8080
volumes:
# Shared files [Path on host]:[Path in container]
- /srv/docker_srv/stirling-pdf:/configs
restart: unless-stopped # Restart policy of the containerIt's pretty straightforward, just choose your Docker image, setup port forwarding, create a volume, and you are all set. I can now access my pdf tool on port 6565 on my host machine !
For managing the different services, I first decided to use Portainer. But it felt overkill, since I was only using Docker Compose, and was isolating pretty much all of my containers.
That's when I discovered Dockge, a lightweight option that only manage Docker Compose (and not all of the docker images).
Besides, all the compose files of my containers are stored according to the setup of the Dockge compose file.
Great, now all my services are up and running, I just need to remember 50 different ports for each service, keep accepting the risk on the warning page my browser shows me because the SSL certificate is invalid, and pray my hard drive won't die on me so I don't lose any of my data.
Wait... That's just bad user experience... I want something easy and safe for my data !
Making it look good
I could just bookmark every port on my browser, setup a rule to remove the warning page on my range of local IPs and back up everything myself from time to time, but it's not clean... And this is pretty annoying when I use a different device.
Let's first setup a reverse proxy to manage certificates and redirection with a domain name
Setting up the DNS to have a clean name for my services
At first, I wanted to deploy my own DNS and create the certificates on domains like pdf.local. But I've learnt it wasn't very easy to do:
Turns out you can't generate certificate for .local or .lan domains... And for other TLD, you need to be a trusted authority for certificate generation, and I'm not one of them. I could have added my authority on the browsers I use, but it was as annoying as creating the bookmarks... So I scrapped the idea.
Instead, I've used Cloudflare DNS, and declared an A record with my local IP. Since I had a lot of different services, I've opted for the wildcard domain. This means I have an entry like this:
A: *.example.com -> 172.16.1.69
So, assuming I browse for pdf.example.com, It automatically resolves to the IP 172.16.1.69 which is my server when connected to my home network (so via Wireguard).
But that doesn't solve the port problem. I need a service that redirects me to the correct port according to the domain I type. That's where the reverse proxy comes in !
Using Nginx as reverse proxy
*4Nginx is not the best choice, because it doesn't support certificate management out of the box, like Caddy does. But since we have setup Dockge, it's easy to deploy pretty much anything, including Nginx-Proxy-Manager, which has a webui for certificate and proxy management.
Using this webui, I can simply say that I want to redirect all requests for pdf.example.com to 172.16.1.69:6565
You can also see up top, I have an SSL tab, to setup the certificate. It's quite easy to do using Cloudflare, since Nginx-Proxy-Manager uses certbot for certificates, you just need to follow the guide to get an API key from Cloudflare and pass it to the webui. Easy !
Now that everything is nice and clean, I just want it to be safe for my data. So let's setup a backup strategy !
Using Restic as a backup tool
For that, Restic is great, I recommend checking out their manual, it's easy to understand and relies on data deduplication. This means that if you backup the same file over and over, Restic only stores it once, so backup sizes remain small. It's also pretty easy to setup purge policies for backup, so you can keep creating backups and have older ones getting deleted automagically.
I've used Python to setup an automatic script for backups, and set a cronjob launching it every day. And quickly enough, I had a folder with all my data. But backing up data onto the same drive is stupid. Backing it up onto another drive is also a bad idea if the server goes up in flames.
Luckily, Hetzner, a hosting platform in Germany, had me covered. Their storage solutions were affordable, and just for 5€/month, I could backup all my files inside one of their storage box. It was perfect for redundancy.
On top of it all, Restic supports encryption out of the box, so I had no fear about Hetzner being able to look into my personal data.
Now if everything goes wrong, my data is safe, and can be restored with a simple command !
We're done !
With a webhook setup on Discord, I can check who's connecting through Wireguard, and if the backup is running smoothly.
Building your own Homelab is very rewarding. Especially when you know it's reliable and you can use it as a daily driver.
Unfortunately, once you've done it, you always want to improve it, trust me. That's what we'll discuss further on future blog post !
I hope I've been able to give you new tools and ideas to start building your own data center <3
- This title is quite fitting, it does feel like being naked ↩
- Since Wireguard is peer-to-peer, it doesn't make sense calling it a server. But in this specific use case, it's easier to understand that way ↩
Also known as a single point of failure I give you that↩- I really recommend using Caddy instead. I'm just describing my setup here, and I've yet to fully experiment with Caddy for my Homelab. ↩
Did you enjoy this article?
Recommend it — Standard Reader surfaces well-loved writing to more readers across the network.