vinhedo1 build runbook
Host: vinhedo1.apibr.com → 144.22.174.243 · Ubuntu 24.04 · OCI VM.Standard.E2.1.Micro
(1 GB RAM, 2 vCPU) · rebuilt August 2026
vinhedo1 is the fleet baseline plus a WireGuard server. This page covers only what is specific to it; follow the baseline for everything else, in this order:
- Baseline Phase 0 — DNS first. The rebuild gave vinhedo1 a new public IP. Until the A
record points at
144.22.174.243, PiVPN’s endpoint, Certbot and every existing WireGuard client config are broken. Also open 51820/udp in the OCI Security List; the other hosts don’t need it. - Baseline Phases 1–6 (base system, SSH, UFW, Fail2Ban, NGINX, Certbot). In Phase 3.3 include
the
51820/udprule; in Phase 4 keep the WireGuard subnet (10.141.230.0/24— checkip -4 addr show wg0after PiVPN picks it) inignoreipso a fumbled login over the VPN can’t ban the tunnel. - PiVPN + WireGuard — below. Must come after UFW is enabled.
- Baseline Phases 7–9 (collector, updates, verification) plus the extra checks at the end of this page.
PiVPN + WireGuard
Why it exists: GitHub Actions runners need to reach the MariaDB on the cPanel host at Nuvem
Hospedagem (osasco, 177.73.237.236), which only accepts connections from whitelisted IPs.
vinhedo1 is that whitelisted IP; runners connect to it over WireGuard and get NATed out.
PiVPN works on Ubuntu 24.04 — WireGuard is in the kernel, so no DKMS module and the old
wireguard-dkms install failure doesn’t apply.
Order matters: install PiVPN after UFW is enabled. PiVPN detects UFW and writes the
NAT/masquerade rules into /etc/ufw/before.rules plus a route allow rule itself. Install it
before UFW and you get a tunnel with no routing.
wget -qO /tmp/install-pivpn.sh https://install.pivpn.io
less /tmp/install-pivpn.sh # actually read it
sudo bash /tmp/install-pivpn.sh
Wizard answers for this box:
| Prompt | Answer |
|---|---|
| Static IP | Accept the current DHCP address — OCI hands out the same one; don’t let PiVPN rewrite netplan |
| Local user | ubuntu |
| VPN type | WireGuard |
| Port | 51820 |
| DNS provider | Cloudflare or Quad9 (this box is not a DNS server) |
| Public endpoint | DNS name → vinhedo1.apibr.com |
| Unattended upgrades | Yes (baseline Phase 8.1 overrides the policy afterwards anyway) |
| Reboot | Yes — then re-check sudo ufw status and sudo wg show |
Choosing the DNS name over the IP is the one that matters: client configs then survive the next rebuild, which is exactly what bit the GitHub Actions database views this time.
Create clients
One client per consumer, named for what it is — gha_<project> for a GitHub Actions workflow,
apibr_<service> for an API BR service, a person’s device by name (iphone_beatriz). Never
share one config between two consumers; you lose the ability to revoke or debug them apart.
sudo pivpn add -n gha_pm
sudo pivpn -qr gha_pm # or grab /home/ubuntu/configs/gha_pm.conf
sudo pivpn -c # list clients + last handshake
sudo pivpn -r gha_pm # revoke
Route MariaDB through the tunnel
In the client config, set AllowedIPs to the tunnel subnet plus the database host only —
split tunnel, so the runner doesn’t push all its traffic through a 1 GB micro instance:
[Peer]
AllowedIPs = 10.141.230.0/24, 177.73.237.236/32
Endpoint = vinhedo1.apibr.com:51820
PersistentKeepalive = 25
WireGuard routes by IP, not name. If the client connects to the database by hostname, pin it in
/etc/hosts on the runner or use the IP — otherwise the packets bypass the tunnel entirely.
Remember to whitelist 144.22.174.243 in cPanel’s Remote MySQL on the Nuvem Hospedagem side
(the old vinhedo1 IP is still listed there until you remove it).
Verify forwarding and NAT
sysctl net.ipv4.ip_forward # 1
sudo ufw show added | grep route # route allow in on wg0 out on ens3
sudo iptables -t nat -L POSTROUTING -n -v # a MASQUERADE for 10.141.230.0/24
sudo ufw status numbered | grep 51820
PiVPN adds a ufw route allow rule for wg0 rather than changing the global forward policy,
so DEFAULT_FORWARD_POLICY in /etc/default/ufw stays DROP and that is fine. Only if the
route rule is missing and you’d rather not add one:
sudo sed -i 's/DEFAULT_FORWARD_POLICY="DROP"/DEFAULT_FORWARD_POLICY="ACCEPT"/' /etc/default/ufw
sudo ufw reload
If NAT is missing, add it at the top of /etc/ufw/before.rules and sudo ufw reload:
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 10.141.230.0/24 -o ens3 -j MASQUERADE
COMMIT
ip route get 1.1.1.1 tells you the real interface name — it is ens3 on this fleet.
Grimoire API (later)
vinhedo1 will host Grimoire API (.NET) behind the baseline NGINX site. When it’s deployed, the
proxy block to add inside the vinhedo1.apibr.com server block is just:
location /api/ {
proxy_pass http://127.0.0.1:5000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Then add the unit name to /etc/projects-monitor/services.conf so the collector reports it
(the setup script’s auto-detection only runs on first provision and already matches grimoire*
unit names).
Verification
On top of baseline Phase 9:
sudo wg show # wg0 up, listening on 51820
sudo pivpn -c # client listed, recent handshake
sysctl net.ipv4.ip_forward # 1
sudo systemctl is-enabled wg-quick@wg0
sudo ufw status verbose | grep 51820
From a GitHub Actions runner (or any client with the config loaded), a connection to
177.73.237.236:3306 should succeed, and sudo pivpn -c on vinhedo1 should show the handshake
time update.