DocsGuides

Deploying apps

One command publishes an app to a real URL with TLS.

The restful-expose helper is the front door. Point it at a port or a static directory, give it a name, and you get a live URL with TLS in about ten seconds.

Two flavors

--port for dynamic apps

For anything that listens on a TCP port: Next.js, Node, Python, Go, Rust, doesn't matter. Run your server bound to 127.0.0.1:<port>, then:

restful-expose --name api --port 3000

Your app is live at https://api.<your-slug>.restful.host/. nginx proxies to 127.0.0.1:3000. Wildcard TLS already covers it.

--root for static sites

For anything pre-built into a directory of HTML/CSS/JS: Astro, Hugo, plain HTML, Vite output, etc. Point at the directory:

restful-expose --name docs --root /home/restful/docs/dist

Live at https://docs.<your-slug>.restful.host/. nginx serves the files directly.

Bind to 127.0.0.1, not 0.0.0.0

Only ports 22, 80, 443 are open to the internet. Everything else is firewalled. Your app should bind to 127.0.0.1 (loopback). nginx is the only path from the outside world to your app, and it talks to the loopback address.

This is also why you don't need to think about TLS termination in your app: nginx does it, your app just speaks plain HTTP on localhost.

Keeping it running

restful-expose writes the nginx config but doesn't manage your process. For development you can run your server in a tmux pane and walk away. For something that should survive reboots, write a systemd unit:

# /etc/systemd/system/restful-app-api.service
[Unit]
Description=My API
After=network.target

[Service]
Type=simple
User=restful
Group=restful
WorkingDirectory=/home/restful/api
ExecStart=/usr/bin/node server.js
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

Then sudo systemctl enable --now restful-app-api. Ask Claude to do this for you and it will, because there's a skill installed on your machine that teaches Claude the conventions.

Updating

restful-expose is idempotent. Re-running it with the same --name updates the nginx config and reloads. Safe to run on every deploy.

To take down an app, delete the nginx file and reload:

sudo rm /etc/nginx/sites-restful/api.conf
sudo nginx -s reload

When you want a real domain

api.<slug>.restful.host is fine for prototypes and internal tools, but for anything customer-facing you probably want your own domain. See Custom domains for the flow.

Something missing or out of date? Tell us or check the support center.