Cole Wisniewski ← all projects

homelab

Live

My k3s cluster on Proxmox, with applications reconciled from Git by Argo CD.

At a glance

Argo CD Applications
37
Postgres clusters
6
Inbound web ports
0
ADRs
0

Stack

Infra
OpenTofu · Proxmox · k3s
Delivery
Git · Argo CD
Networking
Cilium
Security
Cloudflare Tunnel · Authentik · SOPS/age
Data
CloudNativePG · R2
Observability
Hubble · Prometheus · Grafana · Alertmanager

The platform I run

I run my sites and services on a k3s cluster hosted by Proxmox. I wanted one place to rebuild and understand the machines, apps and storage I use every day. Git records the desired state, and Argo CD applies it.

Server rack with status lights on a sky blue background

From Git to the cluster

OpenTofu provisions the VMs and public DNS. A Cloudflare Tunnel routes web traffic to apps that use Authentik for sign in. Argo CD reads this repo and reconciles the k3s manifests with prune and self heal enabled. Cilium handles networking while Prometheus, Grafana and Alertmanager show me what is happening. CloudNativePG stores app databases and backs them up to R2.

Build

  1. OpenTofu
  2. Proxmox VMs
  3. k3s

Deploy

  1. Git
  2. Argo CD
  3. apps on Cilium

Run

  1. Cloudflare Tunnel
  2. Authentik
  3. Prometheus and Grafana
  4. CNPG backups to R2

Making media imports hardlink

Media imports copied files instead of hardlinking them.

Media imports copied each file onto a slow disk because downloads and media lived on separate ZFS datasets. I found identical duplicate files during a storage audit. Even after merging the datasets, separate NFS mounts made hardlinks fail with EXDEV. I traced the error through the Kubernetes mount paths and found that subPath made the same split. I mounted one dataset once at /data and updated the app paths so new imports hardlink.

New imports can hardlink inside one shared mount.