Why developer teams self-host Twenty instead of paying for Salesforce
Most CRMs are designed for sales managers, not engineers. The schema is fixed, the API is rate-limited, and every integration goes through a proprietary marketplace. Twenty inverts this: every entity (contacts, companies, deals, or any custom object you define) is modelled in PostgreSQL and exposed through a fully documented GraphQL API from day one. You own the database, you write migrations, and you integrate with your own tooling — no middleware, no per-API-call billing.
What you get out of the box
- Fully customisable objects and fields — model any entity your business uses, not just the ones Salesforce decided on.
- Kanban, list and table views with real-time collaborative updates across your team.
- Notes, tasks and activity timeline attached to every record — no separate plugin required.
- GraphQL + REST API covering every object, relationship and custom field you create.
- Background worker for automations, webhooks and scheduled jobs — runs alongside the server container.
- CSV import for migrating contacts and companies from HubSpot, Pipedrive or any legacy CRM.
- AGPL-3.0 licence — no vendor lock-in, no per-seat cloud billing, no data stored off your infrastructure.
Prerequisites
A 2 vCPU / 4 GB RAM VPS running Ubuntu 22.04 with Docker installed covers production comfortably. The full stack (server + worker + PostgreSQL + Redis) idles around 1.2 GB RAM; plan 4 GB to keep PostgreSQL breathing room under concurrent queries. A domain name and a Caddy or Nginx reverse proxy for HTTPS. That is everything — no GPU, no licence key, no external service.
Deploy Twenty on a VPS in 6 steps
Provision the VPS
Order a ServOrbit VPS (4 GB RAM, 2 vCPU, Ubuntu 22.04). Once it boots, SSH in and install Docker: curl -fsSL https://get.docker.com | sh. Enable the Docker service: systemctl enable --now docker.
Create your .env file
Create /opt/twenty/.env with four variables: APP_SECRET (generate with openssl rand -hex 32), DB_NAME=twenty, DB_USER=twenty, DB_PASSWORD=<strong-password> and SERVER_URL=https://crm.yourdomain.com (set it now — Twenty embeds this in CORS headers and email links). APP_SECRET is the only cryptographic secret; everything else is derived from it.
Write docker-compose.yml and bring the stack up
Create /opt/twenty/docker-compose.yml with the four services: db (postgres:16-alpine), redis (redis:7-alpine), twenty-server (twentycrm/twenty:latest, port 3000) and twenty-worker (same image, command yarn worker:prod). Connect them via PG_DATABASE_URL and REDIS_URL. Then: docker compose up -d. On first boot, Twenty runs database migrations — allow 60–90 seconds before the UI is ready.
Complete the workspace setup
Open http://<vps-ip>:3000 and follow the setup wizard: create your admin account, name the workspace, and optionally invite teammates by email. Import existing contacts from a CSV in workspace settings → Import.
Put Twenty behind HTTPS with Caddy
Install Caddy: apt install -y caddy. Create /etc/caddy/Caddyfile: crm.yourdomain.com { reverse_proxy localhost:3000 }. Reload: systemctl reload caddy. Caddy obtains and renews the TLS certificate automatically. Restrict port 3000 in your firewall: ufw deny 3000 — all traffic now goes through 443.
Connect your automation tools
In Twenty settings → API, copy your GraphQL endpoint and personal API token. Use them directly in n8n (HTTP Request node) or Activepieces to sync contacts, trigger actions on deal stage changes, or push data from external sources. Twenty also fires outbound webhooks on any record event — configure them in settings → Webhooks.
Logging in for the first time
Open the URL and click "Sign up": the first person to register automatically becomes the administrator of the workspace, and registrations then close. Do it immediately after installation.
Back up the three Docker volumes — twenty_db (PostgreSQL data), twenty_data (local file storage) and twenty_redis (only needed if you use persistent job queues) — to an off-server location daily. A simple docker run --rm -v twenty_db:/data -v /backups:/out alpine tar czf /out/twenty-db-$(date +%F).tar.gz /data one-liner in a cron job covers the database.
The Official Documentation
For advanced configuration and tool-specific options, refer to the official Twenty documentation. This guide covers going live on a VPS; the vendor's documentation remains the reference for fine-tuning, major upgrades and specific use cases.