From 68f69c30eacb51d554918434ca80ea747f1618aa Mon Sep 17 00:00:00 2001 From: Malin Date: Fri, 29 May 2026 08:00:52 +0200 Subject: [PATCH] feat: add VM sizing, host hardware specs and Proxmox provisioning steps --- README.md | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) diff --git a/README.md b/README.md index 85a81ea..9944071 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,180 @@ Telegraf, Beszel --- +## Host Hardware + +| Host | CPU | Logical CPUs | RAM | Storage | VM | +|---|---|---|---|---|---| +| dracula host | Xeon E5-1620 v2 @ 3.70GHz | 8 (4 cores + HT) | 64GB | Datacenter HDD | dracula-new (web) | +| transilvan host | Xeon E5-1620 v2 @ 3.70GHz | 8 (4 cores + HT) | 32GB | SSD | transilvan-new (db) | + +Both hosts run Proxmox VE (confirmed via qemu-guest-agent on current VMs). New VMs are the sole tenants on their respective hosts. + +--- + +## VM Sizing + +### Rationale for 200 concurrent users + +With nginx fastcgi_cache, the vast majority of requests never invoke PHP. On a news site, traffic concentrates on recent articles — the hot working set is small and stays warm in FreeBSD's unified buffer cache (UBC) regardless of underlying disk speed. + +| Metric | Value | Notes | +|---|---|---| +| Expected cache HIT rate | ~85–90% | News sites have concentrated traffic on recent content | +| Concurrent PHP requests at peak | ~20–30 | 200 users × ~15% miss rate | +| PHP-FPM workers (pm.max_children) | 40 | Headroom above expected peak | +| RAM per PHP-FPM worker | ~35MB RSS | WordPress with active plugins | +| PHP-FPM peak RAM | ~1.4GB | 40 workers × 35MB | +| nginx HIT response time | <5ms | Served from UBC, no PHP involved | +| nginx MISS response time | 100–400ms | WP query + render | +| InnoDB buffer pool hit rate | >99% | 20GB pool, 9.6GB dataset fits entirely in RAM | +| Active DB connections | ≤ 40 | One per active PHP-FPM worker | + +### dracula-new (web VM on HDD host) + +| Parameter | Value | +|---|---| +| vCPU | 6 | +| RAM | 14GB | +| Disk | 80GB single virtual disk (HDD-backed) | +| Balloon | Enabled (web VM, acceptable) | + +RAM breakdown: PHP-FPM peak 1.4GB + Redis 512MB + nginx + UBC page cache for hot articles (~4–6GB effective) + OS 1GB + headroom. + +HDD is acceptable for the web node. The fastcgi_cache working set for a news site fits in UBC (RAM). HDD latency only affects cold cache startup and log writes (sequential). The CPU and PHP-FPM worker slots are the actual bottleneck, not disk. + +### transilvan-new (DB VM on SSD host) + +| Parameter | Value | +|---|---| +| vCPU | 4 | +| RAM | 26GB | +| Disk 1 — OS | 40GB virtual (SSD-backed) | +| Disk 2 — ZFS data pool | 150GB virtual (SSD-backed) | +| Balloon | **Disabled** — memory ballooning must not reclaim InnoDB buffer pool RAM | + +RAM breakdown: innodb_buffer_pool_size 20GB + MySQL overhead 2GB + OS 4GB. + +Both virtual disks originate from the same physical SSD pool in Proxmox. Separation is logical: independent sizing, clean `zpool create data /dev/da1`, ZFS snapshots on the data disk without touching the OS disk, and easy future migration if a dedicated physical disk is added to the host. + +--- + +## VM Provisioning (Proxmox) + +### 1. Download FreeBSD 14.2 ISO on each Proxmox host + +```sh +wget -P /var/lib/vz/template/iso/ \ + https://download.freebsd.org/releases/amd64/amd64/ISO-IMAGES/14.2/FreeBSD-14.2-RELEASE-amd64-disc1.iso +``` + +### 2. Create dracula-new (run on the HDD host) + +Via CLI: +```sh +qm create 200 \ + --name dracula-new \ + --memory 14336 \ + --balloon 14336 \ + --cores 6 \ + --cpu host \ + --machine q35 \ + --bios ovmf \ + --efidisk0 local:1,format=raw \ + --net0 virtio,bridge=vmbr0 \ + --ostype other \ + --scsihw virtio-scsi-single \ + --scsi0 local:80,format=raw \ + --cdrom local:iso/FreeBSD-14.2-RELEASE-amd64-disc1.iso \ + --boot order=ide2;scsi0 \ + --agent enabled=1 +``` + +Via UI: +``` +General → Name: dracula-new +OS → FreeBSD (other), ISO: FreeBSD-14.2-RELEASE-amd64-disc1.iso +System → Machine: q35, BIOS: OVMF (UEFI), Qemu Agent: ✓ +Disks → VirtIO SCSI, 80GB, Cache: None +CPU → 6 cores, Type: host +Memory → 14336 MB +Network → VirtIO, vmbr0 +``` + +### 3. Create transilvan-new (run on the SSD host) + +```sh +# VM with OS disk +qm create 201 \ + --name transilvan-new \ + --memory 26624 \ + --balloon 0 \ + --cores 4 \ + --cpu host \ + --machine q35 \ + --bios ovmf \ + --efidisk0 local:1,format=raw \ + --net0 virtio,bridge=vmbr0 \ + --ostype other \ + --scsihw virtio-scsi-single \ + --scsi0 local:40,format=raw,discard=on,ssd=1 \ + --cdrom local:iso/FreeBSD-14.2-RELEASE-amd64-disc1.iso \ + --boot order=ide2;scsi0 \ + --agent enabled=1 + +# Add second disk for ZFS data pool +qm set 201 --scsi1 local:150,format=raw,discard=on,ssd=1 +``` + +`--balloon 0` disables memory ballooning on the DB VM. This is required — ballooning can silently reclaim pages from the InnoDB buffer pool under host memory pressure. + +### 4. FreeBSD installer settings (same for both VMs) + +``` +Welcome screen → Install +Keymap → your preference +Hostname → dracula-new (or transilvan-new) +Distribution → base, kernel (nothing else) +Partitioning → Auto (ZFS) + Pool type → stripe (single disk) + Disk → da0 (the OS disk) + Swap → 2GB + Compress → lz4 + Encrypt → No +Network → vtnet0, configure with a temporary IP for initial pkg bootstrap + (Tailscale will take over; this IP can be removed afterwards) +Mirror → closest region +Root password → set strong password +SSHD → enable +``` + +### 5. First boot — both VMs + +```sh +# Update base system +freebsd-update fetch install + +# Bootstrap pkg and install essentials +pkg update && pkg upgrade -y +pkg install -y qemu-guest-agent tailscale sudo curl wget + +# Enable QEMU guest agent (so Proxmox can see VM IP, issue graceful shutdowns) +sysrc qemu_guest_agent_enable=YES +service qemu-guest-agent start + +# Join Tailscale network +sysrc tailscaled_enable=YES +service tailscaled start +tailscale up --hostname=dracula-new # or transilvan-new + +# Note the assigned Tailscale IP — plug into pf.conf and wp-config placeholders +tailscale ip -4 +``` + +After both VMs have Tailscale IPs, replace all `` and `` placeholders throughout this document and in all config files. + +--- + ## Migration Data Inventory | Component | Size | Action |