Advanced Search
Search Results
228 total results found
Three databases, on purpose
The platform runs three relational databases — PostgreSQL (10.100.100.13), MariaDB (10.100.100.14), and MySQL (10.100.100.15) — each on its own VM, each on local disk, not on the cluster's NFS. Why three? Because real applications disagree about what they want...
Tuning a database for the hardware it has
A freshly installed database ships with cautious, generic defaults. On a box you've sized deliberately (4 vCPU, 4 GiB RAM, SSD-backed disk), a little tuning goes a long way. The themes are the same across all three engines: Let it use the RAM. Tell the engine...
Every app gets its own credentials
This is a hard rule in the lab: no application ever connects as the database admin. Each app gets its own database, its own user, and its own password, scoped to just that database. # for an app 'foo', on PostgreSQL: CREATE DATABASE foo; CREATE USER foo WITH P...
Seeing what the cluster is doing: logs to Loki
The lab already had a central log store (Loki — see its book in Core Infrastructure), with a Promtail agent on every VM shipping system logs. When the cluster arrived, the job was to feed its logs in too. On the Kubernetes nodes the node-level Promtail agent w...
Lessons on data and observability
Match storage to the workload: databases get local disk on dedicated VMs, never NFS. Tune for the box you have: give the engine the RAM, tell it the disk is SSD, log slow queries. MariaDB ≠ MySQL: running both proved it. Check settings against your actual eng...
The front door
Everything that's reachable from the outside world passes through one VM: a pfSense firewall/router (10.100.100.1 inside, a public IP outside). It wears three hats: Router/NAT — gives the private 10.100.100.0/24 VMs a way out to the internet, and is the defau...
NAT: how private VMs reach the world
The VMs live on a private range that isn't routable on the internet. They still need to fetch packages, pull container images, and so on. pfSense handles that with outbound NAT: as a VM's traffic leaves for the internet, pfSense rewrites the source to its own ...
HAProxy: one door, many rooms
All the web services share a single public IP, so something has to look at each incoming request and send it to the right backend. That's HAProxy, running on pfSense, routing by hostname: https://git.example.com -> GIT-Server 10.100.100.2:3000 htt...
TLS terminates here, once
There is exactly one place in the whole lab that deals with certificates: HAProxy on pfSense. It holds a wildcard certificate for *.example.com and terminates TLS for every service. Behind it, traffic to the backends is plain HTTP on the trusted private networ...
A gotcha that cost an afternoon
A war story, because the lessons that stick are the ones that bit you. A backend's address was changed in the HAProxy GUI, Apply was clicked, and… HAProxy kept sending traffic to the old port. The config on disk said one thing; the running proxy did another. B...
Why a jump host
None of the internal VMs accept SSH from the internet. There's exactly one machine you can SSH to from outside — the jump host (or bastion) at 10.100.100.254, which also holds a public address. From there, you hop to anything internal. you --SSH--> Jump host...
The ProxyJump pattern
You don't want to manually SSH to the bastion and then SSH again — that's clumsy and breaks tooling. SSH has a built-in feature for exactly this: ProxyJump (and its lower-level cousin, ProxyCommand). It transparently tunnels your connection to the internal hos...
Hardening, and a host-key surprise
Because the bastion is the one publicly-reachable SSH endpoint, it's the one that gets the most attention: keep it patched, restrict who can log in, prefer keys, watch its auth logs (they ship to the central log store like everything else). A surprise worth wr...
Lessons on bastion access
One way in. Internal VMs expose no SSH to the internet; the bastion is the single public SSH endpoint. ProxyJump makes it painless. Bastion-only access with none of the two-hop hassle — tooling included. Harden the one box hard. It's the door everyone uses; p...
Why golden images
There are ~15 VMs in this lab. Not one of them was installed from an ISO by hand. Every single one is a clone of a single golden image — one carefully prepared template — customised at first boot by cloud-init. The alternative (install Ubuntu by hand, fifteen ...
The template
The template is one VM (ID 9999) prepared once: a current Ubuntu cloud image, the QEMU guest agent, the logging agent, sensible defaults — and then turned into a Proxmox template so it can only be cloned, not run directly. A few things are deliberately baked i...
Injecting per-VM identity with cloud-init
Cloning gives you fifteen identical machines. Cloud-init is what makes each one itself on first boot — its hostname, its IP, its login. The flow for creating a VM here is a small, repeatable recipe: 1. clone the template (9999) -> new VM with the next free I...
Grow-on-first-boot, and a clean teardown
Two finishing touches make the recipe pleasant to live with. Disks grow to fit. The template's disk is small. When you clone and resize the new VM's disk to, say, 250 GiB, cloud-init's growpart/resize on first boot expands the filesystem to fill it automatical...