URI:
       ## 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