Run OpenD on Railway
One Railway project runs one OpenD instance: a web service, a worker, Postgres and a bucket.
About this task
On Railway the web service and the worker are separate services that cannot share a disk, so blobs go
to a Railway Bucket. Railway has deprecated railway.json, so apply the settings
below per service, in the dashboard or through the Railway API. See
Railway's documentation for the platform itself.
- Create a project and add Postgres and a Bucket.
-
Add two services from this repository,
webandworker, both buildingdeploy/Dockerfile, and configure them.Setting web worker Source this repository, branch mainsame Dockerfile path deploy/Dockerfilesame Start command node dist/bin.js servenode dist/bin.js workerPre-deploy node dist/bin.js migratenone Healthcheck /healthz, timeout 120 snone Restart policy on failure, 5 retries always Watch paths packages/**,deploy/Dockerfile,package.json,pnpm-lock.yamlsame Public domain yes, port 3000 no A start command replaces the image's entry point, so always give the full
node dist/bin.js <command>. Watch paths keep docs-only commits from redeploying the app: docs reach readers through the worker, not through a redeploy. -
Set the variables on both services, using reference variables for Postgres and the bucket.
DATABASE_URL=${{Postgres.DATABASE_URL}} S3_BUCKET=${{Bucket.BUCKET}} S3_ENDPOINT=${{Bucket.ENDPOINT}} S3_ACCESS_KEY_ID=${{Bucket.ACCESS_KEY_ID}} S3_SECRET_ACCESS_KEY=${{Bucket.SECRET_ACCESS_KEY}} S3_REGION=${{Bucket.REGION}} PUBLIC_URL=https://<web domain> SESSION_SECRET=<openssl rand -hex 32> OPEND_ADMIN_TOKEN=<openssl rand -hex 32> GITHUB_WEBHOOK_SECRET=<openssl rand -hex 32> NODE_ENV=productionReplace
Bucketwith your bucket service's name. Railway buckets use virtual-hosted addressing, so leaveS3_FORCE_PATH_STYLEunset. Add theOIDC_*variables for reader sign-in, andOPEND_EMBED_SECRETandOPEND_EMBED_ORIGINSto embed help in your apps. -
Deploy, and wait for
webto report healthy.Its pre-deploy step creates the schema. The worker retries until the schema exists.
-
Register the docs repository, and add organizations and readers, through the admin API.
curl -X POST "$PUBLIC_URL/admin/api/repos" -H "authorization: Bearer $OPEND_ADMIN_TOKEN" \ -H 'content-type: application/json' \ -d '{"fullName":"acme/docs","sourceUrl":"https://github.com/acme/docs.git","releaseRefs":["main","v*"]}' -
Publish: point a GitHub webhook at
$PUBLIC_URL/webhooks/github, or trigger a build directly.curl -X POST "$PUBLIC_URL/admin/api/repos/1/builds" -H "authorization: Bearer $OPEND_ADMIN_TOKEN" \ -H 'content-type: application/json' -d '{"ref":"main","sha":"<full commit sha>"}'
Results
A public demo can set NODE_ENV=development and OPEND_DEV_LOGIN=1 so
visitors pick a sample reader. Never do this with real content.
To add the web editor, create a third service from the same Dockerfile with the start command
node dist/bin.js editor serve and its own domain. See Run the web editor.
Tagged releases are published as images to ghcr.io/desktopmachineshop/opend, so a
service can deploy an image tag instead of building from the repository.