Deploy on Railway
Railway runs the published images and generates every secret itself. You supply two hostnames from a domain you own. The template wires the rest: Postgres, a storage bucket, and the four services of a full It's a Plan instance.
Verified template · AGPL-3.0 · No build step
What the template starts
The template creates six resources in one Railway project:
- PostgresThe database, on a Railway volume. The api applies its migrations when it starts.
- BucketRailway object storage, for issue attachments.
- apiThe HTTP API and the auth handler, on port
3000. - webThe web app people sign in to, on port
3001. - workerWebhook deliveries, notifications, schedules and agent runs.
- botThe Telegram bot. It idles until you give it a token.
Railway builds nothing. Each service pulls its image from ghcr.io/croffasia/itsaplan-<service> at the latest tag, which is the newest published release. Railway bills for what these resources use; the rates are on Railway pricing.
Before you start
Two things before the deploy:
- A Railway accountThe template deploys into a project of your own. Nothing here is run by this project.
- A domain you controlYou need two hostnames under one registrable domain, and the right to add DNS records for them.
The domain is not optional. Railway generates *.up.railway.app hostnames, and those are on the Public Suffix List: a browser then reads each service as a separate site and refuses the session cookie. Sign-in returns 200 and the login page comes straight back.
Two hostnames under one registrable domain solve this, because the cookie is issued on the parent they share. This page uses these two as the example:
- api.example.comthe api
- app.example.comthe web app
Deploy
1Open the template
Railway asks for a project name and a region, then shows the six resources.
2Fill in the two fields on the web service
API_URLishttps://api.example.com, andAPP_URLishttps://app.example.com. Give the full origin, withhttps://and no trailing slash. You set each value once: the api reads both by reference, and web readsAPI_URLat startup and hands it to the browser on every render.3Deploy
Railway generates the secrets, creates the database and the bucket, and starts the services. The api runs the migrations on its first start.
4Attach your hostnames
Until you do, the services answer on Railway hostnames, and sign-in does not work on those. The steps are in Attach the hostnames.
Environment variables
Two variables are yours. Set them on the web service, at deploy time:
- API_URLPublic origin of the api. Example:
https://api.example.com. - APP_URLPublic origin of the web app. Example:
https://app.example.com.
The template sets the rest. You do not enter these, and you do not keep them:
- DATABASE_URLA reference to the Postgres service.
POSTGRES_PASSWORDis generated per deploy. - BETTER_AUTH_SECRETSigns the sessions. Generated per deploy.
- APP_ENCRYPTION_KEYEncrypts the provider keys stored in the database. Generated per deploy.
- S3_*Endpoint, bucket and credentials of the Railway bucket.
S3_FORCE_PATH_STYLEisfalsehere, because the bucket serves virtual-host style URLs. The RustFS stack in the Compose file needs the default instead.
No secret is stored in the template, so every deploy has its own. Mail, AI provider keys, single sign-on and the Telegram bot token are not environment variables: you configure them in the interface after you sign in.
.env.example lists every variable the product reads, including the optional ones.
Attach the hostnames
After the deploy, open each service and add its hostname under Settings → Networking → Custom Domain:
- api
api.example.com, port3000 - web
app.example.com, port3001
Here Railway wants the bare hostname, with no scheme. This is different from the variables above, which carry https://.
Railway then shows a CNAME record and a TXT record for each hostname. Add them at your DNS provider. Behind Cloudflare, keep both records unproxied (DNS only), or the certificate is never issued.
First sign-in
Open APP_URL and register. The first account becomes the instance admin, and admin settings open from there: mail provider, AI providers, single sign-on, the Telegram bot token, and who may register.
Changing a hostname later
Edit API_URL or APP_URL on the web service. Both services restart and serve the new address, and nothing is rebuilt. Then attach the new hostnames as above and remove the old ones.
Updates
Every service ships with auto updates on, in the 02:00 to 06:00 UTC window. Railway watches the latest tag in GHCR and redeploys a service once a release pushes a new image. The api applies the new migrations when it starts, so an upgrade needs no step of yours.
To switch it off for a service, or to narrow the window, open Settings → Source → Configure Auto Updates.
Troubleshooting
Sign-in returns to the login page.
The two hostnames are not under one registrable domain, or they are still the generated *.up.railway.app ones. The browser drops the session cookie. Move both services to your own domain and correct API_URL and APP_URL.
The custom domain stays on 'Waiting for DNS'.
The CNAME record or the TXT record is missing at your DNS provider, or the record is proxied. Behind Cloudflare, set both to DNS only.
The web app loads, but every request to the api fails.
API_URL does not match the hostname attached to the api service. It has to be the full origin, with https:// and no trailing slash. Web reads it at startup, so it takes effect when the service restarts.
Attachments do not upload.
The S3_* variables on the api no longer match the bucket. Restore the values the template set, with S3_FORCE_PATH_STYLE on false.
The bot service runs, but the Telegram bot answers nothing.
The token is a setting, not a variable. Add it in the app, under the admin settings. The bot re-reads its configuration from the database and starts on its own.
For anything else, read the service logs first: open the service, then Deployments → View logs.
Support
- Product or templateReport it in GitHub issues.
- Questions and setup helpAsk in GitHub discussions.
- Railway itselfDomains, regions, volumes and billing are Railway’s side: Railway help station.
- This guideIt ships with the source as docs/railway.md.
Other ways to run it: Docker Compose, Coolify, Kubernetes.