---
title: "Deploy OpenDots | (Just Updated) AI Agent Workspace With Pages API, Owner Token Generated"
description: "OpenDots self-hosted AI agent workspace with pages API and SQLite"
category: "Other"
url: https://railway.com/deploy/opendots-or-just-updated-ai-agent-worksp
---

# Deploy OpenDots | (Just Updated) AI Agent Workspace With Pages API, Owner Token Generated

OpenDots self-hosted AI agent workspace with pages API and SQLite

**[Deploy OpenDots | (Just Updated) AI Agent Workspace With Pages API, Owner Token Generated on Railway](https://railway.com/template/opendots-or-just-updated-ai-agent-worksp)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/opendots-or-just-updated-ai-agent-worksp/manifest.json

- **Creator:** SuperSlowSloth
- **Category:** Other

## Template content

### opendots

- **Image:** ghcr.io/bon5co/opendots-railway:0e706ab@sha256:db09d245d7514e8aaf341abe3bd73621e252903d3da35a8e3b20fdc514beeeab
- **Health check:** /
- **Public domain:** Yes

## Documentation

# Deploy and Host OpenDots on Railway

**Built for an LLM agent to deploy and use.** The deploy form has nothing to fill in: the owner token is generated, the REST API is reachable with it as a bearer token, and your workspace (a SQLite database on a volume) survives redeploys. OpenDots is the open-source agent workspace from CopilotKit: spaces, pages and chat with AI teammates in one self-hosted web app, with a JSON API behind it.

## About Hosting OpenDots

This template runs one service, **opendots**, built from the upstream CopilotKit/OpenDots server (a Hono and SQLite server that also serves the web app) pinned to a source commit, wrapped as `ghcr.io/bon5co/opendots-railway` and pinned by digest. A volume at `/data` holds the SQLite database, so spaces and pages are kept across redeploys.

**No open workspace.** Every `/api` route requires `Authorization: Bearer OWNER_TOKEN`. The token is generated at deploy (48 characters) and the wrapper refuses to start with an empty or short one. The web app itself loads without it, and asks for the token to open the workspace.

**What the wrapper fixes for Railway.** The upstream image does not exist, so the wrapper builds the server from source. It sets the public origin from the generated domain (OpenDots checks the browser origin against `APP_ORIGIN`), listens on Railway's injected `PORT`, and chowns the root-owned volume for the unprivileged `node` user so writes reach disk.

**Optional model and Intelligence keys.** Chat with AI teammates needs a CopilotKit Intelligence key and an OpenAI key, which are yours and are not template variables. Add `INTELLIGENCE_API_KEY` and `OPENAI_API_KEY` as variables on the `opendots` service to enable it. Without them the workspace still runs and pages can be created and edited by hand and over the API.

### Agent contract

- Public URL: `https://RAILWAY_PUBLIC_DOMAIN` (the generated domain of the `opendots` service)
- Private URL: `http://opendots.railway.internal:8080`
- Credentials: the variable `OWNER_TOKEN` on the `opendots` service
- Auth: send `Authorization: Bearer OWNER_TOKEN` on every `/api` call, with `Content-Type: application/json` on writes. A request with no token or a wrong token answers `401`.
- Health: `GET /` returns 200

```bash
#!/bin/sh
# needs: RAILWAY_PUBLIC_DOMAIN, OWNER_TOKEN (variables of the opendots service); also curl.
R="https://$RAILWAY_PUBLIC_DOMAIN"; A="Authorization: Bearer $OWNER_TOKEN"; J="Content-Type: application/json"; B=$(mktemp)
n=0; until [ "$(curl -s -o /dev/null -w '%{http_code}' "$R/")" = 200 ]; do n=$((n+1)); [ "$n" -le 60 ] || break; sleep 5; done
curl -s -o /dev/null -w "health: %{http_code}\n" "$R/"
curl -s -o "$B" -w "read with token: %{http_code}\n" -H "$A" "$R/api/workspace"
S=$(sed -n 's/.*"spaces":\[{"id":"\([^"]*\)".*/\1/p' "$B")
curl -s -o "$B" -w "write with token: %{http_code}\n" -H "$A" -H "$J" -d '{"title":"railway-check","content":"written by the agent contract"}' "$R/api/spaces/$S/pages"
P=$(sed -n 's/^{"id":"\([^"]*\)".*/\1/p' "$B")
curl -s -H "$A" "$R/api/spaces/$S/pages" | grep -c "railway-check" | sed 's/^/page found after write: /'
curl -s -o /dev/null -w "delete with token: %{http_code}\n" -X DELETE -H "$A" -H "$J" "$R/api/spaces/$S/pages/$P"
curl -s -o /dev/null -w "read without token: %{http_code}\n" "$R/api/workspace"
curl -s -o /dev/null -w "write without key: %{http_code}\n" -H "$J" -d '{"title":"anonymous","content":"x"}' "$R/api/spaces/$S/pages"
curl -s -o /dev/null -w "write wrong token: %{http_code}\n" -H "Authorization: Bearer wrong" -H "$J" -d '{"title":"anonymous","content":"x"}' "$R/api/spaces/$S/pages"
```

A fresh deploy prints `health: 200`, `read with token: 200`, `write with token: 201`, `page found after write: 1` and `delete with token: 200`. The refusals print `read without token: 401`, `write without key: 401` and `write wrong token: 401`: a request with no token or a wrong one creates nothing.

## Why Deploy OpenDots on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying OpenDots on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.

- **Agent-ready** - a generated token, a contract block and one script that proves health, an authenticated write, read-back, delete, and the refusal of a read and a write with no token or a wrong one.
- **No setup form and no open API** - the owner token is generated and every `/api` route needs it.
- **Data survives redeploys** - the SQLite database sits on a volume at `/data`.
- **Works behind the Railway edge** - the listen port follows `PORT` and the public origin is set from the generated domain.
- **Pinned** - the upstream source is pinned to a commit and the wrapper image by tag and digest.

## Common Use Cases

- **Shared agent workspace** - give a team and its AI agents one self-hosted place for spaces and pages.
- **Agent-written documentation** - an agent creates, reads and removes pages over the REST API.
- **Self-hosted CopilotKit workspace** - run the OpenDots app on infrastructure you control instead of a hosted service.
- **Notes and knowledge base for AI agents** - keep pages in SQLite on your own volume and read them from scripts.

## Dependencies for OpenDots Hosting

- The opendots service with its volume, created by the template.

### Deployment Dependencies

- [OpenDots repository](https://github.com/CopilotKit/OpenDots)
- [Wrapper image source](https://github.com/bon5co/opendots-railway)


## Similar templates

- [Rocky Linux](https://railway.com/deploy/rocky-linux) — Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀
- [Foundry Virtual Tabletop](https://railway.com/deploy/X5tR6G) — A Self-Hosted & Modern Roleplaying Platform
- [Letta Code Remote](https://railway.com/deploy/letta-code-remote) — Run a Letta Code agent 24/7. No inbound ports, just deploy.

Open this page in a browser: https://railway.com/deploy/opendots-or-just-updated-ai-agent-worksp
