https://github.com/psimaker/homelab
Self-hosted home infra: a 53-container Docker dataplane (hosts loogi.ch) + a k3s/GitOps platform I'm building as a CKA learning lab.
https://github.com/psimaker/homelab
ansible devops docker flux gitops homelab kubernetes searxng self-hosted terraform
Last synced: 23 days ago
JSON representation
Self-hosted home infra: a 53-container Docker dataplane (hosts loogi.ch) + a k3s/GitOps platform I'm building as a CKA learning lab.
- Host: GitHub
- URL: https://github.com/psimaker/homelab
- Owner: psimaker
- License: mit
- Created: 2025-08-29T16:22:33.000Z (10 months ago)
- Default Branch: main
- Last Pushed: 2026-05-29T08:35:57.000Z (24 days ago)
- Last Synced: 2026-05-29T10:19:26.889Z (24 days ago)
- Topics: ansible, devops, docker, flux, gitops, homelab, kubernetes, searxng, self-hosted, terraform
- Language: Shell
- Homepage: https://loogi.ch
- Size: 535 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# homelab
Five years of self-hosted, pre-AI Docker operations on bare metal — **53 containers
across 18 Compose stacks**, including one service live for real users: the search
engine [**loogi.ch**](https://loogi.ch). That is **Tier-2**, my production dataplane.
**Tier-1** is a k3s / GitOps platform I'm designing and learning as I prepare for the
CKA. The manifests, OpenTofu and 13 ADRs in this repo are real and written — designed
to learn from, not yet deployed to production. Throughout the README, what is
*running* and what is *designed* are labelled apart.
[](compose/)
[](https://loogi.ch)
[](docs/architecture.md)
[](docs/adr/)
[](LICENSE)
> *I automate things so I can spend more time breaking other things.*
## What runs today — Tier-2 (Docker, production)
A bare-metal Debian host (`airbase`) with five years of hands-on operations — self-taught
and started well before the AI era, so the core understanding is mine, not a model's.
- **[loogi.ch](https://loogi.ch)** — a public, privacy-first SearXNG search engine
with a custom theme, served for real users.
- **53 containers across 18 Compose stacks**: Nextcloud-AIO, Immich, Plex + *arr,
Paperless, Vaultwarden, n8n, Vikunja, Syncthing, ntfy, Gitea …
- **Self-hosted CI/CD** — Gitea Actions with my own runner on `airbase`: build and
deploy pipelines on my own hardware, with this public repo as a one-way GitHub
mirror. End-to-end ownership of the delivery path, not a managed SaaS runner.
- **Nginx Proxy Manager** — reverse proxy and TLS (Let's Encrypt) for the dataplane.
- **Watchtower** — automated container image updates.
- **WireGuard / gluetun**, a segmented home network.
Compose files live in [`compose/`](compose/) as 1:1 snapshots of what runs. This tier
owns terabytes of real state and has survived Docker upgrades, kernel upgrades and a
disk migration. Keeping it on Docker rather than Kubernetes is a deliberate call,
reasoned out in [ADR-0001](docs/adr/0001-tier1-tier2-split.md).
## What I'm building — Tier-1 (k3s platform, learning lab + roadmap)
The target stack I've chosen and am working through as part of my CKA preparation —
each tool picked deliberately and documented as one of **13 ADRs** in
[`docs/adr/`](docs/adr/). I have the basics hands-on (kubectl, writing manifests);
the advanced pieces are exactly what the lab is for.
I spin up a single-node k3s lab on a Raspberry Pi to practise for the CKA and to try
the manifests in this repo — a learning cluster, not a 24/7 deployment. The two-site
Hetzner-edge mesh in the diagram below is the design target, not a running cluster.
**Target stack** (chosen and documented, not yet operated in production): k3s 1.31 +
Cilium, Flux v2 for GitOps, OpenTofu on Hetzner, Headscale mesh, Pocket-ID (OIDC),
Longhorn, kube-prometheus-stack + Loki + Tempo, restic 3-2-1, Traefik + cert-manager.
The manifests and Terraform are committed and thought through; I'm validating them
piece by piece in the lab, not running them under load.
**Goal:** once the platform is solid and I'm CKA-certified, move selected *new*
workloads onto it — never the stateful Tier-2 giants without a concrete reason that
pays for the migration.
## Architecture — today vs. roadmap
```mermaid
flowchart LR
user[End user] --> npm
subgraph Today["Running today — Tier-2 (Docker)"]
npm["Nginx Proxy Manager
+ Let's Encrypt"] --- docker[("53 Compose containers
loogi.ch, Nextcloud, Immich, …")]
end
subgraph Roadmap["Roadmap — Tier-1 (k3s, in build)"]
direction TB
edge["edge — Hetzner
k3s server (planned)"]
agent["airbase — k3s worker
(planned)"]
edge -. Tailscale mesh / Headscale
(planned) .-> agent
end
Today -.->|migrate new workloads once solid| Roadmap
classDef plan stroke-dasharray:5 5;
class edge,agent plan;
```
## Tour
Most of this repo is design and code I've written and reasoned about. What is
*running* is the `compose/` tier; the `kubernetes/` and `terraform/` trees are the
lab and the roadmap.
| You'd like to see... | Look at... | State |
| --- | --- | --- |
| The Tier-1 / Tier-2 split decision | [`docs/adr/0001-tier1-tier2-split.md`](docs/adr/0001-tier1-tier2-split.md) | design |
| All 13 decisions and *why* | [`docs/adr/`](docs/adr/) | design |
| The full design | [`docs/architecture.md`](docs/architecture.md) | design |
| Cloud infrastructure as code | [`terraform/live/prod/`](terraform/live/prod/) | written, lab |
| How nodes are configured | [`ansible/roles/`](ansible/roles/) | written, lab |
| The Tier-1 platform manifests | [`kubernetes/infrastructure/`](kubernetes/infrastructure/) | written, lab |
| The Tier-2 stacks that actually run | [`compose/`](compose/) | **live** |
| Self-hosted CI | [`.gitea/workflows/`](.gitea/workflows/) | **live** |
## Stack — running today (Tier-2)
| Layer | Tool |
| --- | --- |
| Host | Debian, bare metal (`airbase`) |
| Orchestration | Docker Compose |
| Reverse proxy / TLS | Nginx Proxy Manager + Let's Encrypt |
| CI/CD | Gitea Actions, self-hosted runner on `airbase` |
| Updates | Watchtower (automated image updates) |
| Networking | WireGuard / gluetun, segmented LAN |
The Tier-1 target stack (k3s, Cilium, Flux, OpenTofu, …) is listed in
"What I'm building" above and detailed in [`docs/architecture.md`](docs/architecture.md) —
kept out of this table on purpose, because that table is what runs.
## Repo layout
```
homelab/
├── docs/ Architecture, ADRs, runbooks (design + reasoning)
├── terraform/ OpenTofu — Hetzner, Cloudflare, Backblaze (written, lab)
├── ansible/ Roles + playbooks (written, lab)
├── kubernetes/
│ ├── flux-system/ Flux components (lab)
│ ├── infrastructure/ Controllers, storage, observability, identity (lab)
│ └── apps/ Tier-1 workload manifests (lab)
├── compose/ Tier-2 Docker Compose stacks — what actually runs
├── scripts/ bootstrap, sops helpers
├── .gitea/workflows/ CI on my self-hosted Gitea (live)
└── .github/workflows/ no-op stubs (mirror only — Gitea is the source)
```
## Live links
- Production search engine: [loogi.ch](https://loogi.ch) — runs on Tier-2
- LOOGI source: [github.com/psimaker/loogi](https://github.com/psimaker/loogi)
- Canonical code: self-hosted Gitea *(private)* · this is the public mirror
## About
I'm a career-changer moving into DevOps / Platform Engineering, based in central
Switzerland and looking for a junior role (on-site or hybrid). Five years of
hands-on self-hosting, a merged Nextcloud Server contribution (PR #59317, backported
to two stable releases), and the CKA in preparation. If this repo caught your eye,
reach me via my [GitHub profile](https://github.com/psimaker).
## License
[MIT](LICENSE).