Node / VPS
What you'll have at the end: a Vura app running as a managed systemd service on any Linux VPS, with Caddy as a reverse proxy providing HTTPS and WebSocket passthrough.
Supports all route kinds: serverless, hot (WebSocket), task.
Steps
1. Scaffold and build
npm create vura@latest my-app
cd my-app
npm install
npm run build
After npm run build, dist/server/entry.js is the unified server.
2. Copy to the server
rsync -a dist/ user@your-server:/srv/my-app/dist/
rsync package.json user@your-server:/srv/my-app/
Or push via git and build on the server directly.
3. Install production dependencies on the server
cd /srv/my-app
npm install --omit=dev --no-audit --no-fund
If dist/package.json exists (emitted when hot routes are present), run npm install inside dist/ as well:
cd /srv/my-app/dist && npm install --omit=dev --no-audit --no-fund && cd /srv/my-app
4. Smoke-test the server manually
PORT=3000 NODE_ENV=production node dist/server/entry.js
Expected output:
[vura] listening on port 3000
Open a second terminal and verify:
curl -fsS http://localhost:3000/api/hello
Expected: a JSON response from the hello route.
For WebSocket smoke-test (requires wscat or equivalent):
wscat -c ws://localhost:3000/api/chat
> ping
< You: ping
Then Ctrl-C the server.
5. Create the systemd unit
# /etc/systemd/system/my-app.service
[Unit]
Description=Vura app — my-app
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/srv/my-app
ExecStart=/usr/bin/node dist/server/entry.js
Restart=always
RestartSec=5
Environment=NODE_ENV=production
Environment=PORT=3000
Environment=VURA_REVALIDATE_SECRET=change-me
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable my-app
sudo systemctl start my-app
sudo systemctl status my-app
6. Add a reverse proxy with Caddy
Caddy handles HTTPS automatically and passes WebSocket upgrades through transparently.
# /etc/caddy/Caddyfile
your-domain.com {
reverse_proxy localhost:3000
}
The three-liner is sufficient — Caddy's default reverse_proxy handles Upgrade: websocket headers without any extra directives.
Reload Caddy:
sudo systemctl reload caddy
Smoke test
# Static page
curl -fsS https://your-domain.com/ | grep -q '<h1'
# API route
curl -fsS https://your-domain.com/api/hello
# WebSocket
wscat -c wss://your-domain.com/api/chat
Expected: the static page returns HTML with an <h1, the API route returns JSON, and the WebSocket connection stays open (send a message to verify echo or broadcast).
CI-tested: this guide is verified by the
node-vpsjob in.github/workflows/selfhost.yml. The job boots the built server onPORT=3000, curls/, curls/api/hello, and opens a WebSocket to/api/chat(verifying the Welcome message). It does not test systemd or Caddy configuration — those require a real Linux host.
Route kind support
All kinds: serverless, hot (WebSocket), task / cron.