{"id":48699900,"url":"https://github.com/mortylabs/kubernetes","last_synced_at":"2026-04-11T09:49:37.849Z","repository":{"id":223372399,"uuid":"380440668","full_name":"mortylabs/kubernetes","owner":"mortylabs","description":"Andrew Morty's production-grade K3s homelab on Raspberry Pi — Home Assistant, InfluxDB, Grafana, MQTT, Pi-hole, deCONZ, UniFi, Cloudflare DDNS and more","archived":false,"fork":false,"pushed_at":"2026-03-15T21:28:36.000Z","size":335,"stargazers_count":26,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-04-11T09:49:15.263Z","etag":null,"topics":["cert-manager","cloudflare-ddns","docker","esp8266","grafana","home-assistant","homelab","influxdb","ingress-nginx","iot","k3s","k8s","kubernetes","metallb","mongodb","morty","mqtt","python3","raspberry-pi","wordpress"],"latest_commit_sha":null,"homepage":"https://mortylabs.com","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mortylabs.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":"2021-06-26T07:18:46.000Z","updated_at":"2026-03-24T06:52:07.000Z","dependencies_parsed_at":null,"dependency_job_id":"a18bf517-55fa-4828-a206-a91c16671fef","html_url":"https://github.com/mortylabs/kubernetes","commit_stats":null,"previous_names":["mortylabs/kubernetes"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mortylabs/kubernetes","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mortylabs%2Fkubernetes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mortylabs%2Fkubernetes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mortylabs%2Fkubernetes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mortylabs%2Fkubernetes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mortylabs","download_url":"https://codeload.github.com/mortylabs/kubernetes/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mortylabs%2Fkubernetes/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31676210,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-11T08:18:19.405Z","status":"ssl_error","status_checked_at":"2026-04-11T08:17:08.892Z","response_time":54,"last_error":"SSL_read: 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":["cert-manager","cloudflare-ddns","docker","esp8266","grafana","home-assistant","homelab","influxdb","ingress-nginx","iot","k3s","k8s","kubernetes","metallb","mongodb","morty","mqtt","python3","raspberry-pi","wordpress"],"created_at":"2026-04-11T09:49:37.105Z","updated_at":"2026-04-11T09:49:37.840Z","avatar_url":"https://github.com/mortylabs.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🏠 Morty Labs — K3s Homelab\n\n\u003e A lightweight K3s-based Kubernetes cluster, currently running version **`v1.34.4+k3s1`** as of **25th February 2026**, tailored for a personal homelab hosting `Home Assistant`, `InfluxDB`, `Grafana`, `MQTT`, `UniFi Controller`, `Pi-hole`, `deCONZ`, and more.\n\n[![K3s](https://img.shields.io/badge/K3s-v1.34.4%2Bk3s1-blue?logo=kubernetes)](https://k3s.io/)\n[![cert-manager](https://img.shields.io/badge/cert--manager-v1.19.4-green?logo=letsencrypt)](https://cert-manager.io/)\n[![MetalLB](https://img.shields.io/badge/MetalLB-v0.15.3-blue)](https://metallb.universe.tf/)\n[![ingress-nginx](https://img.shields.io/badge/ingress--nginx-v1.12.0-brightgreen?logo=nginx)](https://kubernetes.github.io/ingress-nginx/)\n[![License: GPL-3.0](https://img.shields.io/badge/license-GPL--3.0-orange)](LICENSE)\n[![Stars](https://img.shields.io/github/stars/mortylabs/kubernetes?style=social)](https://github.com/mortylabs/kubernetes/stargazers)\n[![CI](https://github.com/mortylabs/kubernetes/actions/workflows/lint.yaml/badge.svg)](https://github.com/mortylabs/kubernetes/actions/workflows/lint.yaml)\n\n![Raspberry Pi](https://img.shields.io/badge/hardware-Raspberry%20Pi%204-red?logo=raspberry-pi)\n![ARM64](https://img.shields.io/badge/arch-ARM64-lightgrey)\n![Cloudflare](https://img.shields.io/badge/DNS-Cloudflare-orange?logo=cloudflare)\n\n---\n\n## 🤔 Why This Repo Exists\n\nTo better understand Kubernetes concepts, I wrote all deployment `.yaml` files myself from scratch, instead of relying on third-party Helm charts:\n\n- Fully orchestrated Kubernetes stack built for **Raspberry Pi**\n- Ideal for self-hosted services: Home Assistant, databases, dashboards, network management, and more\n- Modular and portable — spin up the same stack at home or at a remote site\n- Secure by default — TLS everywhere, Cloudflare WAF in front, fail2ban on the nodes\n\n---\n\n## 👤 Who Is This For?\n\n- Raspberry Pi enthusiasts wanting to run a production-grade homelab or website\n- Home Assistant users who want persistent storage, TLS, and proper ingress\n- Anyone learning Kubernetes who wants real working manifests, not toy examples\n- DevOps engineers setting up a low-cost remote monitoring stack\n\n---\n\n## 🎯 What You'll End Up With\n\nA fully working homelab cluster with:\n\n- 🏡 Home Assistant accessible at `https://ha.yourdomain.com`\n- 📊 Grafana dashboards at `https://grafana.yourdomain.com`\n- 🔒 Automatic TLS certificates via Let's Encrypt\n- 📡 MQTT broker for all your IoT sensors\n- 🕳️ Network-wide ad blocking via Pi-hole\n- ☁️ Automatic DNS updates when your home IP changes\n- 💾 All data persisted on NFS — survives pod restarts and reboots\n\n---\n\n## 🚀 Cluster Overview\n\n- **Kubernetes Distribution:** [Rancher K3s](https://k3s.io/)\n- **Load Balancer:** [MetalLB](https://metallb.universe.tf/) v0.15.3\n- **Ingress/Reverse Proxy:** [ingress-nginx](https://kubernetes.github.io/ingress-nginx/) v1.12.0 (replacing the default Traefik)\n- **TLS:** [cert-manager](https://cert-manager.io/) v1.19.4 + Let's Encrypt\n- **DNS/CDN:** [Cloudflare](https://cloudflare.com) (proxy + WAF + DDNS)\n- **Nodes:** Raspberry Pi 4 Model B — ARM64, 8GB RAM\n- **Operating System:** Raspberry Pi OS (Bookworm) 64-bit\n- **Storage:** Dedicated Raspberry Pi NFS server (SSD-based, 500GB)\n- **Backups:** Automatic backups to Google Drive and GitHub\n\nFeel free to explore, reuse, or adapt this repo for your own Kubernetes learning journey!\n\n---\n\n## 📦 Deployed Services\n\n- [`home-assistant`](home-assistant/) — Core home automation hub\n- [`influxdb`](influxdb/) — Time-series metrics storage\n- [`grafana`](grafana/) — Metrics dashboards\n- [`mqtt_broker`](mqtt_broker/) — Mosquitto MQTT broker\n- [`mqtt2influx`](mqtt2influx/) — MQTT → InfluxDB bridge\n- [`govee2mqtt`](govee2mqtt/) — Govee BLE lights → MQTT\n- [`deconz`](deconz/) — Zigbee gateway (ConBee II)\n- [`pihole`](pihole/) — Network-wide ad/DNS blocking\n- [`unifi`](unifi/) — Ubiquiti UniFi Controller\n- [`cloudflare-dns`](cloudflare-dns/) — Cloudflare DDNS CronJob\n- [`ingress`](ingress/) — ingress-nginx + cert-manager ClusterIssuer\n- [`metallb`](metallb/) — Bare-metal load balancer config\n- [`pv_nfs`](pv_nfs/) — NFS persistent volume provisioner\n- [`wordpress`](wordpress/) — WordPress + MariaDB\n- [`ingress-nginx`](ingress-nginx/) — Cloudflare real IP forwarding config for ingress-nginx\n\n---\n\n## 🛠 Installation — k3s\n\nEdit `/boot/firmware/cmdline.txt` (Bookworm) or `/boot/cmdline.txt` (Bullseye) and append to the **single existing line**:\n```\ncgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1\n```\n\nThen install k3s with Traefik and the built-in service LB disabled:\n```\ncurl -sfL https://get.k3s.io | sh -s - --disable=traefik --disable=servicelb --write-kubeconfig-mode 644\n```\n\n---\n\n## 🛠 Installation — NFS Persistent Storage\n\nFollow this tutorial to configure your Pi as an NFS server:\nhttps://pimylifeup.com/raspberry-pi-nfs/\n\nThen deploy the NFS provisioner in k3s:\n```\ncd pv_nfs\nkubectl apply -f class.yaml\nkubectl apply -f rbac.yaml\nkubectl apply -f deployment.yaml\n```\n\n---\n\n## 🛠 Installation — NGINX Ingress\n```\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/cloud/deploy.yaml\n```\n\n---\n\n## 🛠 Installation — MetalLB Load Balancer\n```\ncd metallb\nkubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.3/config/manifests/metallb-native.yaml\nvi config.yaml  # edit and set the IP address range reserved on your DHCP server\nkubectl apply -f config.yaml\n```\n\n---\n\n## 🛠 Installation — HTTPS Ingress via cert-manager \u0026 Let's Encrypt\n\nBelow will install cert-manager **v1.19.4**, which is the latest version as of **25th February 2026**.\n```\ncd ingress\nkubectl create namespace cert-manager\nkubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.19.4/cert-manager.yaml\nvi letsencrypt.yaml  # update your email address\nkubectl apply -f letsencrypt.yaml\n```\n\nRemember to open ports 80 and 443 on your router and forward traffic to the MetalLB ingress IP.\n\n---\n\n## 🛠 Installation — Applications\n\nFor each app, edit `pv.yaml` to set your NFS server IP and path, edit `secrets.yaml` to set credentials, then:\n```\nkubectl apply -f pv.yaml\nkubectl apply -f secrets.yaml\nkubectl apply -f deployment.yaml\nkubectl apply -f svc.yaml\nkubectl apply -f ingress.yaml  # if applicable\n```\n\nSee each app's `README.md` for specific instructions.\n\n---\n\n## 🔐 Secrets Management\n\nEach app has a `secrets.yaml` file excluded from git via `.gitignore`. Never commit real credentials. See each app folder for the specific secrets required.\n\n---\n\n## ☁️ Cloudflare DNS\n\nAll services are exposed via Cloudflare-proxied subdomains. DNS records are kept in sync automatically via the [`cloudflare-dns`](cloudflare-dns/) CronJob which runs every 20 minutes.\n\n---\n\n## ⬆️ Upgrading k3s\n```\ncurl -sfL https://get.k3s.io | sh -s - --disable=traefik --disable=servicelb --write-kubeconfig-mode 644\nkubectl get nodes\n```\n\nAlways check the [k3s release notes](https://github.com/k3s-io/k3s/releases) before upgrading.\n\n---\n\nBuilt with ☕ and mild obsession by [Andrew Morty](https://mortylabs.com) 🏴󠁧󠁢󠁳󠁣󠁴󠁿\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmortylabs%2Fkubernetes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmortylabs%2Fkubernetes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmortylabs%2Fkubernetes/lists"}