web / vm
For years, I deployed my web apps to a PaaS. In 2026 I moved cibot onto virtual machines on Ubicloud.
Why not PaaS
cibot's cost was almost all workers running test suites. A PaaS bills a premium for managed convenience, and its scaling model fought my workload:
- A persistent disk keeps caches warm across runs, but the PaaS does not scale servers that have disks. I could only scale up to a bigger box, never out to more of them.
- Ubicloud gave roughly twice the CPU and RAM for about a third less.
A VM per box gives warm local caches and horizontal scale together. Each cibot workers box owns its NVMe disk and registers with the cibot farmer over HTTP.
Pets, not cattle
I run a small number of long-lived VMs and provision them directly instead of baking an image. A shell script installs the toolchain and a local Postgres for tests, tuned for the box size. The script is idempotent, so re-running it on a fresh VM is the whole setup.
The application is a static Go binary. I cross-compile on my laptop and copy it up:
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o /tmp/cibot ./cmd/cibot
scp /tmp/cibot cibot-workers:/tmp/cibot
No Docker and no registry. See unix / ssh for the host
aliases that make scp cibot-workers: work.
Running the processes
A PaaS starts your process and restarts it on crash. On a VM, systemd does that job. I run the web process and the background workers as units, and read their output with journalctl.
Networking
A PaaS gives a private network between services for free. On Ubicloud I put the VMs on one private subnet, so the farmer and workers talk over private addresses with no public exposure and no egress cost. Only the single endpoint that GitHub must reach is public, behind Caddy for TLS.
I lock the provider firewall to least privilege: SSH plus the public web ports from anywhere, and everything else only from the private subnet. Nothing internal is reachable from the internet.
Managed Postgres
cibot's database runs on Ubicloud's managed Postgres, with backups and a CA I verify against. The throwaway test databases stay local on each worker box, where speed matters and durability does not.