Skip to content
dihlabs.lol

Operations

Deployment

dihlabs.lol runs on one $1.50 VPS: 1 vCPU, 2 GB of memory, Ubuntu 24.04. nginx in front, the site on Bun, the Rust engine next to it, all under systemd, updated from this…

On this page

dihlabs.lol runs on one $1.50 VPS: 1 vCPU, 2 GB of memory, Ubuntu 24.04. nginx in front, the site on Bun, the Rust engine next to it, all under systemd, updated from this repository automatically.

Production layout

piecewhereruns as
nginx:80 (and :443 with TLS)www-data
The site (optz start)127.0.0.1:3001, from /opt/optz/current/web/portfoliooptz-web.service
The Rust engine127.0.0.1:3000optz.service
Releases/opt/optz/releases/<sha>, /opt/optz/current → the live one
Data and backups/var/lib/optz (SQLite), hourly verified snapshotsoptz-backup.timer
Secrets/etc/optz/envroot only

First install

ssh root@your-server
# clone into /srv/optz and pull the branch every 30 s (BRANCH defaults to main)
curl -fsSL https://raw.githubusercontent.com/sxnistxr/OPTZ/main/deploy/setup-vps.sh | sudo BRANCH=main bash
sudo bash /srv/optz/ops/install-prod.sh        # users, toolchains (pinned, checksummed), units, first deploy

install-prod.sh installs Bun 1.4.4 and the Rust toolchain from pinned, checksummed archives, creates the optz user and directories, writes /etc/optz/env with a random secret, installs the systemd units and runs the first deploy.

Every deploy

ops/deploy.sh builds the commit, switches releases and health-checks them; it rolls back by itself if the new release isn't healthy within 30 seconds, and keeps the five newest releases. Follow it with journalctl -u optz-sync.service -f.

The site build downloads its fonts from Google at build time and renders Open Graph images, so the server needs outbound HTTPS while building (not while serving). Downloads are cached in ~/.cache/optz, so later builds only fetch what changed.

Behind Cloudflare

The site sends Cache-Control: s-maxage=300, stale-while-revalidate=86400 on pages (server.cdnMaxAge in optz.config.ts), so a CDN in front serves them for five minutes and refreshes in the background. To clear Cloudflare's copy on every deploy, add a zone id and an API token with the "Cache Purge" permission to /etc/optz/env:

CF_ZONE_ID=...
CF_API_TOKEN=...

deploy.sh purges the zone after the new release is live. Without them it skips the purge, and pages update at the CDN within five minutes.

The domain and TLS

Point dihlabs.lol (and www) at the server with A records, then get a certificate. Use certonly: the nginx config is generated on every deploy, so certbot shouldn't edit it.

sudo apt install certbot python3-certbot-nginx
sudo certbot certonly --nginx -d dihlabs.lol -d www.dihlabs.lol --deploy-hook "systemctl reload nginx"
sudo bash /srv/optz/ops/deploy.sh        # regenerates nginx with HTTPS; "already live" is fine

Once /etc/letsencrypt/live/<domain>/ exists, every deploy generates the config with HTTPS (HTTP/2, HSTS) and a redirect from port 80. certbot renews the certificate by itself and the deploy hook reloads nginx. The site's absolute URLs (canonical links, Open Graph, sitemap) come from url in portfolio/content/site.json, or the SITE_URL environment variable.

nginx

The config is generated, not hand-written: optz nginx turns optz.config.ts into a server block (hashed assets from disk with gzip_static, everything else to Bun with keep-alive, and micro-caching for proxied APIs). The deploy regenerates and reloads it when it changes.

Other ways to run an optz app

commandnotes
Single executableoptz build --compile → dist/servercopy one file and run it; sharp is used if it can be found
Edge workeroptz build --target edge → dist/edge/npx wrangler deploy from there (Cloudflare), or Deno Deploy / Vercel Edge
Static hostoptz export → dist/staticno server features

Operations

  • Logs: journalctl -u optz -u optz-web -f
  • Restart: sudo systemctl restart optz optz-web
  • Memory per connection on the box: bash /srv/optz/ops/vps-mem.sh
  • Restore a backup: ops/RESTORE.md