{"id":29667918,"url":"https://github.com/anokfireball/homelab-as-code","last_synced_at":"2026-03-03T20:04:20.003Z","repository":{"id":246644671,"uuid":"821732409","full_name":"anokfireball/homelab-as-code","owner":"anokfireball","description":"IaC for going from empty disks to running HA homelab cluster managed using GitOps within 2(-ish) clicks","archived":false,"fork":false,"pushed_at":"2026-02-27T12:55:08.000Z","size":3936,"stargazers_count":8,"open_issues_count":22,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-27T12:56:17.435Z","etag":null,"topics":["ansible","cloud-init","devops","flux","gitops","helm","homelab","k8s-at-home","kubernetes","netboot","pxe","selfhosted"],"latest_commit_sha":null,"homepage":"","language":"Jinja","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anokfireball.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-06-29T09:24:54.000Z","updated_at":"2026-02-27T12:53:34.000Z","dependencies_parsed_at":"2024-12-24T19:15:21.005Z","dependency_job_id":"458901f2-31f0-4f2a-9863-59ba11c5256f","html_url":"https://github.com/anokfireball/homelab-as-code","commit_stats":null,"previous_names":["c0nsultant/homelab-as-code","anokfireball/homelab-as-code"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/anokfireball/homelab-as-code","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anokfireball%2Fhomelab-as-code","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anokfireball%2Fhomelab-as-code/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anokfireball%2Fhomelab-as-code/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anokfireball%2Fhomelab-as-code/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anokfireball","download_url":"https://codeload.github.com/anokfireball/homelab-as-code/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anokfireball%2Fhomelab-as-code/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30057645,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-03T18:21:05.932Z","status":"ssl_error","status_checked_at":"2026-03-03T18:20:59.341Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["ansible","cloud-init","devops","flux","gitops","helm","homelab","k8s-at-home","kubernetes","netboot","pxe","selfhosted"],"created_at":"2025-07-22T17:02:50.164Z","updated_at":"2026-03-03T20:04:19.996Z","avatar_url":"https://github.com/anokfireball.png","language":"Jinja","readme":"\u003cdiv align=\"center\"\u003e\n\n![Homelab-as-Code logo](logo.png \"Homelab-as-Code logo\")\n\n\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/k8s-homelab_loadbalancer-[http]/health/badge.svg\" alt=\"Cluster Health\"\u003e\n\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/k8s-homelab_loadbalancer-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/k8s-homelab_loadbalancer-[http]/uptimes/30d/badge.svg\" alt=\"Cluster Uptime\"\u003e\u003c/a\u003e\n\n\u003ch3\u003eBootstrap and GitOps sources to get my baremetal homelab set up consistently.\u003c/h3\u003e\n\n\u003c/div\u003e\n\n# 🏡 Homelab-as-Code (HaC™)\n\nThis repository was born out of the need to better manage an ever-growing homelab environment.\nAfter starting with a simple single-node Docker Compose setup, the increasing number of services began to make maintenance and updates more challenging.\n\nAs the complexity grew, it became clear that a more structured, Infrastructure-as-Code approach was needed to:\n- keep configurations versioned and thus better documented\n- make deployments more consistently repeatable and reliable\n- simplify the process of adding new services without losing track of the overall state\n- enable easier backup and disaster recovery that is centrally managed\n- provide better scalability and resilience beyond a single node\n\nI decided to take this opportunity to properly learn Kubernetes hands-on, embracing the complexity and \"feeling the pain\" that comes with it rather than _just_ having the theoretical knowledge.\nThis repo serves as both documentation of my setup as well as a real-world learning experience in managing infrastructure that I rely upon as code.\n\nPS: This setup is mature enough to be girlfriend-approved. 😉\n\n## 🔰 Overview\n\nAt the highest possible level, this repo and HaC workflow consists of three parts:\n- [cloud-init](cloud-init) contains the stage 1 bootstrapping for the cluster nodes.\n  This includes only the very basic OS-level configuration required for the other stages of this workflow.\n  The contained shell script creates all files required to install the OS via [network boot](https://ubuntu.com/server/docs/how-to-netboot-the-server-installer-on-amd64) and without user interaction.\n  _Triggering_ the network-boot installation is out-of-scope for the moment.\n  After completion of the cloud-init [autoinstall](https://canonical-subiquity.readthedocs-hosted.com/en/latest/intro-to-autoinstall.html), all nodes reboot and are ready to accept SSH connections.\n- [ansible/cluster](ansible/cluster) contains the stage 2 system configuration for the cluster nodes.\n  This includes a range of tasks including power management, networking setup, and most importantly bootstrapping the kubernetes cluster using [kubeadm](https://kubernetes.io/docs/reference/setup-tools/kubeadm/).\n  The included Ansible playbook performs the required tasks on the nodes via SSH and a dedicated Ansible user created in the previous step.\n  After completion of this stage, the Kubernetes cluster is set up with [HA](https://kube-vip.io/) control planes, joined worker nodes, dual-stack [CNI](https://www.tigera.io/tigera-products/calico/), almost working [OIDC authn](https://dexidp.io/), and last but not least a bootstrapped [GitOps](https://fluxcd.io/) setup that is ready to start reconciling.\n- [flux](flux) contains the final stage 3 GitOps cluster configuration.\n  This includes everything running _inside_ kubernetes in the cluster and ranges from basic system infrastructure like [load balancer](https://metallb.io/), [ingress](https://kubernetes.github.io/ingress-nginx/), and [CSI](https://longhorn.io/) to more user-style applications such as [password manager](https://bitwarden.com/) and [file management](https://nextcloud.com/) apps.\n  The included Flux kustomizations are automatically installed and/or reconciled on the cluster without* user interaction.\n  This process is staggered since there is an inherent dependency between some of the components.\n  After completion of this stage, the cluster is fully set up and ready for use.\n\nIn addition to the core homelab IaC, there is one more loosely related stage:\n- [ansible/gateway](ansible/gateway) contains system configuration for a remotely hosted ingress gateway used to expose select services publicly.\n  This includes setup of [GitOps](https://docs.ansible.com/ansible/latest/cli/ansible-pull.html) outside of Kubernetes, [mesh networking](https://tailscale.com/) outside of Kubernetes, and a [reverse proxy](https://caddyserver.com/) with ACME support.\n  The included Ansible playbook performs the required tasks on a manually provisioned gateway via SSH and a dedicated Ansible user also created manually.\n  After completion of this stage, the public gateway is set up and ready to reverse proxy connections to the cluster.\n\n## 📐 Tech Stack\n\n| Component                                                            | Purpose                                | Notes                                                                              |\n| -------------------------------------------------------------------- | -------------------------------------- | ---------------------------------------------------------------------------------- |\n| [Ubuntu Server 24.04](https://ubuntu.com/server)                     | Base Operating System                  |                                                                                    |\n| [cloud-init](https://cloud-init.io/)                                 | Headless OS Installation               | see [cloud-init/README.md](cloud-init/README.md)                                   |\n| [Ansible](https://ansible.com/)                                      | OS Configuration                       |                                                                                    |\n| [kubeadm](https://kubernetes.io/docs/reference/setup-tools/kubeadm/) | k8s _Distribution_ / Install Mechanism | stacked HA controlplanes                                                           |\n| [containerd](https://containerd.io/)                                 | OCI Runtime                            |                                                                                    |\n| [Calico](https://www.tigera.io/tigera-products/calico/)              | CNI                                    | dual-stack nodes and services                                                      |\n| [kube-vip](https://kube-vip.io/)                                     | Virtual IP for controlplane Nodes      | used in L2/ARP mode                                                                |\n| [Flux2](https://fluxcd.io)                                           | GitOps Automation inside the Cluster   |                                                                                    |\n| [SOPS](https://getsops.io/)                                          | Secrets Management                     | [age](https://age-encryption.org/) rather than PGP, but not any more user-friendly |\n\n## 📱 Applications\n\n### 🤖 System-Level\n\n\u003ctable\u003e\n    \u003ctr\u003e\n        \u003cth\u003e\u003c/th\u003e\n        \u003cth\u003eName\u003c/th\u003e\n        \u003cth\u003ePurpose\u003c/th\u003e\n        \u003cth\u003eNotes\u003c/th\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/metallb/metallb/refs/heads/main/website/static/images/logo/metallb-blue.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://metallb.io/\"\u003emetallb\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eCloud-Native Service LoadBalancer\u003c/td\u003e\n        \u003ctd\u003eused in L2/ARP mode, so only VIP rather than true LB\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/kubernetes-sigs/external-dns/refs/heads/master/docs/img/external-dns.png\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://kubernetes-sigs.github.io/external-dns/\"\u003eexternal-dns\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eDNS Management Automation\u003c/td\u003e\n        \u003ctd\u003esplit-horizon realized using \u003ca href=\"https://github.com/crutonjohn/external-dns-opnsense-webhook\"\u003eopnsense webhook\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/cert-manager/cert-manager/refs/heads/master/logo/logo.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://cert-manager.io/\"\u003ecert-manager\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eAutomated Certificate Management\u003c/td\u003e\n        \u003ctd\u003eLet's Encrypt via ACME DNS\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/nginx/nginx.org/refs/heads/main/img/ingress_logo.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://kubernetes.github.io/ingress-nginx/\"\u003eingress-nginx\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eIngress Controller\u003c/td\u003e\n        \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/kyverno/kyverno/refs/heads/main/img/logo.png\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://kyverno.io/\"\u003eKyverno\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003ePolicy Engine\u003c/td\u003e\n        \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/spegel-org/website/refs/heads/main/static/favicon.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://spegel.dev/\"\u003eSpegel\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eCluster-Internal P2P Container Image Distribution\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://spegel.dev/docs/guides/updating-latest-tag/\"\u003ebasically mandates\u003c/a\u003e the use of digests or good pinning\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/longhorn/website/refs/heads/master/static/img/logos/longhorn-icon-color.png\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://longhorn.io/\"\u003elonghorn\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eCloud-Native Distributed Block Storage CSI\u003c/td\u003e\n        \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://cdn.jsdelivr.net/gh/selfhst/icons/svg/truenas-core.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://github.com/democratic-csi/democratic-csi\"\u003edemocratic-csi\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eCSI for Common External Storage Systems\u003c/td\u003e\n        \u003ctd\u003eusing the freenas-nfs implementation\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/renovatebot/renovate/refs/heads/main/docs/usage/assets/images/logo.png\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://www.mend.io/renovate/\"\u003eRenovate Bot\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eDependency Update Automation\u003c/td\u003e\n        \u003ctd\u003eused for multiple repos, not just this one\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/k8up-io/k8up/refs/heads/master/docs/modules/ROOT/assets/images/k8up-logo-square.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://k8up.io/\"\u003ek8up\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eCloud-Native Backup/Restore\u003c/td\u003e\n        \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg.github.io/refs/heads/main/assets/images/hero_image.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://cloudnative-pg.io/\"\u003eCloudNativePG\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eCloud-Native PostgreSQL Operator\u003c/td\u003e\n        \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/grafana/grafana/refs/heads/main/public/img/grafana_icon.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://grafana.com/grafana/\"\u003eGrafana\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eMonitoring and Observability\u003c/td\u003e\n        \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/prometheus/prometheus/refs/heads/main/documentation/images/prometheus-logo.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://prometheus.io/\"\u003ePrometheus\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eMetrics Aggregation and Storage\u003c/td\u003e\n        \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/grafana/loki/refs/heads/main/docs/sources/logo.png\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://grafana.com/loki/\"\u003eLoki\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eLog Aggregation and Storage\u003c/td\u003e\n        \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/AnalogJ/scrutiny/refs/heads/master/webapp/frontend/src/assets/images/logo/scrutiny-logo-dark.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://github.com/AnalogJ/scrutiny\"\u003eScrutiny\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eDrive Health Monitoring\u003c/td\u003e\n        \u003ctd\u003evia SMART\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg height=\"32\" width=\"32\" src=\"https://raw.githubusercontent.com/kubernetes-sigs/descheduler/refs/heads/master/assets/logo/descheduler-stacked-color.png\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://sigs.k8s.io/descheduler\"\u003edescheduler\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003ePod Eviction for Node Balancing\u003c/td\u003e\n        \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/stakater/Reloader/refs/heads/master/theme_override/resources/assets/images/favicon.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://docs.stakater.com/reloader/\"\u003ereloader\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eHot-Reload for ALL Workloads\u003c/td\u003e\n        \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/dexidp/website/refs/heads/main/static/img/logos/dex-glyph-color.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://dexidp.io/\"\u003eDex\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eOIDC Provider\u003c/td\u003e\n        \u003ctd\u003eused for API server authentication\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/tailscale/tailscale/refs/heads/main/client/web/src/assets/icons/tailscale-icon.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://github.com/tailscale/tailscale/tree/main/cmd/k8s-operator\"\u003eTailscale\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eOverlay Mesh VPN Operator\u003c/td\u003e\n        \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://kubernetes-sigs.github.io/metrics-server/\"\u003emetrics-server\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eMetrics API\u003c/td\u003e\n        \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/FairwindsOps/goldilocks/refs/heads/master/pkg/dashboard/assets/images/favicon.ico\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://goldilocks.docs.fairwinds.com/\"\u003eGoldilocks\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eResource Recommendation Engine\u003c/td\u003e\n        \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler\"\u003eVertical Pod Autoscaler\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eWorkload Resource Scaler\u003c/td\u003e\n        \u003ctd\u003eused exclusively for Goldilocks recommendations\u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/table\u003e\n\n### 👨‍💻 User-Level\n\n\u003ctable\u003e\n    \u003ctr\u003e\n        \u003cth\u003e\u003c/th\u003e\n        \u003cth\u003eName\u003c/th\u003e\n        \u003cth\u003ePurpose\u003c/th\u003e\n        \u003cth\u003eNotes\u003c/th\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/pi-hole/docs/refs/heads/master/docs/images/logo.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://pi-hole.net/\"\u003ePi-hole\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eFiltering DNS Proxy\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_pi-hole-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_pi-hole-[http]/uptimes/30d/badge.svg\" alt=\"Pi-hole Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/nextcloud/server/refs/heads/master/core/img/favicon.png\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://nextcloud.com/\"\u003eNextcloud\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eFile Storage and Management\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_nextcloud-[http---public]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_nextcloud-[http---public]/uptimes/30d/badge.svg\" alt=\"Nextcloud Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/dani-garcia/vaultwarden/refs/heads/main/resources/vaultwarden-icon.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://github.com/dani-garcia/vaultwarden\"\u003eVaultwarden\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eAPI-compatible Password Manager\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_bitwarden-[http---public]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_bitwarden-[http---public]/uptimes/30d/badge.svg\" alt=\"Vaultwarden Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/immich-app/immich/refs/heads/main/web/static/favicon.ico\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://immich.app/\"\u003eImmich\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003ePhoto/Video Storage and Management\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_immich-[http---public]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_immich-[http---public]/uptimes/30d/badge.svg\" alt=\"Immich Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/refs/heads/dev/docs/assets/favicon.png\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://docs.paperless-ngx.com/\"\u003ePaperless-ngx\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eDocument Management System\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_paperless-ngx-[http---public]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_paperless-ngx-[http---public]/uptimes/30d/badge.svg\" alt=\"Paperkess-ngx Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/firefly-iii/firefly-iii/refs/heads/main/public/favicon.ico\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://www.firefly-iii.org/\"\u003eFirefly III\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003ePersonal Finance Manager\u003c/td\u003e\n        \u003ctd\u003eincluding \u003ca href=\"https://github.com/firefly-iii/data-importer\"\u003eimporter\u003c/a\u003e and \u003ca href=\"https://github.com/cioraneanu/firefly-pico\"\u003epico\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_firefly-iii-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_firefly-iii-[http]/uptimes/30d/badge.svg\" alt=\"Firefly III Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/TomBursch/kitchenowl/refs/heads/main/kitchenowl/web/favicon.ico\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://kitchenowl.org/\"\u003eKitchenOwl\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eRecipe and Grocery Manager\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_kitchenowl-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_kitchenowl-[http]/uptimes/30d/badge.svg\" alt=\"KitchenOwl Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/gethomepage/homepage/refs/heads/dev/public/homepage.ico\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gethomepage.dev/\"\u003eHomepage\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eApplication Dashboard\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_homepage-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_homepage-[http]/uptimes/30d/badge.svg\" alt=\"Homepage Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/FreshRSS/freshrss.org/refs/heads/main/static/favicon.ico\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://freshrss.org/index.html\"\u003eFresh-RSS\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eRSS Aggregator\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_fresh-rss-[http---public]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_fresh-rss-[http---public]/uptimes/30d/badge.svg\" alt=\"Fresh-RSS Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/RSS-Bridge/rss-bridge/refs/heads/master/static/favicon.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://rss-bridge.org/\"\u003eRSS-Bridge\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eUnofficial RSS Feeds of ANY Source\u003c/td\u003e\n        \u003ctd\u003e\u003ci\u003eany\u003c/i\u003e as long as you know some PHP\u003cbr\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_rss-bridge-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_rss-bridge-[http]/uptimes/30d/badge.svg\" alt=\"RSS-Bridge Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://d21buns5ku92am.cloudfront.net/26628/documents/54546-1717072325-sc-logo-cloud-black-7412d7.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://github.com/anokfireball/soundcloud-scraper\"\u003eSoundcloud Scraper\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eParser + Webhook for my Soundcloud Feed\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_soundcloud-scraper-[push]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_soundcloud-scraper-[push]/uptimes/30d/badge.svg\" alt=\"Soundcloud Scraper Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/Stirling-Tools/Stirling-PDF/refs/heads/main/docs/stirling.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://www.stirlingpdf.com/\"\u003eStirling PDF\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eSwiss-Army Knife for PDFs\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_stirling-pdf-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_stirling-pdf-[http]/uptimes/30d/badge.svg\" alt=\"Stirling PDF Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/excalidraw/excalidraw/refs/heads/master/public/favicon.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://excalidraw.com/\"\u003eExcalidraw\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eVirtual Whiteboard\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_excalidraw-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_excalidraw-[http]/uptimes/30d/badge.svg\" alt=\"Excalidraw Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://cdn.jsdelivr.net/gh/selfhst/icons/svg/ubiquiti-unifi.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://ui.com/consoles\"\u003eUniFi Network Application\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eAP Administration and Management\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_unifi-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_unifi-[http]/uptimes/30d/badge.svg\" alt=\"UniFi Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://cdn.jsdelivr.net/gh/selfhst/icons/svg/opnsense-v1.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://github.com/anokfireball/opnsense-ipv6-prefix-update\"\u003eOPNsense Prefix Updater\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eUpdate Network Configs with Latest Non-Static IPv6\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/petrus_opnsense-prefix-update-[push]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/petrus_opnsense-prefix-update-[push]/uptimes/30d/badge.svg\" alt=\"OPNsense Prefix Updater Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/n8n-io/n8n-docs/refs/heads/main/docs/_images/favicon.ico\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://n8n.io/\"\u003en8n\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eWorkflow Automation\u003c/td\u003e\n        \u003ctd\u003efreemium/open core\u003cbr\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_n8n-[http---public]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_n8n-[http---public]/uptimes/30d/badge.svg\" alt=\"n8n Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/jellyfin/jellyfin.org/refs/heads/master/static/images/icon-transparent.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://jellyfin.org/\"\u003eJellyfin\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eMedia Streaming and Management\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_jellyfin-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_jellyfin-[http]/uptimes/30d/badge.svg\" alt=\"Jellyfin Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/qdm12/gluetun/refs/heads/master/doc/logo.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://github.com/qdm12/gluetun/\"\u003eGluetun\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eVPN Gateway\u003c/td\u003e\n        \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/qbittorrent/qBittorrent-website/refs/heads/master/src/favicon.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://www.qbittorrent.org/\"\u003eqBittorrent\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eTorrent Client\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_qbittorrent-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_qbittorrent-[http]/uptimes/30d/badge.svg\" alt=\"qBittorrent Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/sabnzbd/sabnzbd/refs/heads/develop/interfaces/Config/templates/staticcfg/images/logo-small.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://sabnzbd.org/\"\u003eSABnzbd\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eUsenet Client\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_sabnzbd-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_sabnzbd-[http]/uptimes/30d/badge.svg\" alt=\"SABnzbd Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/Prowlarr/Prowlarr/refs/heads/develop/Logo/Prowlarr.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://prowlarr.com/\"\u003eProwlarr\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eTorrent \u0026 Usenet Indexer Engine\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_prowlarr-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_prowlarr-[http]/uptimes/30d/badge.svg\" alt=\"Prowlarr Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/Radarr/Radarr/refs/heads/develop/Logo/Radarr.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://radarr.video/\"\u003eRadarr\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eMovie Management\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_radarr-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_radarr-[http]/uptimes/30d/badge.svg\" alt=\"Radarr Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/Sonarr/Sonarr/refs/heads/develop/Logo/Sonarr.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://sonarr.tv/\"\u003eSonarr\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eTV Show Management\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_sonarr-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_sonarr-[http]/uptimes/30d/badge.svg\" alt=\"Sonarr Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/Lidarr/Lidarr/refs/heads/develop/Logo/Lidarr.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://lidarr.audio/\"\u003eLidarr\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eMusic Management\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_lidarr-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_lidarr-[http]/uptimes/30d/badge.svg\" alt=\"Lidarr Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003cimg width=\"32\" src=\"https://raw.githubusercontent.com/FlareSolverr/FlareSolverr/refs/heads/master/resources/flaresolverr_logo.svg\"\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://github.com/FlareSolverr/FlareSolverr\"\u003eFlareSolverr\u003c/a\u003e\u003c/td\u003e\n        \u003ctd\u003eCloudflare Protection Bypass\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://gatus.kthxbye.cyou/endpoints/services_flaresolverr-[http]\"\u003e\u003cimg src=\"https://gatus.kthxbye.cyou/api/v1/endpoints/services_flaresolverr-[http]/uptimes/30d/badge.svg\" alt=\"FlareSolverr Uptime\"\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/table\u003e\n\n## ☁️ Cloud Dependencies\n\nWhile the ultimate goal is to have as self-sufficient of a setup as possible, some external services are still required for proper operation.\n\n| Service                                   | Purpose                                  | Notes                                               |\n| ----------------------------------------- | ---------------------------------------- | --------------------------------------------------- |\n| [GitHub](https://github.com/)             | Git Repository Hosting, GitOps Source    |                                                     |\n| [INWX](https://www.inwx.de/)              | Domain Registrar                         |                                                     |\n| [Cloudflare](https://www.cloudflare.com/) | Public DNS Auth Hosting                  |                                                     |\n| [Let's Encrypt](https://letsencrypt.org/) | SSL Certificates                         |                                                     |\n| [netcup](https://www.netcup.de/)          | Public Reverse-Proxy for Select Services |                                                     |\n| [BackBlaze](https://www.backblaze.com/)   | Cloud Storage for Backups                | the \"3\" in 3-2-1 for the really important data      |\n| [TailScale](https://tailscale.com/)       | Overlay Mesh VPN                         | used for split-horizon and a direct route back home |\n| VPN Provider                              | VPN Gateway                              | unassociated external IP for all the Linux ISOs     |\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanokfireball%2Fhomelab-as-code","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanokfireball%2Fhomelab-as-code","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanokfireball%2Fhomelab-as-code/lists"}