typress
An editorial workshop.日本語

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/typress

Master 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.env

systemd 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.service

MemoryDenyWriteExecute 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.timer

macOS 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.