Skip to content
pcjun97Public

About

Exposing the vulnerable configurations of my homelab to the public

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Latest commit

 

History

169 Commits

Folders and files

Repository files navigation

Chi Jun's Homelab

This project stores configurations of services in my homelab.

TODO

  • Add more nodes for a high-availability setup
  • Implement solution for backup to offsite storage
  • Include IaC (Infrastructure as Code) for server setup (OS & packages)
  • Add and improve documentations
  • Add CI/CD to lint and sync the configurations

Hardware

The homelab runs on a single machine with the following specifications:

  • Intel i5-3330
  • 16GB RAM (8GB+8GB)
  • 960GB SSD (OS + /mnt/fast)
  • 1TB HDD (/mnt/bulk)
  • Nvidia 1050Ti

Platform

The operating system of choice is Debian 13 (trixie), with tailscale installed.

The rest of the host is set up with Ansible (ansible/), which installs:

  • the NVIDIA driver from Debian's non-free (the 550 branch, which still supports Pascal GPUs) and the NVIDIA container toolkit, which k3s detects as the nvidia runtime
  • a single-node k3s cluster, with the following optional addons disabled:
    • helm-controller
    • servicelb
    • traefik
    • local-storage (replaced by a self-managed local-path-provisioner)
    • metrics-server
  • helm (through Homebrew), used to render charts when bootstrapping Argo CD

Services

Third-party apps/services:

Tools

  • GitOps solution of choice is combination of kustomize and argo-cd
  • No secrets are stored in git. The Tailscale operator OAuth secret is created by hand (see Bootstrap).

Bootstrap

  1. In the Tailscale admin console:
    • Enable MagicDNS and HTTPS certificates
    • Add the operator's default tags to the policy file:
      "tagOwners": {
        "tag:k8s-operator": [],
        "tag:k8s": ["tag:k8s-operator"],
      },
      and, if the policy doesn't allow all traffic, a grant letting your devices reach tag:k8s and tag:k8s-operator on port 443
    • Give tailnet admins cluster-admin through the operator's API server proxy:
      "grants": [{
        "src": ["autogroup:admin"],
        "dst": ["tag:k8s-operator"],
        "app": { "tailscale.com/cap/kubernetes": [{ "impersonate": { "groups": ["system:masters"] } }] },
      }],
    • Create an OAuth client (Settings → Trust credentials) tagged tag:k8s-operator, with write access to Devices Core, Auth Keys and Services, as in the operator install guide
  2. Set up the host. This needs Ansible and Homebrew installed on the host first. Debian's ansible package includes the community.general collection; with plain ansible-core, run ansible-galaxy collection install -r requirements.yaml as well. Add --connection=local when running on the host itself:
    sudo apt install ansible
    cd ansible && ansible-playbook site.yaml --ask-become-pass
    
  3. Bootstrap the cluster from the host (no sudo needed; kubectl and helm must be on the PATH):
    cd ansible && ansible-playbook bootstrap.yaml
    
    The playbook skips any step that's already done:
    • prompts for the Tailscale OAuth client ID and secret (the secret is hidden and never logged) and creates the operator-oauth secret
    • installs Argo CD and the ApplicationSet, which creates one application per directory under kustomize/
    • syncs local-path-provisioner, tailscale, metrics-server, argocd and homelab in order, waiting for each to become healthy. Only applications that have never been synced are synced, so re-running it never forces a sync.
  4. Sync the remaining applications by hand in Argo CD, at https://argocd.<tailnet>.ts.net (user admin, password from kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath='{.data.password}' | base64 -d).

Miscellaneous

Networking

All endpoints are private and only reachable over Tailscale. Each Ingress uses the tailscale ingress class from the Tailscale operator, which gives the service its own tailnet device at https://<name>.<tailnet>.ts.net with a certificate issued by Tailscale. MagicDNS and HTTPS must be enabled for the tailnet.

Storage

Volumes are provisioned by local-path-provisioner into <disk>/k8s/<namespace>/<pvc>/, with reclaimPolicy: Retain:

  • local-fast (default): /mnt/fast on the SSD, for app config
  • local-bulk: /mnt/bulk on the HDD, for media (the media PVC shared by jellyfin and qbittorrent)

Remote kubectl

The Tailscale operator runs an API server proxy in auth mode. Requests are authenticated with the caller's Tailscale identity and mapped to Kubernetes groups by the policy grant above, so no Kubernetes credentials leave the host. From any tailnet device with kubectl installed:

tailscale configure kubeconfig tailscale-operator

On a machine without the tailscale CLI, such as WSL with Tailscale running on Windows, create the same kubeconfig by hand. The token is a placeholder; the proxy authenticates the connection's Tailscale identity instead:

kubectl config set-cluster homelab --server=https://tailscale-operator.<tailnet>.ts.net
kubectl config set-credentials tailscale-auth --token=unused
kubectl config set-context homelab --cluster=homelab --user=tailscale-auth
kubectl config use-context homelab

If WSL can't resolve or reach tailnet names, enable networkingMode=mirrored and dnsTunneling=true under [wsl2] in %USERPROFILE%\.wslconfig, then run wsl --shutdown.

The first request after the operator starts may time out while the proxy gets its certificate. If the cluster can't run pods, the proxy is unavailable too; SSH to the host and use its local kubeconfig instead.

About

Exposing the vulnerable configurations of my homelab to the public

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Contributors

Languages