{"id":15148346,"url":"https://github.com/sunsided/epimelitis","last_synced_at":"2026-03-02T05:04:30.262Z","repository":{"id":223053241,"uuid":"758195589","full_name":"sunsided/epimelitis","owner":"sunsided","description":"Home Assistant and Pi-Hole in Kubernetes in Talos Linux on a Raspberry Pi","archived":false,"fork":false,"pushed_at":"2025-10-19T15:30:20.000Z","size":355,"stargazers_count":9,"open_issues_count":8,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-10-19T23:47:52.379Z","etag":null,"topics":["alpine-linux","kubernetes","kvm","libvirt","mosquitto","opentofu","pi-hole","qemu","raspberry-pi","raspberry-pi-5","talos-linux","terraform","zigbee"],"latest_commit_sha":null,"homepage":"","language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sunsided.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-15T20:10:51.000Z","updated_at":"2025-10-19T15:30:23.000Z","dependencies_parsed_at":"2024-02-25T13:24:27.607Z","dependency_job_id":"85b0c997-6c3c-41c9-a4e1-1c0c8d6f0afa","html_url":"https://github.com/sunsided/epimelitis","commit_stats":null,"previous_names":["sunsided/epimelitis"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sunsided/epimelitis","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunsided%2Fepimelitis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunsided%2Fepimelitis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunsided%2Fepimelitis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunsided%2Fepimelitis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sunsided","download_url":"https://codeload.github.com/sunsided/epimelitis/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunsided%2Fepimelitis/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29993106,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T01:47:34.672Z","status":"online","status_checked_at":"2026-03-02T02:00:07.342Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alpine-linux","kubernetes","kvm","libvirt","mosquitto","opentofu","pi-hole","qemu","raspberry-pi","raspberry-pi-5","talos-linux","terraform","zigbee"],"created_at":"2024-09-26T13:03:14.750Z","updated_at":"2026-03-02T05:04:30.246Z","avatar_url":"https://github.com/sunsided.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Επιμελητής\n\n![Home Assistant](https://img.shields.io/badge/Home_Assistant-2024.2-blue?logo=home-assistant)\n![YAML](https://img.shields.io/badge/Zigbee-3.0-blue?logo=zigbee)\n![Raspberry Pi](https://img.shields.io/badge/Raspberry_Pi-5-blue?logo=raspberrypi)\n![Kubernetes](https://img.shields.io/badge/Kubernetes-1.29-blue?logo=kubernetes)\n![Talos Linux](https://img.shields.io/badge/Talos_Linux-1.64-blue?logo=linux)\n![Alpine Linux](https://img.shields.io/badge/Alpine_Linux-3.19-blue?logo=alpine-linux)\n![libvirt](https://img.shields.io/badge/libvirt-9.10-blue?logo=qemu)\n![OpenTofu](https://img.shields.io/badge/OpenTofu-1.6-blue?logo=opentofu)\n![YAML](https://img.shields.io/badge/YAML-now_30%25_more-blue?logo=yaml)\n\n\u003e **επιμελητής** **•** (epimelitís) _m_ (_plural_ **επιμελητές**, _feminine_ **επιμελήτρια**)\n\u003e\n\u003e one who takes care of a thing, in an official capacity; a curator, an editor, (law) a caretaker or guardian\n\n\u003cdiv align=\"center\"/\u003e\n    \u003cimg alt=\"A raging raspberry carrying a shipload of lightbulbs and hardware\" src=\"docs/images/raspberry-rage.jpg\"\u003e\n\u003c/div\u003e\n\n## What if ...\n\n- We run **Home Assistant**\n- ... but in a **Container**\n- ... that runs on **Kubernetes**\n- ... inside a Kernel-based **Virtual Machine**\n- ... that runs on **Alpine Linux**\n- ... on a **Raspberry Pi**\n\nFor this experiment I'll be using a Raspberry Pi 5 with a 256 GB class A2 microSD card (it was cheap).\n\nOkay, hear me out:\n\n\u003cdiv align=\"center\"/\u003e\n    \u003cimg alt=\"Crazy Guy suggesting Kubernetes\" src=\"docs/images/aliens.jpg\"\u003e\n\u003c/div\u003e\n\n## Table of Contents\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n- [1. Setting up Alpine Linux as the Hypervisor OS](#1-setting-up-alpine-linux-as-the-hypervisor-os)\n  - [Getting Alpine](#getting-alpine)\n  - [Configuring Alpine](#configuring-alpine)\n  - [Enable the community repository](#enable-the-community-repository)\n  - [Become a Hypervisor: Installing KVM / Qemu / libvirt](#become-a-hypervisor-installing-kvm--qemu--libvirt)\n  - [Enable automatic suspension and restart of Guests](#enable-automatic-suspension-and-restart-of-guests)\n- [2. Provision Talos Linux](#2-provision-talos-linux)\n  - [Download the `metal-arm64` image and convert it to qcow2](#download-the-metal-arm64-image-and-convert-it-to-qcow2)\n  - [Run OpenTofu / Terraform to create the Talos Linux guest](#run-opentofu--terraform-to-create-the-talos-linux-guest)\n  - [Connect to the Talos VM](#connect-to-the-talos-vm)\n  - [Configuring and Bootstrapping Talos](#configuring-and-bootstrapping-talos)\n- [3. The part where we use Kubernetes](#3-the-part-where-we-use-kubernetes)\n  - [Storage, Ingress, Load balancing](#storage-ingress-load-balancing)\n  - [Improved DNS](#improved-dns)\n  - [Home Assistant and Sensors](#home-assistant-and-sensors)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## 1. Setting up Alpine Linux as the Hypervisor OS\n\n### Getting Alpine\n\nGet Alpine Linux from the [Downloads](https://www.alpinelinux.org/downloads/) page and select the Raspberry Pi variant.\n\nFor example, Alpine Linux 3.19.1 for Raspberry Pi can be downloaded from:\n\n```shell\ncurl -LO https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/aarch64/alpine-rpi-3.19.1-aarch64.img.gz\n```\n\nFlash the image using [Raspberry Pi Imager] and boot your\nPi from the SD card.\n\n### Configuring Alpine\n\nI had to plug in my keyboard to the first USB 3 port _after_ the Pi was booted.\nOther ports or timings didn't work for me.\n\nFollowing the [setup-alpine] instructions,\n\n- log in as `root` with no password\n- run `setup-alpine` and answer truthfully\n    - disable remote login for root\n    - create a new user for yourself\n    - enable lan and wifi\n    - enable SSH server\n    - create a `sys` partition\n- reboot\n- log in and run `ip a` to get the Pi's IP address\n\nFrom your regular machine, run `ssh-copy-id \u003cUSER\u003e@\u003cIP\u003e`.\nIf this works you can unplug the display and keyboard.\n\nSee also [Granting Your User Administrative Access] for\n`doas` (`sudo` in Ubuntu lingo). As `root`, run\n\n```\napk add doas\necho 'permit :wheel' \u003e /etc/doas.d/doas.conf\naddgroup \u003cUSER\u003e wheel\n```\n\nAfter this, `doas \u003ccommand\u003e` does the trick.\n\n[setup-alpine]: https://docs.alpinelinux.org/user-handbook/0.1a/Installing/setup_alpine.html\n[Granting Your User Administrative Access]: https://docs.alpinelinux.org/user-handbook/0.1a/Working/post-install.html#_granting_your_user_administrative_access\n\n### Enable the community repository\n\nEdit the `/etc/apk/repositories` file:\n\n```shell\ndoas apk add vim\ndoas vim /etc/apk/repositories\n```\n\nEnable the `http://alpine.sakamoto.pl/alpine/v3.19/community` rpo.\n\n### Become a Hypervisor: Installing KVM / Qemu / libvirt\n\n```shell\napk add \\\n    libvirt-daemon libvirt-client \\\n    qemu-img qemu-system-arm qemu-system-aarch64 qemu-modules \\\n    openrc\nrc-update add libvirtd\n```\n\nAdd your user to `libvirt`:\n\n```shell\naddgroup \u003cUSER\u003e libvirt\n```\n\n\u003e By default, libvirt uses NAT for VM connectivity. If you want to use the default configuration, you need to load the `tun` module.\n\n```shell\nmodprobe tun\necho \"tun\" \u003e\u003e /etc/modules-load.d/tun.conf\ncat /etc/modules | grep tun || echo tun \u003e\u003e /etc/modules\n```\n\n\u003e If you prefer bridging a guest over your Ethernet interface, you need to make a bridge.\n\nAdd the scripts that will create bridges off `/etc/network/interfaces`:\n\n```shell\napk add bridge\n```\n\nAdd the network bridge:\n\n```shell\nbrctl addbr brlan\nbrctl addif brlan eth0\n```\n\nChange your `/etc/network/interfaces` to\n\n- disable `dhcp` on your `eth0`\n- add `iface brlan inet dhcp`\n- set `bridge-ports eth0` to bridge it with eth0\n\n```plain\nauto lo\niface lo inet loopback\n\nauto eth0\niface eth0 inet manual\n\nauto brlan\niface brlan inet dhcp\n    bridge-ports eth0\n    bridge-stp 0\n    post-up ip -6 a flush dev brlan; sysctl -w net.ipv6.conf.brlan.disable_ipv6=1\n\nauto wlan0\niface wlan0 inet dhcp\n```\n\nFor more information, see [Bridge] and [Bridging for Qemu] (this one is important).\n\n[Bridge]: https://wiki.alpinelinux.org/wiki/Bridge\n[Bridging for Qemu]: https://wiki.alpinelinux.org/wiki/Bridge#Bridging_for_QEMU\n\nTo restart the networking stack, run\n\n```shell\nservice networking restart\n```\n\nIf it fails, reconnect your keyboard ...\n\n\u003e In order to use libvirtd to remotely control KVM over ssh PolicyKit needs a `.pkla` informing it that this is allowed. Write the following file to `/etc/polkit-1/localauthority/50-local.d/50-libvirt-ssh-remote-access-policy.pkla`\n\n```shell\napk add dbus polkit\nrc-update add dbus\n```\n\nWe do that:\n\n```shell\nmkdir -p /etc/polkit-1/localauthority/50-local.d/\ncat \u003c\u003cEOF \u003e file.txt\n[Remote libvirt SSH access]\n Identity=unix-group:libvirt\n Action=org.libvirt.unix.manage\n ResultAny=yes\n ResultInactive=yes\n ResultActive=yes\nEOF\n```\n\nFor the Terraform `libvirt` provider to work, we also need\nto enable TCP forwarding for the SSH server.\n\n```shell\nsed -i '/^AllowTcpForwarding no$/s/no/yes/' /etc/ssh/sshd_config\nservice sshd restart\n```\n\n### Enable automatic suspension and restart of Guests\n\n\u003e The `libvirt-guests` service (available from Alpine 3.13.5)\n\u003e allows running guests to be automatically suspended or shut\n\u003e down when the host is shut down or rebooted.\n\u003e\n\u003e The service is configured in /etc/conf.d/libvirt-guests.\n\u003e Enable the service with:\n\n```shell\nrc-update add libvirt-guests\n```\n\n## 2. Provision Talos Linux\n\n### Download the `metal-arm64` image and convert it to qcow2\n\n```shell\ncurl -LO https://github.com/siderolabs/talos/releases/download/v1.6.4/metal-arm64.iso\nqemu-img convert -O qcow2 metal-arm64.iso metal-arm64.qcow2\n```\n\n### Run OpenTofu / Terraform to create the Talos Linux guest\n\nChange into the [`infra/`](infra/) directory and run:\n\n```shell\ntofu apply\n# or terraform apply\n```\n\n### Connect to the Talos VM\n\n```shell\nvirsh console talos\n```\n\nIn the UEFI shell, type `exit`. You will be brought to the\nUEFI, where you select the `Boot Manager`. Pick the third\ndisk from the list and boot from there - you'll see Talos Linux' boot menu now:\n\n```\n                GNU GRUB  version 2.06\n\n /------------------------------------------------\\\n |*Talos ISO                                      |\n | Reset Talos installation                       |\n |                                                |\n \\------------------------------------------------/\n```\n\nBoot Talos. Say hi. It'll greet you with\n\n```plain\n[    9.851478] [talos] entering maintenance service {\"component\": \"controller-runtime\", \"controller\": \"config.AcquireController\"}\n[    9.854129] [talos] this machine is reachable at: {\"component\": \"controller-runtime\", \"controller\": \"runtime.MaintenanceServiceController\"}\n[    9.855517] [talos]  10.22.27.56 {\"component\": \"controller-runtime\", \"controller\": \"runtime.MaintenanceServiceController\"}\n[    9.856546] [talos]  2001:9e8:17ba:2200:5054:ff:feba:99ef {\"component\": \"controller-runtime\", \"controller\": \"runtime.MaintenanceServiceController\"}\n[    9.858176] [talos] server certificate issued {\"component\": \"controller-runtime\", \"controller\": \"runtime.MaintenanceServiceController\", \"fingerprint\": \"rMWhs9V9Y30sbs9W5KNCgVRReKGrfvV0FwMtqEX4OW8=\"}\n[    9.860209] [talos] upload configuration using talosctl: {\"component\": \"controller-runtime\", \"controller\": \"runtime.MaintenanceServiceController\"}\n[    9.862119] [talos]  talosctl apply-config --insecure --nodes 10.22.27.56 --file \u003cconfig.yaml\u003e {\"component\": \"controller-runtime\", \"controller\": \"runtime.MaintenanceServiceController\"}\n[    9.863452] [talos] or apply configuration using talosctl interactive installer: {\"component\": \"controller-runtime\", \"controller\": \"runtime.MaintenanceServiceController\"}\n[    9.864784] [talos]  talosctl apply-config --insecure --nodes 10.22.27.56 --mode=interactive {\"component\": \"controller-runtime\", \"controller\": \"runtime.MaintenanceServiceController\"}\n[    9.866219] [talos] optionally with node fingerprint check: {\"component\": \"controller-runtime\", \"controller\": \"runtime.MaintenanceServiceController\"}\n[    9.867265] [talos]  talosctl apply-config --insecure --nodes 10.22.27.56 --cert-fingerprint 'rMWhs9V9Y30sbs9W5KNCgVRReKGrfvV0FwMtqEX4OW8=' --file \u003cconfig.yaml\u003e {\"component\": \"controller-runtime\", \"controller\": \"runtime.MaintenanceServiceController\"}\n```\n\n**Take note of the IP**, in this case `10.22.27.56`.\n\nYou may now probably want to tell your router to always assign this IP address to that new device on your network.\n\n### Configuring and Bootstrapping Talos\n\nFirst, get `talosctl`:\n\n```shell\ncurl -sL https://talos.dev/install | sh\n```\n\nGiven the above IP we can now identify the available disks:\n\n```shell\ntalosctl disks --insecure --nodes 10.22.27.56\n```\n\nThe disk of `124 MB` is the one we just booted from, the `54 GB` is my system disk and the `107 GB` is for state.\n\n```plain\nDEV        MODEL   SERIAL   TYPE   UUID   WWID   MODALIAS                    NAME   SIZE     BUS_PATH                                         SUBSYSTEM          READ_ONLY   SYSTEM_DISK\n/dev/vda   -       -        HDD    -      -      virtio:d00000002v00001AF4   -      54 GB    /pci0000:00/0000:00:01.2/0000:03:00.0/virtio2/   /sys/class/block\n/dev/vdb   -       -        HDD    -      -      virtio:d00000002v00001AF4   -      107 GB   /pci0000:00/0000:00:01.3/0000:04:00.0/virtio3/   /sys/class/block\n/dev/vdc   -       -        HDD    -      -      virtio:d00000002v00001AF4   -      124 MB   /pci0000:00/0000:00:01.4/0000:05:00.0/virtio4/   /sys/class/block\n```\n\nDo have a look at the [Local Path Provisioner] configuration mentioned in the Talos Linux documentation if you want to extend your storage.\n\nChange into the [`talos/`](talos/) directory and run the `talosctl gen config` command. Make sure to use the proper disk, here `/dev/vda`:\n\n```shell\ntalosctl gen config \"talos-epimelitis\" https://talos-epimelitis.fritz.box:6443 \\\n    --additional-sans=talos-epimelitis.fritz.box \\\n    --additional-sans=talos-epimelitis \\\n    --additional-sans=10.22.27.71 \\\n    --install-disk=/dev/vda \\\n    --output-dir=.talosconfig \\\n    --output-types=controlplane,talosconfig \\\n    --config-patch=@cp-patch.yaml\n```\n\nEdit the created `.talosconfig/controlplane.yaml` in an editor and add the storage volume (as shown above):\n\n```yaml\nmachine:\n  # ...\n\n  kubelet:\n    extraMounts:\n    - destination: /var/mnt/storage\n        type: bind\n        source: /var/mnt/storage\n        options:\n        - bind\n        - rshared\n        - rw\n\n  # ...\n\n  disks:\n    - device: /dev/vdb\n      partitions:\n        - mountpoint: /var/mnt/storage\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003e💡 Show details ...\u003c/b\u003e\u003c/summary\u003e\n\n\u003cp\u003eOn subsequent boots after the first one, \u003cc\u003etalosctl dmesg\u003c/c\u003e will print something like\u003c/p\u003e\n\n\u003cpre\u003e\u003ccode\u003e\ntalos-epimelitis.fritz.box: user: warning: [2024-02-19T20:45:36.936258652Z]: [talos] phase udevSetup (12/17): done, 1.516129ms\ntalos-epimelitis.fritz.box: user: warning: [2024-02-19T20:45:36.936771652Z]: [talos] phase userDisks (13/17): 1 tasks(s)\ntalos-epimelitis.fritz.box: user: warning: [2024-02-19T20:45:36.937193652Z]: [talos] task mountUserDisks (1/1): starting\ntalos-epimelitis.fritz.box: user: warning: [2024-02-19T20:45:36.938507652Z]: [talos] task mountUserDisks (1/1): skipping setup of \"/dev/vdb\", found existing partitions\ntalos-epimelitis.fritz.box: kern:  notice: [2024-02-19T20:45:36.940458652Z]: XFS (vdb1): Mounting V5 Filesystem\ntalos-epimelitis.fritz.box: kern:    info: [2024-02-19T20:45:36.958119652Z]: XFS (vdb1): Ending clean mount\ntalos-epimelitis.fritz.box: user: warning: [2024-02-19T20:45:36.959145652Z]: [talos] task mountUserDisks (1/1): done, 21.875926ms\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e... indicating the disk has been correctly set up.\u003c/p\u003e\n\u003c/details\u003e\n\nUpdate your talosconfig with the correct endpoint:\n\n```shell\ntalosctl config endpoint --talosconfig .talosconfig/talosconfig talos-epimelitis.fritz.box\n```\n\nNow apply the configuration to the node:\n\n```shell\ntalosctl apply-config --insecure --nodes talos-epimelitis.fritz.box  --file .talosconfig/controlplane.yaml\n```\n\nAfter a while (observe the `virsh console talos` output), bootstrap etcd:\n\n```shell\ntalosctl bootstrap --talosconfig .talosconfig/talosconfig --nodes talos-epimelitis.fritz.box\n```\n\nLastly, configure your kubeconfig file:\n\n```shell\ntalosctl kubeconfig --talosconfig .talosconfig/talosconfig --nodes talos-epimelitis.fritz.box\n```\n\nSwitch the the new context:\n\n```shell\nkubectl config use-context admin@talos-epimelitis\n```\n\nThen apply a patch for the metric server to avoid timeout related issues:\n\n```shell\nkubectl -k metric-server\n```\n\n[Local Path Provisioner]: https://www.talos.dev/v1.6/kubernetes-guides/configuration/local-storage/#local-path-provisioner\n\n## 3. The part where we use Kubernetes\n\nChange into the [`cluster/`](cluster/) directory and appy the kustomizations, or:\n\n```shell\nkubectl kustomize --enable-helm cluster | kubectl apply -f -\n```\n\nNote that you'll need `kubectl kustomize` due to Helm. As of writing this, `kubectl apply -k` will not do.\n\n### Storage, Ingress, Load balancing\n\nThe system foundation consists of these parts:\n\n- [Local Path Provisioner] serves our `PersistentVolumeClaims` from the SD card\n- [MetalLB] assignes IP addresses to Load Balancers, both in our home network and in a dedicated one.\n- [Nginx Ingress Controller] handles the `Ingress` resources\n\nWith this setup we could deploy our workloads, have them persisted and make them\nexternally available (give or take a static route setup on your home network's Router).\nWhen requests come in over the network bridge, MetalLB takes care of routing them\nto the correct workload.\n\nNote that by virtue of our Talos setup we already have\n\n- [Kubelet Serving Cert Approver] for accepting certificate signing requests for system components, and\n- [Kubernetes Metrics Server] for node and pod metrics.\n\nDue to some timeout related issues the already installed Metrics Server will be\npatched with a slightly more relaxed one.\n\n[Kube Serving Cert Approver]: https://github.com/alex1989hu/kubelet-serving-cert-approver\n[Kubernetes Metrics Server]: https://github.com/kubernetes-sigs/metrics-server\n\n### Improved DNS\n\nWe can do one better:\n\n- [Pi-Hole] is used as a DNS Server (and it _also_ filters Ads). With the power of MetalLB\n  we give it an address in our home network.\n- [ExternalDNS] announces Ingress host names to an external DNS - in this case, Pi-Hole.  It'll then be reachable as `http://pi-hole.home`.\n\nWith this, all we need to do is tell our Router to use our Pi-Hole as a DNS server.\nWhatever Ingress we deploy now, ExternalDNS will announce it to Pi-Hole and thus\nevery device on our home network can access the Kubernetes-run workload by name.\n\n### Home Assistant and Sensors\n\nTherefore and lastly,\n\n- [Mosquitto] is our MQTT Broker for Smart Home appliances. I re-soldered and flashed\n  some Sonoff Slampher E27 sockets with Tasmota, and they'll talk to Mosquitto.\n- [Home Assistant] itself. It'll be reachable as `http://home-assistant.home`.\n\nHome Assistant is deployed using a `LoadBalancer` on the home network in order for\nit to pick up UDP packets in that subnet.\n\n[Local Path Provisioner]: https://github.com/rancher/local-path-provisioner\n[MetalLB]: https://metallb.universe.tf/\n[Nginx Ingress Controller]: https://github.com/kubernetes/ingress-nginx\n[Pi-Hole]: https://pi-hole.net/\n[ExternalDNS]: https://github.com/kubernetes-sigs/external-dns\n[Mosquitto]: https://mosquitto.org/\n[Home Assistant]: https://www.home-assistant.io/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsunsided%2Fepimelitis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsunsided%2Fepimelitis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsunsided%2Fepimelitis/lists"}