Skip to main content

Deploy to a VPS

The baseline production shape is intentionally conventional:

Internet → HTTPS/Nginx → Bun/Elysia → PostgreSQL

├─ SvelteKit build
└─ S3-compatible storage (when used)

systemd worker → Bunway Jobs PostgreSQL database

Build, migrate, and start using the scripts in the generated package.json. Run bunway db:migrate --all during a controlled release, not concurrently from every application process.

Nginx

server {
listen 443 ssl http2;
server_name app.example.com;

client_max_body_size 25m;
proxy_read_timeout 3600s;

location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_buffering off;
}
}

Define map $http_upgrade $connection_upgrade { default upgrade; '' close; } in the http block. proxy_buffering off permits timely SSE delivery; upgrade headers permit WebSockets. Use Certbot or your platform's TLS process and add an HTTP-to-HTTPS server block.

systemd application

[Unit]
Description=Bunway application
After=network.target

[Service]
Type=simple
User=bunway
WorkingDirectory=/srv/myapp
EnvironmentFile=/srv/myapp/.env
ExecStart=/home/bunway/.bun/bin/bun run src/app.ts
Restart=on-failure

[Install]
WantedBy=multi-user.target

Create a second unit for the worker with the same directory/environment and ExecStart=/home/bunway/.bun/bin/bunway worker. Then use:

sudo systemctl daemon-reload
sudo systemctl enable --now myapp myapp-worker
sudo systemctl status myapp myapp-worker
journalctl -u myapp -u myapp-worker -f

Adjust executable paths to the deployment user. Multi-process Realtime is currently in-memory: a publisher and subscriber must share a Bun process. Use one application process for those features until an external bridge exists. Use S3-compatible storage instead of local disk across hosts.