Agent SaaS Starter
Guides

Deploy on Jio

Run the application and its OAuth-protected MCP server on one computer.

Use a Large Jio computer (4 vCPU, 8 GiB RAM) for the Rust and Next.js builds. Keep it running while testing the connectors; destroying it removes the database and changes the public URL on the next deployment.

jio config
jio create

Inside the computer, check out the reviewed branch under /home/jio/saas-template. Install Rust 1.94+, Bun 1.3+, OpenSSL development headers, a C/C++ build toolchain, PostgreSQL, and nginx. The tested Ubuntu packages were:

sudo apt-get update
sudo apt-get install -y build-essential pkg-config libssl-dev cmake postgresql nginx
sudo -u postgres createuser jio
sudo -u postgres createdb -O jio saas_template

Public origin and configuration

Use one public port, 8080, for the application, API, OAuth discovery, and MCP. Obtain its URL with jio expose 8080 <vm-id> once the proxy is listening. Set these values in the guest's private .env, replacing https://your-public-origin with that exact URL:

APP_ENV=production
APP_URL=https://your-public-origin
API_PUBLIC_URL=https://your-public-origin
AUTH_ISSUER=https://your-public-origin
MCP_PUBLIC_URL=https://your-public-origin
MCP_RESOURCE=https://your-public-origin/mcp
API_INTERNAL_URL=http://127.0.0.1:4000
DATABASE_URL="postgresql:///saas_template?host=/var/run/postgresql&user=jio"

Copy other settings from .env.example. Generate a new RSA signing key on this computer with bun run keys:dev, protect .env and the key files, and retain them across service restarts. Set the app, docs, and landing URLs to origins, without paths. Do not upload your Jio credentials to the guest.

Reverse proxy

Bind the web app to 127.0.0.1:3000, API to 127.0.0.1:4000, and MCP to 127.0.0.1:4001. nginx listens on 127.0.0.1:8080; Jio provides public HTTPS. Route requests as follows:

PathUpstream
/ and exactly /oauth/consentWeb app, port 3000
/api/, /oauth/, /.well-known/API, port 4000
/mcp and /.well-known/oauth-protected-resourceMCP, port 4001

Preserve Host and X-Forwarded-Host, set X-Forwarded-Proto to https, use HTTP/1.1, disable proxy buffering, and allow long-lived MCP responses. Do not send /oauth/consent to the API. Use access logs containing $uri rather than $request_uri so OAuth codes and other query secrets are not logged. Apply rate limits at the trusted edge to authentication and registration routes.

Build and keep services running

bun install --frozen-lockfile
cargo build --release -p starter-api -p starter-mcp-server
bun run build:app
bun run build:docs

Run the following under separate systemd services as jio, with WorkingDirectory=/home/jio/saas-template, EnvironmentFile=/home/jio/saas-template/.env, and Restart=on-failure:

/home/jio/saas-template/target/release/starter-api
/home/jio/saas-template/target/release/starter-mcp-server
/usr/local/bin/bun --cwd apps/app start --hostname 127.0.0.1 --port 3000

Enable the services at boot. Start PostgreSQL before testing registration. The API applies embedded migrations at startup. For docs, run the docs app on loopback 3003 and optionally publish a second nginx listener on 8081.

From your trusted machine:

jio expose 8080 <vm-id>

Open the public app, register and sign in. Connect ChatGPT and Claude to https://your-public-origin/mcp. Run the authentication checks against the deployed origin before sharing it. Use a stable hostname and durable database/key backups for a lasting deployment.

On this page