## title: My homelab
## date: "2024-06-06"
I've got an old laptop that I don't use anymore, so I
thought I'd turn it into a server and deploy some free, open-
source web services on it.
The aim is to create a private homelab, i.e. the machine
should only be accessible via the local network. None of the
services are exposed to the Internet, with the exception of
Wireguard, which lets me access the services from the
outside.
The aim of this post is to present the main steps I've taken
and explain how the homelab works.
My laptop is an ASUS ROG G750 with 8GB of memory and 2 HDDs
of around 600GB each. It hasn't been used for about five or
six years and the battery is dead.
HTML ASUS ROG G750
## First steps
First, I decided to make an old USB key bootable. I install
Ventoy on it to be able to load different image disks (ISO)
without having to rewrite each time directly on the USB key.
HTML Ventoy
I put Memtest86+ to test the memory, shredos.x86_64 to wipe
the HDDs and finally Debian 12 which will be the main OS.
HTML Memtest86+
HTML shredos.x86_64
HTML Debian 12
So when I boot on the USB key, it loads the "multiboot" boot-
loader (Ventoy) and I can then load one of the three
programs.
## Pre configuration
To be able to deploy the system configuration and reproduce
it later, I'm writing an Ansible playbook and testing it on
a local VM (virt-manager + KVM).
The entire configuration is available at the bottom of the
page.
## TLS certificates
I want communication with web applications to be encrypted
and secure, so I need an HTTPS server, so I need TLS
certificates and, to make things easier, a domain name.
For the domain name I used Duck DNS and reserved the sub-
domain theobori.duckdns.org which for the moment corresponds
to the IPv4 of my virtual machine accessible only from the
host system.
HTML Duck DNS
HTML theobori.duckdns.org
In fact, I only need to manage one certificate with two
SANs:
- theobori.duckdns.org
- *.theobori.duckdns.org
## Services
Every application is deployed with the Ansible playbook are
conteuneurized and managed with Docker.
They are accessible only through port 443 managed by
Traefik. Each sub-domain of theobori.duckdns.org corresponds
to a service, with the exception of the homepage, which is
associated with the domain itself.
HTML Traefik
HTML theobori.duckdns.org
## Firewall
To filter incoming network traffic, I manipulate iptables
with the ufw tool. There are only four ports open as
declared below in the Ansible playbook configuration.
- role: weareinteractive.ufw
tags: ufw
ufw_enabled: true
ufw_packages: ["ufw"]
ufw_rules:
- logging: "full"
- rule: allow
to_port: "443"
- rule: allow
to_port: "80"
- rule: allow
{% raw %} to_port: "{{ ssh_port }}" {% endraw %}
# Wireguard
- rule: allow
to_port: "51820"
proto: udp
# Delete default rule
- rule: allow
name: Anywhere
delete: true
ufw_manage_config: true
ufw_config:
IPV6: "yes"
DEFAULT_INPUT_POLICY: DROP
DEFAULT_OUTPUT_POLICY: ACCEPT
DEFAULT_FORWARD_POLICY: DROP
DEFAULT_APPLICATION_POLICY: SKIP
MANAGE_BUILTINS: "no"
IPT_SYSCTL: /etc/ufw/sysctl.conf
IPT_MODULES: ""
## Identity provider
Services with integration for protocols to verify user
identity or determine permissions are all linked to the
Authentik user directory.
HTML Authentik
I needed OAuth2 for Portainer and LDAP for several other
services such as Owncloud.
HTML Portainer
HTML Owncloud
If I remember correctly, the OAuth2 Outpost is embedded in
the application by default, whereas the LDAP Outpost had to
be configured with specific parameters for Docker.
Here's a diagram of several services trying to retrieve the
identity of an Authentik user.
HTML Authentik
/authentik_users.png
IMG /authentik_users.png
## Access management
With Authentik, group policies have been created to
authorize only certain groups of users to access certain
services.
HTML Authentik
For example, for Jellyfin, only users in the Jellyfin group
are authorized to connect.
HTML Jellyfin
In this way, I was able to secure all administration
services by authorizing only users in groups reserved for
administration.
I also used Traefik and Authentik to secure access to
services not protected by authentication.
HTML Traefik
HTML Authentik
I added middleware to the reverse proxy to enable HTTP
ForwardAuth with Authentik. In practical terms, this places
a connection portal in front of the targeted web services.
HTML Authentik
Let's say I want to access duplicati.theobori.duckdns.org,
it could be schematized as follows.
HTML duplicati.theobori.duckdns.org
/authentik_proxy.png
IMG /authentik_proxy.png
## Media stack
One of the main objectives was to be able to manage movies
and series and watch them from any device on the local
network.
So I set up a stack for managing and downloading media,
which would then be streamed to devices by Jellyfin.
HTML Jellyfin
Here's what the media stack looks like.
/media_stack.png
IMG /media_stack.png
## Backup and restore
To back up container data, I use Duplicati. It lets you
encrypt data and manage retention very easily via a web
interface.
HTML Duplicati
These backups can then be restored on my old computer.
## Monitoring
To keep abreast of service status, I've opted for Uptime
Kuma, which will alert me via Discord when a service is down
for n seconds.
HTML Uptime Kuma
I also have a Prometheus and Grafana stack that lets me
collect metrics on the system and on Docker containers. As
for Uptime Kuma, I'm alerted by Discord according to limits
defined for RAM and available storage space, for example.
HTML Prometheus
HTML Grafana
HTML Uptime Kuma
This is how the monitoring stack looks.
/monitoring_stack.png
IMG /monitoring_stack.png
## Final home page
Here's an overview of the dashboard, featuring all the
services exposed to the local network. In a way it's the end
result of service implementation.
/dashy.png
IMG /dashy.png
## Links
https://github.com/theobori/homelab
HTML https://github.com/theobori/homelab