{"id":18929110,"url":"https://github.com/jwillikers/home-lab-helm","last_synced_at":"2025-04-15T14:31:59.927Z","repository":{"id":202769679,"uuid":"597516248","full_name":"jwillikers/home-lab-helm","owner":"jwillikers","description":"Kubernetes YAML and Podman systemd configuration files for running my services at home","archived":false,"fork":false,"pushed_at":"2024-08-11T20:18:27.000Z","size":547,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-08-12T21:04:23.588Z","etag":null,"topics":["bitcoin-core","caddy","certbot","eclipse-mosquitto","esphome","gitea","homelab","homelab-setup","icinga","jellyfin","kubernetes","miniflux","minio","nextcloud","nginx","omada-controller","podman","systemd","vaultwarden"],"latest_commit_sha":null,"homepage":"","language":"Shell","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/jwillikers.png","metadata":{"files":{"readme":"README.adoc","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":"2023-02-04T19:38:07.000Z","updated_at":"2024-08-11T20:18:30.000Z","dependencies_parsed_at":"2024-01-15T16:23:13.027Z","dependency_job_id":"0d303ab9-e4a4-409b-8154-22c19a6dfe6d","html_url":"https://github.com/jwillikers/home-lab-helm","commit_stats":null,"previous_names":["jwillikers/home-lab-helm"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwillikers%2Fhome-lab-helm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwillikers%2Fhome-lab-helm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwillikers%2Fhome-lab-helm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwillikers%2Fhome-lab-helm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jwillikers","download_url":"https://codeload.github.com/jwillikers/home-lab-helm/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223677329,"owners_count":17184445,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["bitcoin-core","caddy","certbot","eclipse-mosquitto","esphome","gitea","homelab","homelab-setup","icinga","jellyfin","kubernetes","miniflux","minio","nextcloud","nginx","omada-controller","podman","systemd","vaultwarden"],"created_at":"2024-11-08T11:30:10.626Z","updated_at":"2024-11-08T11:30:11.583Z","avatar_url":"https://github.com/jwillikers.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"= Home Lab Helm\nJordan Williams \u003cjordan@jwillikers.com\u003e\n:experimental:\n:icons: font\n:keywords: container helm k8s kubernetes linux podman systemd\nifdef::env-github[]\n:tip-caption: :bulb:\n:note-caption: :information_source:\n:important-caption: :heavy_exclamation_mark:\n:caution-caption: :fire:\n:warning-caption: :warning:\nendif::[]\n\nKubernetes YAML and https://podman.io/[Podman] systemd configuration files for running my services at home.\n\nEverything is meant to be run rootless via Podman.\nThe configuration is intended for systems using https://selinuxproject.org/page/Main_Page[SELinux].\nhttps://fedoraproject.org/iot/[Fedora IoT] is the current OS used for deployment.\n\nhttps://caddyserver.com/[Caddy] is used on per-machine basis as a reverse-proxy to manage connections between the containers and everything external to the host.\nCaddy configuration files for these services are stored in the https://codeberg.org/jwillikers/caddy-config[Caddy Config] repository.\nAnything that allows using a choice of database uses https://www.postgresql.org/[PostgreSQL].\n\n== Organization\n\nWhy use Kubernetes YAML?\nGood question.\nIt's standard.\nKubernetes YAML isn't the equivalent of Docker Compose, but it accomplishes many of the same goals while being a common standard specification.\nIt's a bit trickier to learn, but it also supports _pods_, which are an incredibly powerful construct when orchestrating containers.\nPlus, you can more easily scale up from Podman to full Kubernetes implementations.\n\nAs mentioned, this repository is meant to be run via Podman.\nThe reason for this is approach is to reduce the overhead and complexity required for a full Kubernetes deployment.\nA minimalist approach like this makes a lot of sense for a self-hosted home lab which likely doesn't benefit as much from the redundancy and scalability provided by Kubernetes.\nThat said, I still kind of want those features and very well might migrate to a real Kubernetes deployment in the future.\n\nTo address scalability, this repository is organized in a modular fashion by service.\nSince Podman is used instead of a true Kubernetes implementation, the distribution of services across servers must be handled manually.\nIndividual services can be deployed by symlinking the desired systemd files for the service to the appropriate directory to activate them.\nThis configuration typically requires a dedicated reverse-proxy on each device which proxies connections from the host to the internal Podman networks on which the services are running.\nConfigurations for the reverse-proxies are provided in a similar where individual configurations for each service can be activated individually.\n\nWhat about templates?\nYeah, that comes back to minimalism and simplicity.\nI haven't figured out how I want to go about centralizing the configuration so that host names and what not are managed across all of the various configuration files.\nThat's something that might just be addressed by moving things to a full Kubernetes configuration.\nFor now, things are simply just hard-coded, which makes the configuration really easy to read at least.\n\nI use OVH to manage public DNS entries for my domain.\nI don't make any services accessible to the public internet, which requires me to use the DNS-01 ACME challenge to automatically provision TLS certificates.\nPlugins exist which automate this process for OVH.\n\nTo simplify configuration and make it easy to move services to different devices, the DNS entries for each service use CNAME records which point to the host device.\nTwo different domains are typically published for each service, one at `jwillikers.io` and another at `lan.jwillikers.io`.\nThe former is accessible via Tailscale from both inside and outside the LAN.\nThe latter is only available on the LAN.\nTLS certificates are acquired for both domains, allowing the use of TLS to access services over Tailscale and the local network.\n\n[TIP]\n====\nDon't mess with self-signed certificates.footnote:[_Everything_ will break.]\n====\n\nTailscale is used to secure connections between individual devices while also allowing external connections to services.\nThis requires no port-forwarding at the router level and is free up to a lot of devices.\n\n[TIP]\n====\nDisable key-expiry to reduce confusing troubleshooting sessions.\nYou can manually replace keys instead without surprises.\n====\n\nStorage is managed via persistent volume claims and host mounts.\nThe primary difference in how they are used is based primarily on whether or not the data for the volume should be backed up.\nPersistent volume claims are used for ephemeral data that is _not_ backed up, which includes things like caches and less important persistent data.\nHost mounts are used for mounting in configuration files provided by Git repositories, which are things under the `~/Projects` directory, and for important data that should be backed up, which resides under the `~/container-volumes` directory.\n\nBoth persistent volume claims and mounted volumes in the `~/container-volumes` directory follow a consistent naming scheme that mirrors the name of the Podman containers.\nThese volumes are named according to the pod and container to which they belong.\nThe naming scheme is `pod-container-name`, where dashes separate the different components.\nAs an example, the data directory for the vaultwarden container in the vaultwarden pod is named `vaultwarden-vaultwarden-data`.\nThe data directory for the PostgreSQL container in the pod is named `vaultwarden-postgresql-data`.\nPods with a single container may omit the container name for brevity.\n\nFor my backups, which use Btrbk, the `~/container-volumes` directory is a Btrfs subvolume.\nThis allows for fast, consistent snapshots which are easily backed up to other devices using incremental Btrfs send and receive commands.\nHourly backups are _extremely_ helpful.\nIn order to reduce storage consumption, only the volumes I find critical for restoration are mounted from the `~/container-volumes` directory.\nFor example, I don't mind losing the InfluxDB database, so that uses a persistent volume claim instead.\nSo, be sure to adjust the volumes according to your own needs.\nMy Btrbk backup configuration can be found in the https://codeberg.org/jwillikers/btrbk-config[btrbk Config] directory if you're interested.\nComprehensive backup strategies should probably incorporate database dumps and copies of the data stored in S3-compatible object storage like MinIO.\n\n== Create a Dedicated User\n\nThese services are meant to be run under a user account dedicated to running rootless Podman containers.\nThis should be a system account and should use the same user id and group id across systems to simplify permissions.\n\n. On rpm-ostree systems, the _systemd-journal_ group does not exist in the `/etc/group`, so it must be added.\n+\n[,sh]\n----\necho $(getent group systemd-journal) | sudo tee -a /etc/group\n----\n\n. Create a `core` system group.\n+\n[,sh]\n----\nsudo groupadd --gid 818 --system core\n----\n\n. Create a primary user account named `core` for running containers with Podman.\n+\n--\n[,sh]\n----\nsudo useradd \\\n  --add-subids-for-system \\\n  --btrfs-subvolume-home \\\n  --comment \"Primary account for running containers\" \\\n  --create-home \\\n  --gid core \\\n  --groups systemd-journal \\\n  --shell /usr/sbin/nologin \\\n  --system \\\n  --uid 818 \\\n  core\n----\n\n[TIP]\n====\nThe `--root` flag can be used to create this user in the given chroot environment.\n====\n--\n\n. Verify that the new `core` user has entries in `/etc/subuid` and `/etc/subgid`.\nIf for some reason, there are no subuid and subgid ranges for the user, follow these steps.\nI don't know why this happens, but it does sometimes.\n+\n[NOTE]\n====\nThese commands use the fish shell because I can never remember how to math in Bash.footnote:[Or anything else in Bash for that matter.]\n====\n\n.. Calculate the first value for the next subuid allotment.\n+\n--\nIf `/etc/subuid` is empty, use 100,000 as the initial value.\n\n[,sh]\n----\nset new_subuid 100000\n----\n\nOtherwise, use the following function to calculate the next available subuid range.\n\n[,sh]\n----\nset new_subuid (math (tail -1 /etc/subuid | awk -F \":\" '{print $2}') + 65536)\n----\n--\n\n.. Calculate the first value for the next subuid allotment.\n+\n--\nIf `/etc/subgid` is empty, use 100,000 as the initial value.\n\n[,sh]\n----\nset new_subgid 100000\n----\n\nOtherwise, use the following function to calculate the next available subgid range.\n\n[,sh]\n----\nset new_subgid (math (tail -1 /etc/subgid | awk -F \":\" '{print $2}') + 65536)\n----\n--\n\n.. Configure the `core` user with the calculated subuid and subgid ranges.\n+\n[,sh]\n----\nsudo usermod \\\n  --add-subuids $new_subuid-(math $new_subuid + 65535) \\\n  --add-subgids $new_subgid-(math $new_subgid + 65535) \\\n  core\n----\n\n. Automatically start the core user's session.\n+\n[,sh]\n----\nsudo loginctl enable-linger core\n----\n\n. Open a shell as the `core` user with the following command.\nI prefer the fish shell, so I use that here, but substitute Bash, ZSH, etc. per your preference.\n+\n[,sh]\n----\nsudo -H -u core fish -c 'cd; fish'\n----\n\n. Configure the `XDG_RUNTIME_DIR` environment variable for the user in order for sockets to be found correctly.\n+\n[,sh]\n----\nset -Ux XDG_RUNTIME_DIR /run/user/(id -u)\n----\n\n. To get automatic updates, enable Podman's automatic update timer for the user.\n+\n[,sh]\n----\nsystemctl --user enable --now podman-auto-update.timer\n----\n\n== Usage\n\n. Open a shell as the system user account for running the containers.\n+\n[,sh]\n----\nsudo -H -u core fish -c 'cd; fish'\n----\n\n. Create the `~/Projects` directory.\n+\n[,sh]\n----\nmkdir ~/Projects\n----\n\n. Clone this repository to the `~/Projects` directory.\nThe configurations rely on this repository being at this location.\nSorry.\n+\n[,sh]\n----\ngit -C ~/Projects clone https://codeberg.org/jwillikers/home-lab-helm.git\n----\n\n. Now follow the instructions in the _README.adoc_ files for the desired services.\n\n== Services\n\n* \u003c\u003cbitcoin-core/README.adoc,Bitcoin Core\u003e\u003e\n* \u003c\u003ccaddy/README.adoc,Caddy\u003e\u003e\n* \u003c\u003ccertbot/README.adoc,Certbot\u003e\u003e\n* \u003c\u003ceclipse-mosquitto/README.adoc,Eclipse Mosquitto\u003e\u003e\n* \u003c\u003cesphome/README.adoc,ESPHome\u003e\u003e\n* \u003c\u003cforgejo/README.adoc,Forgejo\u003e\u003e\n* \u003c\u003cicinga/README.adoc,Icinga\u003e\u003e\n* \u003c\u003cimmich/README.adoc,Immich\u003e\u003e\n* \u003c\u003cinfluxdb/README.adoc,InfluxDB\u003e\u003e\n* \u003c\u003cjellyfin/README.adoc,Jellyfin\u003e\u003e\n* \u003c\u003cMediaMTX/README.adoc,MediaMTX\u003e\u003e\n* \u003c\u003cminiflux/README.adoc,Miniflux\u003e\u003e\n* \u003c\u003cminio/README.adoc,MinIO\u003e\u003e\n* \u003c\u003cnextcloud/README.adoc,Nextcloud\u003e\u003e\n* \u003c\u003cnginx/README.adoc,NGINX\u003e\u003e\n* \u003c\u003comada-controller/README.adoc,Omada Controller\u003e\u003e\n* \u003c\u003cvaultwarden/README.adoc,Vaultwarden\u003e\u003e\n\n== References\n\n.Documentation\n* https://docs.podman.io/en/latest/[Podman Documentation]\n* https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html[podman-systemd.unit]\n* https://www.freedesktop.org/software/systemd/man/latest/[systemd Manual Pages]\n* https://github.com/containers/podman/blob/main/libpod/define/annotations.go[Podman Pod Annotations]\n* https://github.com/containers/podman/blob/main/pkg/util/kube.go[Podman Volume Annotations]\n\n== License\n\nThis project is licensed under the https://creativecommons.org/licenses/by-sa/4.0/legalcode[Creative Commons Attribution-ShareAlike 4.0 International License].\n\n© 2023-2024 Jordan Williams\n\n== Authors\n\nmailto:{email}[{author}]\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjwillikers%2Fhome-lab-helm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjwillikers%2Fhome-lab-helm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjwillikers%2Fhome-lab-helm/lists"}