Deployment
Run typress on a Linux host with a systemd unit, nginx as a TLS-terminating reverse proxy, and a Let's Encrypt certificate. A 2 GB VPS is comfortable. The repo's packaging/ directory has a hardened systemd unit and an LE auto-renew timer.
User and directories
sudo useradd -r -s /usr/sbin/nologin -d /var/lib/typress typress
sudo mkdir -p /opt/typress /var/lib/typress /etc/typress
sudo chown typress:typress /var/lib/typress
sudo chmod 0700 /var/lib/typress
sudo cp dist/typress /opt/typress/typressMaster key and env
openssl rand 32 | base64 | tr '+/' '-_' | tr -d '=' \
| sudo tee /etc/typress/master.key >/dev/null
sudo chmod 0400 /etc/typress/master.key
sudo chown root:typress /etc/typress/master.key
sudo cp packaging/typress.env.example /etc/typress/typress.env
sudoedit /etc/typress/typress.env # paste master key, edit origin
sudo chmod 0640 /etc/typress/typress.env
sudo chown root:typress /etc/typress/typress.envsystemd unit
packaging/typress.service ships ProtectSystem=strict, PrivateTmp, RestrictNamespaces, SystemCallFilter, and every other hardening directive that doesn't break Bun's JIT.
sudo cp packaging/typress.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now typress.serviceMemoryDenyWriteExecute is intentionally omitted. Bun's bundled JavaScriptCore JIT needs W^X memory; enabling it stops the binary from booting.
nginx and TLS
typress doesn't terminate TLS itself — front it with nginx or Caddy. Let's Encrypt's short-lived (6-day) IP certificates landed in 2026, so you can run TLS even before you have a domain.
server {
listen 443 ssl http2;
server_name your-site.example;
ssl_certificate /etc/letsencrypt/live/.../fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/.../privkey.pem;
client_max_body_size 0; # let typress enforce TYPRESS_MAX_UPLOAD_BYTES
location / {
proxy_pass http://127.0.0.1:4321;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}LE auto-renewal
Short-lived certs expire in 6 days. packaging/typress-le-renew.timer runs certbot renew every 12 hours, so a single failure isn't fatal — the next cycle picks it up.
sudo cp packaging/typress-le-renew.{service,timer} /etc/systemd/system/
sudo systemctl enable --now typress-le-renew.timermacOS cross-compile pitfall
Binaries built on macOS with --target=bun-linux-x64 have a known JSC heap bug on Linux that consumes ∞GB at idle. Build natively on the Linux host instead. Other production gotchas live in Troubleshooting.