Deploying apps
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
Section titled “Two flavors”--port for dynamic apps
Section titled “--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 3000Your 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
Section titled “--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/distLive at https://docs.<your-slug>.restful.host/. nginx serves the files directly.
Bind to 127.0.0.1, not 0.0.0.0
Section titled “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
Section titled “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:
[Unit]Description=My APIAfter=network.target
[Service]Type=simpleUser=restfulGroup=restfulWorkingDirectory=/home/restful/apiExecStart=/usr/bin/node server.jsRestart=alwaysRestartSec=3
[Install]WantedBy=multi-user.targetThen sudo systemctl enable --now restful-app-api. Ask Claude to do this for you and it will — there’s a skill installed on your machine that teaches Claude the conventions.
Updating
Section titled “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.confsudo nginx -s reloadWhen you want a real domain
Section titled “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.