You Donβt Need Kubernetes
Side Projects on One Linux Server
---
# The Side Project Trap

| "Best Practice" Stack | What You Actually Need |
|:--|:--|
| Build for scale πππ | Build for reality |
| Kubernetes cluster | One server |
| CI/CD pipeline for infra | A config file |
| HashiCorp Vault | Your password manager |
| Grafana + Prometheus | Something you already run |
| Hours of maintenance | Hours on your actual project |
---
# PuzzleSecretary.com
A web service for tracking social game scores
- I play Wordle, Connections, Strands, etc. with friends across time zones
- We share scores in a Signal chat
- I can track how my friend Peter in the UK is doing β we play at similar times
- But when the US wakes up, it becomes a flood of scores I can't follow
- PuzzleSecretary collects scores from Signal and WhatsApp, builds personal leaderboards and group comparisons
---
# Don't Solve Problems You Don't Have
graph LR
S[Signal] -->|~msgs/day| F[Flask]
W[WhatsApp] -->|~msgs/day| F
F -->|INSERT| DB[(SQLite)]
DB -->|SELECT| F
F -->|leaderboards| B[Browser]
style DB fill:#f9f,stroke:#333
Human players around the world β low-frequency writes
Friends checking leaderboards β low-frequency reads
SQLite excels at both. One VM. Done.
---
# What Do I Already Have or Know?

The recurring question behind every decision
---
# The OS: Flatcar Linux

- Immutable β dm-verity protected `/usr`, no drift
- Auto-updates β atomic, whole-OS, rollback = reboot
- No `apt install` β all your dependencies go in containers
- Treat the OS like firmware: provision once, update automatically
- I work with the Flatcar engineers β virtual throat to choke
**My Flatcar 101 talk is today @ 5pm in Track III**
---
# Containers: Rootless Podman Quadlets
```ini
[Container]
Image=ghcr.io/bexelbie/puzzlesecretary:latest
Label=io.containers.autoupdate=registry
Volume=/home/app/leaderboard:/data:Z
EnvironmentFile=/home/app/env
PublishPort=127.0.0.1:5000:5000
[Service]
Restart=always
ExecStartPre=/opt/op-secret-manager/op-secret-manager
ExecStopPost=/opt/op-secret-manager/op-secret-manager --cleanup
[Install]
WantedBy=default.target
```
- Quadlet file = container described as a systemd service
- Rootless = unprivileged host user. Break out? You're still nobody.
---
# Secrets: Your Password Manager is Already a Vault
graph LR
A[1Password] -->|API| B[OP Secret Manager]
B -->|files| C[/run/secrets/]
B -->|env vars| D[Quadlet .env files]
C --> E[Containers]
D --> E
style A fill:#0572ec,stroke:#333,color:#fff
style E fill:#f9f,stroke:#333
- Your password manager stores credentials, notes, files β and has an API
- Applications understand files and environment variables
- Connect the two: pre-exec in systemd downloads secrets before the service starts
- I also store configuration as 1Password notes β centralized secrets AND config
- managed with github.com/bexelbie/op-secret-manager
---
# Network: Zero Open Ports

| Inbound Traffic | How |
|:--|:--|
| Web (puzzlesecretary.com) | Cloudflare Tunnel |
| SSH (management) | Tailscale |
| Open ports on the VM | **None** |
---
# Monitoring and Alerting
## Why Not Grafana?
1. I don't want to run more infrastructure just for running infrastructure
2. I am not going to look at a dashboard
---
# The Pipeline: Telegraf β MQTT β ???
graph LR
subgraph VM ["Azure VM"]
C[Containers] -->|metrics| T[Telegraf]
T -->|publish| M[MQTT messages]
end
M --> Q["???"]
style VM fill:#e8f4f8,stroke:#333
style T fill:#4b275f,stroke:#333,color:#fff
style Q fill:#ffd700,stroke:#333
- Telegraf: container that gathers system and custom metrics
- MQTT: lightweight message protocol
- Metrics flow out to ... something that stores time-series data and alerts
---
#  Home Assistant

We think of it as "turn on the lights."
It's actually: track a value, store it, graph it, alert on it.
- Battery levels, temperature, meter readings β all time-series data
- Long-term statistics engine built in
- Already running MQTT at my house for unrelated reasons
- I use this pattern for two servers now
---
# Alerting: Home Assistant Knows How to Reach You
Home Assistant can:
- Push a notification to your phone
- Override silent mode for critical alerts
- Add an item to your to-do list
- Put a message on an e-ink display
- It could even flash the lights and pause the movie if needed

---
# The Architecture
One VM. Six connections to things I already had.
graph LR
MO[Montastic] -.->|probe| CC[Cloudflare]
CC -->|tunnel| VM[VM: Flatcar + Quadlets]
VM -->|fetch secrets| OP[1Password]
VM -->|MQTT/Tailscale| HA[Home Assistant]
HA -->|alerts| PH[Phone]
LAP[Laptop] -->|SSH/Tailscale| VM
---
# Day 2: What Maintenance Looks Like
| When | What | How long |
|:--|:--|:--|
| Most days | Nothing. It runs itself. | 0 min |
| Wednesday | HA says "3 containers need updates" β SSH in, `podman auto-update` | 5 min |
| When I ship a feature | Push release to Github, container auto built then load it | 15 min |
| Something breaks | HA alerts my phone, I SSH in and look at logs | varies |
| OS update | Flatcar stages it, reboots Wednesday morning | 0 min |
---
# The Recurring Question

Every decision followed the same pattern:
| I need... | I already have or know ... |
|:--|:--|
| A server OS | Flatcar (from my day job) |
| Container management | Podman Quadlets β systemd |
| A secrets vault | 1Password (family plan) |
| Secure networking | Cloudflare + Tailscale |
| Monitoring | Home Assistant + MQTT |
| Alerting & notifications | Home Assistant automations |
| External uptime check | Montastic (free) |
---
# Adapt the Principle, Not the Stack
You don't need my specific tools. You need the question.
- Flatcar β Fedora CoreOS, NixOS, whatever immutable OS fits
- 1Password β Bitwarden, any password manager with an API
- Home Assistant β Uptime Kuma, anything that tracks values and alerts
- Cloudflare Tunnel β ngrok, bore, any reverse tunnel
- The principle: stretch what you already know and pay for
---
# Thank You
**Come to Flatcar 101** β Today @ 5pm, Track III
**Try PuzzleSecretary** β puzzlesecretary.com