Smart home on K3s
Self-hosted home automation, in my own flat
If the internet goes down, the lights still work. Everything below follows from that.
- lights, plugs and sensors
- 20+
- ports open to the internet
- 0
- Orchestration
- Bare-metal K3s, single nodecontrol plane and every workload, with room spare
- control plane and every workload, with room spare
- Reconciliation
- ArgoCDthe flat's desired state is a git repo
- the flat's desired state is a git repo
- Automation
- Home Assistant
- Radio
- Zigbee meshno device talks to a vendor cloud
- no device talks to a vendor cloud
- Transport
- MQTT
- Monitoring
- Prometheus + Grafanasame stack as work, smaller
- same stack as work, smaller
- Exposure
- Tailscale onlyremote access is over the VPN or not at all
- remote access is over the VPN or not at all
Why it all runs locally
Most smart-home setups end up as a pile of vendor apps tied together with cloud accounts. That works until a vendor goes away, or you realise your motion sensor is reporting to a server in another country.
I wanted the opposite: everything local, and every change to it in version control. It's the same stack I run at work, sized to a flat. Mostly because I already know how to debug it.
Everything runs on one Pi
A Raspberry Pi 5 (8GB) is the whole control plane. I run NVMe over USB because SD cards die under sustained writes, and a UPS on the power side because Home Assistant restarting at 3am after a tripped fuse isn't an experience I wanted twice. It's on wired ethernet. The Pi is the thing every light depends on, and I didn't want it depending on the router's Wi-Fi as well.
A SONOFF Zigbee USB coordinator handles the radio. Devices pair directly with Zigbee2MQTT, which talks to Home Assistant over MQTT. No bridges, no cloud round-trip.
I'm at twenty-plus endpoints today: Hue bulbs, Innr plugs on power-monitored circuits, temperature and humidity sensors, motion and contact sensors, and a solar-powered camera. One node covers all of it, and I've had no reason to add a second.
What happens when I press a light switch
Every hop is on hardware in the flat. The internet connection can drop and the lights still work, because nothing on this path needed it. Remote access is a separate concern, handled by Tailscale rather than by opening a port.
The whole flat is a git repo
Everything on the Pi is a Kubernetes deployment, reconciled by ArgoCD from a git repo. Adding a new automation, tweaking a Grafana dashboard, bumping the Home Assistant version. All of it goes through a commit. The cluster pulls; nothing pushes.
That sounds like overkill for a home lab, and it would be if it were any other tool. ArgoCD on K3s is about 80MB of memory and a few CRDs. The payoff is a setup that survives me. If I blat the SD card tomorrow, a fresh install plus argocd app sync brings everything back.
Power draw and humidity, in Grafana
Prometheus scrapes metrics from Home Assistant's exporter and from node-exporter on the Pi itself. Innr smart plugs report real-time power draw on the kitchen heater and the hallway lamp. SONOFF LCD sensors report temperature and humidity per room.
Grafana sits on top, with dashboards for power draw and room-by-room temperature.
Remote access goes over Tailscale
Zero ports exposed to the internet. Remote access goes through Tailscale. Every device on my account joins a private overlay network and reaches the Pi by its tailnet IP. Nothing on the router needs opening.
The blast radius if Home Assistant is compromised is limited to the LAN, and the LAN is segmented so the IoT VLAN can't reach anything else.
Next
Smart TRV valves next, so heating schedules run per room rather than per flat. After that, presence detection good enough to retire the motion sensors. They're fine for "is someone in the hallway" and useless for "is anyone home".