Deploy Twenty CRM | Server, Worker, Postgres and Redis, All Pinned
Server, worker, Postgres and Redis. Pinned, and the worker actually runs.
Postgres
Just deployed
/var/lib/postgresql/data
Twenty worker
Just deployed
Redis
Just deployed
/data
Twenty
Just deployed
/app/packages/twenty-server/.local-storage
Deploy and Host Twenty CRM on Railway
Twenty, the open-source CRM, self-hosted as four services: the server, the background worker, Postgres and Redis. Every image is pinned.
Nothing to fill in. Open the domain and create the first account.
About Hosting Twenty CRM
The four services are wired together the way Twenty's own compose file does it, adapted for this platform:
- Server: the API and the app, with a volume for uploaded files
- Worker: the background job runner, on the same image, started with
yarn worker:prod - Postgres 16 and Redis 8, each on its own volume
The worker is the part people skip. Without it, jobs queue up in Redis and nothing runs them: no email sync, no calendar sync, no cron. Here it is a separate service, because that is what it is.
The first sign-up happens in the browser, at the domain.
Common Use Cases
- A self-hosted CRM whose data lives in your own Postgres database rather than a vendor's.
- Email and calendar sync that actually runs, because the worker that processes those jobs is deployed alongside the server instead of left out.
- A base for integrations over Twenty's REST API.
Dependencies for Twenty CRM Hosting
Deployment Dependencies
- Twenty
twentycrm/twenty:v2.31.1, the server (public) - Twenty worker
twentycrm/twenty:v2.31.1, the background job runner (private) - Postgres
postgres:16.11-alpine - Redis
redis:8.6.5-alpine - Twenty, by Twenty PBC, AGPL-3.0. This template only configures their published images.
Implementation Details
- Migrations run on the server, not the worker. The worker sets
DISABLE_DB_MIGRATIONSandDISABLE_CRON_JOBS_REGISTRATION, so two services starting at once cannot both try to migrate the same database. - The worker shares the server's
APP_SECRETby reference, not a second generated value. The two have to match, and a template that generated two would look fine and then fail in a way that is hard to trace. - Redis binds both IPv4 and IPv6. The private network here is IPv6, and the default Redis config listens on neither usefully.
- Logs are set to
error,warn. At default verbosity Twenty exceeds the platform's log rate limit even on a quiet instance; while testing this template, hundreds of messages were dropped per second.
Configuration
APP_SECRET and both database passwords are generated. SERVER_URL follows the public domain.
Files are stored on the server's volume (STORAGE_TYPE=local). For S3, set STORAGE_TYPE=s3 and the STORAGE_S3_* variables from Twenty's documentation.
Verification
Deployed from this template: /healthz returns status: ok, the app is served, the REST API answers unauthenticated calls with 403 rather than 404, and the worker's own log shows it processing jobs off the cron-queue through BullMQ, which only happens if the server, Redis and the worker are all talking to each other.
The first sign-up is a browser flow and was not driven during testing.
Why Deploy Twenty CRM 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 Twenty CRM 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.
Template Content
Postgres
postgres:16.11-alpineTwenty worker
twentycrm/twenty:v2.31.1Redis
redis:8.6.5-alpineTwenty
twentycrm/twenty:v2.31.1