feat: add VM sizing, host hardware specs and Proxmox provisioning steps

This commit is contained in:
Malin
2026-05-29 08:00:52 +02:00
parent 4295bec6c0
commit 68f69c30ea

174
README.md
View File

@@ -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 | ~8590% | News sites have concentrated traffic on recent content |
| Concurrent PHP requests at peak | ~2030 | 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 | 100400ms | 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 (~46GB 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 `<dracula-new Tailscale IP>` and `<transilvan-new Tailscale IP>` placeholders throughout this document and in all config files.
---
## Migration Data Inventory
| Component | Size | Action |