feat: rename VMs to zamolxis(900)/decebal(901), raise RAM to 24GB/30GB, decebal to 6vCPU, innodb_buffer_pool 26G

This commit is contained in:
Malin
2026-05-29 08:45:19 +02:00
parent b1047817e3
commit 795e84d438

106
README.md
View File

@@ -123,12 +123,12 @@ FreeBSD 15.0 over 14.x specifically because PHP 8.5 is a **binary package** on 1
## Target Architecture
```
[internet] → [NPM node, Tailscale] → [dracula-new FreeBSD 15.0, Tailscale] → [transilvan-new FreeBSD 15.0, Tailscale]
[internet] → [NPM node, Tailscale] → [zamolxis FreeBSD 15.0, Tailscale] → [decebal FreeBSD 15.0, Tailscale]
dracula-new (FreeBSD 15.0) transilvan-new (FreeBSD 15.0)
zamolxis (FreeBSD 15.0) decebal (FreeBSD 15.0)
────────────────────────── ─────────────────────────────
nginx (pkg) ZFS pool → /var/db/mysql
PHP 8.5 (ports build) recordsize=16K (InnoDB optimal)
PHP 8.5.6 (pkg) recordsize=16K (InnoDB optimal)
gd, imagick, intl, mbstring, compression=lz4
opcache, pdo_mysql, redis, primarycache=metadata
soap, sockets, sodium, MySQL 8.4 LTS (ports)
@@ -171,10 +171,10 @@ Proxmox native monitoring
| Host | CPU | Logical CPUs | RAM | Storage | Available to VMs | VM |
|---|---|---|---|---|---|---|
| dracula host | Xeon E5-1620 v2 @ 3.70GHz | 8 (4 cores + HT) | 64GB | Datacenter HDD | ~full | dracula-new (web) |
| transilvan host | Xeon E5-1620 v2 @ 3.70GHz | 8 (4 cores + HT) | 32GB | SSD (160GB total, ~130GB free after Proxmox) | 130GB | transilvan-new (db) |
| dracula host | Xeon E5-1620 v2 @ 3.70GHz | 8 (4 cores + HT) | 64GB | Datacenter HDD | ~full | zamolxis / ID 900 (web) |
| transilvan host | Xeon E5-1620 v2 @ 3.70GHz | 8 (4 cores + HT) | 32GB | SSD 160GB (~130GB free) | 130GB | decebal / ID 901 (db) — sole VM |
Both hosts run Proxmox VE (confirmed via qemu-guest-agent on current VMs). New VMs are the sole tenants on their respective hosts.
Both hosts run Proxmox VE (confirmed via qemu-guest-agent on current VMs). Decebal's host is dedicated — no other VMs share it.
---
@@ -193,34 +193,34 @@ With nginx fastcgi_cache, the vast majority of requests never invoke PHP. On a n
| 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 |
| InnoDB buffer pool hit rate | >99% | 26GB pool, 9.6GB dataset fits entirely in RAM with 16GB to spare |
| Active DB connections | ≤ 40 | One per active PHP-FPM worker |
### dracula-new (web VM on HDD host)
### zamolxis (web VM on HDD host)
| Parameter | Value |
|---|---|
| vCPU | 6 |
| RAM | 14GB |
| RAM | 24GB |
| 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.
RAM breakdown: PHP-FPM peak 1.4GB + Redis ~150MB + nginx + OS ~1GB + **~20GB available for UBC page cache**. With 20GB of UBC headroom, the entire nginx fastcgi_cache working set lives in RAM regardless of what is on disk — HDD latency becomes irrelevant for cached pages. Cold cache startup and log writes (sequential) are the only HDD operations that matter.
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)
### decebal (DB VM on SSD host — sole VM)
| Parameter | Value |
|---|---|
| vCPU | 4 |
| RAM | 26GB |
| vCPU | 6 |
| RAM | 30GB |
| Disk 1 — OS | 20GB virtual (SSD-backed) |
| Disk 2 — ZFS data pool | 100GB virtual (SSD-backed) |
| Total disk | 120GB — fits within 130GB available, 10GB buffer for Proxmox overhead |
| Balloon | **Disabled** — memory ballooning must not reclaim InnoDB buffer pool RAM |
RAM breakdown: innodb_buffer_pool_size 20GB + MySQL overhead 2GB + OS 4GB.
RAM breakdown: innodb_buffer_pool_size 26GB + MySQL overhead ~2GB + OS ~2GB. Decebal is the sole VM on its host — 30GB allocation leaves 2GB for the Proxmox host OS, which is the practical minimum.
6 vCPU (from 8 logical CPUs on host) gives MySQL adequate threads for InnoDB background I/O, parallel queries, and connection handling while leaving 2 threads for Proxmox.
**Disk sizing rationale:** FreeBSD base installs to ~2GB; 20GB for the OS disk is generous for binaries, ports tree fragments, and logs. The 100GB ZFS data pool provides: 9.6GB current dataset (likely 67GB after lz4 compression), 7 days of compressed mysqldumps (~4GB each = ~28GB), binlog rotation buffer (expire_logs_days = 3), and substantial growth headroom at the current data trajectory.
@@ -230,21 +230,21 @@ Both virtual disks originate from the same physical SSD pool in Proxmox. Separat
## VM Provisioning (Proxmox)
### 1. Download FreeBSD 14.2 ISO on each Proxmox host
### 1. Download FreeBSD 15.0 ISO on each Proxmox host
```sh
wget -P /var/lib/vz/template/iso/ \
https://download.freebsd.org/releases/amd64/amd64/ISO-IMAGES/15.0/FreeBSD-15.0-RELEASE-amd64-disc1.iso
```
### 2. Create dracula-new (run on the HDD host)
### 2. Create zamolxis / ID 900 (run on the HDD host)
Via CLI:
```sh
qm create 200 \
--name dracula-new \
--memory 14336 \
--balloon 14336 \
qm create 900 \
--name zamolxis \
--memory 24576 \
--balloon 24576 \
--cores 6 \
--cpu host \
--machine q35 \
@@ -261,24 +261,24 @@ qm create 200 \
Via UI:
```
General → Name: dracula-new
General → Name: zamolxis
OS → FreeBSD (other), ISO: FreeBSD-15.0-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
Memory → 24576 MB
Network → VirtIO, vmbr0
```
### 3. Create transilvan-new (run on the SSD host)
### 3. Create decebal / ID 901 (run on the SSD host — sole VM)
```sh
# VM with OS disk
qm create 201 \
--name transilvan-new \
--memory 26624 \
qm create 901 \
--name decebal \
--memory 30720 \
--balloon 0 \
--cores 4 \
--cores 6 \
--cpu host \
--machine q35 \
--bios ovmf \
@@ -292,7 +292,7 @@ qm create 201 \
--agent enabled=1
# Add second disk for ZFS data pool
qm set 201 --scsi1 local:100,format=raw,discard=on,ssd=1
qm set 901 --scsi1 local:100,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.
@@ -302,7 +302,7 @@ qm set 201 --scsi1 local:100,format=raw,discard=on,ssd=1
```
Welcome screen → Install
Keymap → your preference
Hostname → dracula-new (or transilvan-new)
Hostname → zamolxis (or decebal)
Distribution → base, kernel (nothing else)
Partitioning → Auto (ZFS)
Pool type → stripe (single disk)
@@ -339,13 +339,13 @@ service qemu-guest-agent start
# Join Tailscale network
sysrc tailscaled_enable=YES
service tailscaled start
tailscale up --hostname=dracula-new # or transilvan-new
tailscale up --hostname=zamolxis # or decebal
# 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.
After both VMs have Tailscale IPs, replace all `<zamolxis Tailscale IP>` and `<decebal Tailscale IP>` placeholders throughout this document and in all config files.
---
@@ -416,7 +416,7 @@ ssh -i /root/.ssh/id_ed25519 -p 79 root@transilvan \
---
## Phase 1 — DB Node (transilvan-new)
## Phase 1 — DB Node (decebal)
### 1.1 FreeBSD base + ZFS
@@ -444,10 +444,10 @@ sysrc mysql_dbdir=/var/db/mysql
`/usr/local/etc/mysql/my.cnf`:
```ini
[mysqld]
bind-address = <transilvan-new Tailscale IP>
bind-address = <decebal Tailscale IP>
datadir = /var/db/mysql
socket = /tmp/mysql.sock
innodb_buffer_pool_size = 24G
innodb_buffer_pool_size = 26G
innodb_log_file_size = 1G
innodb_flush_log_at_trx_commit = 1
innodb_flush_method = O_DIRECT
@@ -463,7 +463,7 @@ skip-name-resolve
```
ext_if = "vtnet0"
ts_if = "tailscale0"
web_ts = "<dracula-new Tailscale IP>"
web_ts = "<zamolxis Tailscale IP>"
set skip on lo0
block all
@@ -483,7 +483,7 @@ service pf start
pkg install tailscale
sysrc tailscaled_enable=YES
service tailscaled start
tailscale up --hostname=transilvan-new
tailscale up --hostname=decebal
```
### 1.5 DB restore
@@ -494,14 +494,14 @@ tailscale up --hostname=transilvan-new
ssh root@transilvan \
"mysqldump -S /tmp/mysqld.sock --single-transaction \
--routines --triggers --events sql_sibiuindepen" \
| ssh root@transilvan-new "mysql -u root sql_sibiuindepen"
| ssh root@decebal "mysql -u root sql_sibiuindepen"
# Create app user (use same password as current DB_PASSWORD in wp-config)
mysql -u root -e "
CREATE USER 'sql_sibiuindepen'@'<dracula-new Tailscale IP>'
CREATE USER 'sql_sibiuindepen'@'<zamolxis Tailscale IP>'
IDENTIFIED BY '<password>';
GRANT ALL ON sql_sibiuindepen.* TO
'sql_sibiuindepen'@'<dracula-new Tailscale IP>';
'sql_sibiuindepen'@'<zamolxis Tailscale IP>';
FLUSH PRIVILEGES;"
```
@@ -528,7 +528,7 @@ Crontab:
---
## Phase 2 — Web Node (dracula-new)
## Phase 2 — Web Node (zamolxis)
### 2.1 Base packages
@@ -703,7 +703,7 @@ service pf start
pkg install tailscale
sysrc tailscaled_enable=YES
service tailscaled start
tailscale up --hostname=dracula-new
tailscale up --hostname=zamolxis
```
### 2.7 rsync web files
@@ -726,7 +726,7 @@ Two changes on the new node only:
```php
// 1. Update DB_HOST to new transilvan Tailscale IP
define( 'DB_HOST', '<transilvan-new Tailscale IP>' );
define( 'DB_HOST', '<decebal Tailscale IP>' );
// 2. WP_CACHE stays true for Redis Object Cache drop-in
// Remove the W3TC comment, keep the constant:
@@ -851,17 +851,17 @@ curl -s https://connect.facebook.net/ro_RO/sdk.js > ${WEBROOT}/fb-sdk-ro.js
## Phase 3 — Zero-downtime Cutover
### Pre-cutover checklist (run on dracula-new before touching NPM)
### Pre-cutover checklist (run on zamolxis before touching NPM)
```sh
# 1. Site responds via new stack directly
curl -sk -o /dev/null -w "%{http_code}" \
http://<dracula-new Tailscale IP>/ \
http://<zamolxis Tailscale IP>/ \
-H "Host: sibiuindependent.ro"
# Expected: 200
# 2. DB connection live
mysql -h <transilvan-new Tailscale IP> \
mysql -h <decebal Tailscale IP> \
-u sql_sibiuindepen -p sql_sibiuindepen \
-e "SELECT COUNT(*) FROM wp_posts WHERE post_status='publish';"
@@ -872,7 +872,7 @@ wp --path=/var/www/sibiuindependent.ro --allow-root redis-cache status
php85 -m | grep -E "imagick|redis|pdo_mysql|opcache|intl|soap|sodium"
# 5. nginx fastcgi_cache working — second request should be HIT
curl -sI http://<dracula-new Tailscale IP>/ -H "Host: sibiuindependent.ro" \
curl -sI http://<zamolxis Tailscale IP>/ -H "Host: sibiuindependent.ro" \
| grep X-Cache-Status
# First request: MISS, second request: HIT
```
@@ -893,11 +893,11 @@ T-2 Final DB dump and import:
ssh root@transilvan \
"mysqldump -S /tmp/mysqld.sock --single-transaction \
--routines --triggers --events sql_sibiuindepen" \
| ssh root@transilvan-new "mysql -u root sql_sibiuindepen"
| ssh root@decebal "mysql -u root sql_sibiuindepen"
T-3 Switch NPM upstream:
old: 100.99.157.56 (dracula Tailscale IP)
new: <dracula-new Tailscale IP>
new: <zamolxis Tailscale IP>
(single upstream change in NPM — no DNS TTL involved, instant)
T-4 Smoke test:
@@ -932,11 +932,11 @@ zfs snapshot data/mysql@post-migration-$(date +%Y%m%d)
## Open Items at Time of Planning
- [ ] Confirm new Tailscale hostnames for both nodes (determines pf rules and wp-config DB_HOST)
- [ ] Confirm NPM node Tailscale IP (determines pf rule on dracula-new)
- [ ] Confirm NPM node Tailscale IP (determines pf rule on zamolxis)
- [x] PHP 8.5 — binary package on FreeBSD 15.0, `pkg install php85`. No compilation. All extensions confirmed available.
- [ ] Redis Object Cache plugin — already in plugins dir or fresh install needed
- [ ] W3TC features in use beyond caching: minify? If yes, switch to standalone nginx-based minification or keep W3TC minify only with nginx page cache
- [ ] ZFS pool disk — confirm second disk available on transilvan-new VM
- [ ] ZFS pool disk — confirm second disk available on decebal VM
- [ ] MySQL 8.4 vs MariaDB 11.4 LTS — plan targets MySQL 8.4; revisit if preferred
- [x] Beszel and Telegraf — dropped. Proxmox native VM monitoring is sufficient.
- [x] Redis placement — local to dracula-new (unix socket). No 3rd host. WordPress object cache uses 50150MB RAM; a dedicated VM would cost more resources than Redis itself consumes. A separate Redis host is only justified when scaling to multiple web nodes sharing a single cache.
- [x] Redis placement — local to zamolxis (unix socket). No 3rd host. WordPress object cache uses 50150MB RAM; a dedicated VM would cost more resources than Redis itself consumes. A separate Redis host is only justified when scaling to multiple web nodes sharing a single cache.