Deployment
One-click deploy to Railway or Render, or run the container on any host
daysurface-serve runs the FastAPI app, which mounts FastMCP at /mcp. One image,
one process, one port -- anything that can run a container can host it. Deploy it
one-click to Railway or Render, or run the container yourself.
Deploy on Railway
One-click template: backend + managed Postgres, migrations run automatically.
Deploy to Render
One-click blueprint from render.yaml, database and session secret wired.
Both targets provision the backend (FastAPI + MCP at /mcp) as a Docker service
plus a managed Postgres database, run Alembic migrations, and prompt for the
required secrets. The landing page (landing-page/) deploys separately and is
not included.
Forking this repo?
The buttons point at the canonical upstream template. To deploy your own fork,
change the Render button's repo= URL to your fork and re-create the Railway
template from your project (its deploy link is fixed to a published template).
Render's button takes an absolute repo URL, so it can't auto-follow a fork.
Railway
The committed railway.json
pins the Docker build, pre-deploy migrations, and health check, so the template
inherits them. To re-generate or update the template: project Settings ->
Generate Template from Project -> Publish (dashboard only; the CLI can't
publish templates).
Backend service variable map
The template has two services: a Postgres service (use Railway's standard Postgres defaults) and the backend. Set the backend's variables as follows.
Auto-resolve / auto-generate -- paste as defaults so it deploys with zero input:
| Variable | Value |
|---|---|
DEV_ENV | prod |
BACKEND_DB_URI | ${{Postgres.DATABASE_URL}} (private URL; matches your Postgres service name) |
MCP_PUBLIC_URL | https://${{RAILWAY_PUBLIC_DOMAIN}}/mcp |
GOOGLE_REDIRECT_URI | https://${{RAILWAY_PUBLIC_DOMAIN}}/api/v1/auth/google/callback |
SESSION_SECRET_KEY | ${{ secret(32) }} |
GOOGLE_TOKEN_ENC_KEY | ${{ secret(43, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_") }}= |
The trailing = on GOOGLE_TOKEN_ENC_KEY is literal (outside the ${{ }}): 43
base64url chars + = decodes to the 32 bytes Fernet requires. Railway generates
secret(...) values once and persists them, so redeploys don't invalidate
the session secret or break stored Gmail tokens.
Leave empty; the deployer pastes their own (per-deployment credentials that can't be pre-baked):
WORKOS_CLIENT_ID · WORKOS_API_KEY · WORKOS_AUTHKIT_DOMAIN · GOOGLE_CLIENT_ID · GOOGLE_CLIENT_SECRET
Gotchas
DEV_ENVmust beprod. The Dockerfile sets it, but an empty template var overrides it back to blank, silently disabling prod token encryption and the prod config overlay.- The backend service needs a public domain enabled, or
${{RAILWAY_PUBLIC_DOMAIN}}resolves to empty and both URLs break. - After deploy, register the
GOOGLE_REDIRECT_URIvalue in your Google Cloud OAuth client's authorized redirect URIs, and point your WorkOS redirect/resource atMCP_PUBLIC_URL. (Inherent to OAuth; can't be automated.)
Render
Driven by render.yaml.
The database and SESSION_SECRET_KEY are wired automatically; you're prompted
for the WorkOS and Google OAuth secrets. After the first deploy, set
MCP_PUBLIC_URL to https://<your-render-host>/mcp and GOOGLE_REDIRECT_URI
to https://<your-render-host>/api/v1/auth/google/callback (also add that
callback to your Google OAuth client), then redeploy.
Any container host
No Railway or Render? Any container host works. The Dockerfile runs:
uv run uvicorn api_server.server:app --host 0.0.0.0 --port ${PORT:-8080}Expose port 8080 (or whatever you set PORT to), point the healthcheck at
/health, and mount MCP traffic at the /mcp path. Set DEV_ENV=prod,
BACKEND_DB_URI, and SESSION_SECRET_KEY at minimum -- see the Railway variable
map above for the full set.
Optional integrations
See .env.example
for the full list of optional integrations (LLM keys, Stripe, LangFuse, Telegram,
etc.). Add any you need from the platform dashboard after the first deploy.
Connecting clients
Once deployed, clients connect to https://YOUR-DOMAIN/mcp with a Bearer JWT
or an X-API-KEY header. See Setup.