Aventora CRM Docker Hub Deployment
Deploy files live in the docker/ folder (compose, .env.example, build scripts).
See also: deploy-twenty-vps.md for building directly on the VPS using packages/twenty-docker/ compose files.
This folder provides a clean deployment flow where you:
- Build image from source once (local machine or CI),
- Push image to Docker Hub,
- Pull and run image on client VPS.
This avoids rebuilding on each VPS deploy.
Files
docker-compose.yml- runtime stack for VPS: server, worker, redis (Postgres is external; setPG_DATABASE_*in.env). Compose project name istwenty(matches the legacydocker-compose.aventora.external-db.ymllayout so container/network naming stays consistent).docker-compose.aventora.external-db.yml- thin alias (include:ofdocker-compose.yml) for existing docs/commandsdocker-compose.host-network.yml- optional merge when host Postgres only trusts127.0.0.1inpg_hba(see Troubleshooting)docker-compose.internal-db.yml- optional local Postgres 16; merged when you useup.sh/up.ps1withPG_DATABASE_HOSTempty ordb.env.example- environment template for VPS (see also.env.vpsfor a filled-out multi-workspace example)build-and-push.sh- build and push image to Docker Hubbuild-and-push.ps1- Windows PowerShell build and push scriptup.sh- Linux startup helper (auto internal/external DB mode)up.ps1- Windows startup helper (auto internal/external DB mode)
1) Build and push image to Docker Hub
Prerequisites:
- Docker installed
- Docker Hub repo created (for example
aventoraai/aventora-twenty) - Logged in:
docker login
Run from repo root:
bash docker/build-and-push.sh 2026-04-29.1 https://crm.yourdomain.com aventoraai/aventora-twenty
Windows PowerShell (from repo root):
powershell -ExecutionPolicy Bypass -File .\docker\build-and-push.ps1 -Tag 2026-04-29.1 -ServerUrl https://crm.yourdomain.com -ImageRepo aventoraai/aventora-twenty
If Docker build cache is suspected to be stale, force a clean build:
powershell -ExecutionPolicy Bypass -File .\docker\build-and-push.ps1 -Tag 2026-04-29.1 -ServerUrl https://crm.yourdomain.com -ImageRepo aventoraai/aventora-twenty -NoCache
Arguments:
2026-04-29.1- image taghttps://crm.yourdomain.com- value baked into frontend build (REACT_APP_SERVER_BASE_URL)aventoraai/aventora-twenty- Docker Hub repository
Script pushes:
aventoraai/aventora-twenty:2026-04-29.1aventoraai/aventora-twenty:latest
2) Prepare client VPS
On a fresh Ubuntu VPS:
sudo apt update && sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update && sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker "$USER"
Log out/log in again (or run newgrp docker).
3) Copy deploy files to VPS
Create deploy directory and copy this docker folder there (for example with scp or git checkout).
Example target:
mkdir -p /opt/aventora/crm
cd /opt/aventora/crm
Place these files in /opt/aventora/crm:
docker-compose.yml.env(copied from.env.example)
Create .env:
cp .env.example .env
nano .env
Set at minimum:
DOCKER_IMAGE— omit or useaventora-twenty:latestif you load that image locally; otherwiseaventoraai/aventora-twenty:2026-04-29.1(immutable tag) from the registrySERVER_URL=https://crm.yourdomain.comAPP_SECRET=<openssl rand -base64 32>PG_DATABASE_HOSTandPG_DATABASE_PORT— URL used by the app matches the legacy compose file (postgres://…@${PG_DATABASE_HOST}:${PG_DATABASE_PORT}/…)PG_DATABASE_USER,PG_DATABASE_NAME,PG_DATABASE_PASSWORDHOST_PORT=3000(change if 3000 is already used, for example3001)
4) Pull and start CRM on VPS
If image is private, log in first:
docker login
Then deploy:
docker compose pull
docker compose up -d
docker compose ps
docker compose logs -f server
Automatic DB mode (internal vs external)
Use the helper script so the optional Postgres container is merged automatically from .env:
Linux:
bash ./up.sh
Windows PowerShell:
powershell -ExecutionPolicy Bypass -File .\up.ps1
Rules:
PG_DATABASE_HOSTempty ordb-> mergesdocker-compose.internal-db.yml(starts thedbservice)PG_DATABASE_HOSTset to any other value ->docker-compose.ymlonly (external database; nodbcontainer)
On the VPS, set PG_DATABASE_HOST to your real Postgres host and deploy with plain docker compose up -d (only copy docker-compose.yml; you do not need docker-compose.internal-db.yml unless you want local-dev parity).
Runtime environment config
The image is reusable across environments. Runtime values come from the deploy .env used by Docker Compose (--env-file .env), not from a hidden internal .env in the image.
SERVER_URLin deploy.envcontrols the runtime frontend backend URL config.PG_DATABASE_*,REDIS_URL,APP_SECRET, and other values are also injected from deploy.env.- The same image tag can run in local, staging, and production with different
.envvalues.
Multi-workspace setup (local + production)
For multi-workspace mode, use a subdomain-capable base domain and enable:
IS_MULTIWORKSPACE_ENABLED=trueDEFAULT_SUBDOMAIN=app(or your preferred default)FRONTEND_URLset to the default workspace URL (for examplehttps://app.crm.yourdomain.com)
Notes:
SERVER_URLshould still point to your reachable server base URL.- In multi-workspace mode, frontend API base should resolve to the current browser origin (workspace subdomain) to avoid cross-origin credential issues.
- If your frontend and API are intentionally split across different origins, set
CORS_ALLOWED_ORIGINSto a comma-separated explicit allowlist.
Local development tip:
- Use
*.localhosthostnames (for exampleapp.localhost:3004,workspace-a.localhost:3004) so each workspace can be reached on its own subdomain without extra hosts-file mapping.
4.1) Private Docker Hub repo auth (recommended token flow)
For private repos, use a Docker Hub access token (not your account password):
- In Docker Hub, create an access token.
- On VPS, login with username + token:
echo "<DOCKERHUB_TOKEN>" | docker login -u "<DOCKERHUB_USERNAME>" --password-stdin
- Verify pull access:
docker pull aventoraai/aventora-twenty:2026-04-29.1
- Deploy as usual:
docker compose pull
docker compose up -d
Tips:
- Token must have permission to read the private repository.
- Repeat
docker loginon each VPS node that needs to pull images. - If auth fails, run
docker logoutthen login again with a fresh token.
5) Update to a new release
- Build/push a new tag (
2026-05-01.1) - Change
DOCKER_IMAGEin.env - Run:
docker compose pull
docker compose up -d
Notes
- Prefer immutable tags in production (
YYYY-MM-DD.N) instead of onlylatest. SERVER_URLshould match the public URL users open in browser.- Put a reverse proxy (Nginx/Caddy) in front for HTTPS and proxy to
localhost:3000.
Troubleshooting
Postgres on the host + CRM in Docker: no pg_hba.conf entry for host "172.x.x.x"
Containers reach Postgres via host.docker.internal, but PostgreSQL sees the Docker bridge IP of the container (for example 172.18.0.3), not 127.0.0.1. If pg_hba.conf only allows localhost, connections are rejected.
Option A — one-line Postgres change (typical on Ubuntu)
Edit pg_hba.conf (often /etc/postgresql/<version>/main/pg_hba.conf) and allow Docker bridge ranges with the same auth method as your other host lines (often scram-sha-256):
host all all 172.16.0.0/12 scram-sha-256
Then:
sudo systemctl reload postgresql
Option B — no pg_hba edit (Linux): host networking
Merge docker-compose.host-network.yml so the API and worker use host network mode and connect to Postgres at 127.0.0.1 (same as a local client). Redis stays on the bridge with 127.0.0.1:6379 published.
docker compose -f docker-compose.yml -f docker-compose.host-network.yml --env-file .env up -d --force-recreate
The API listens on the host on port 3000 (or NODE_PORT inside the image). Put your reverse proxy in front as usual. Requires Linux (VPS); Docker Desktop behavior differs.
Confirm postgresql.conf has listen_addresses so localhost TCP works (listen_addresses often includes localhost already).
Docker build: TypeError: LRU is not a constructor
If Docker build fails with TypeError: LRU is not a constructor during npx nx build twenty-front:
- Re-run with a clean build:
powershell -ExecutionPolicy Bypass -File .\docker\build-and-push.ps1 -Tag 2026-04-29.1 -ServerUrl https://crm.yourdomain.com -ImageRepo aventoraai/aventora-twenty -NoCache
- If it still fails, prune build cache and retry:
docker builder prune -af
- Ensure Docker Desktop is up to date and has enough memory allocated.
The PowerShell script now fails fast if build/tag/push fails, so it will not print a successful deploy message after a failed build.
TIPS Services integration
When enabling TIPS CRM sync, set TIPS env vars in deploy .env and run bootstrap + sync after the stack is up. See CRM Complete Guide — TIPS Services sync.
Related docs
- deploy-twenty-vps.md — build-on-VPS flow using
packages/twenty-docker/compose files - CRM Complete Guide — upgrade, CLI, TIPS, SSO, Sales Cockpit
- Aventora customizations (engineer index) — fork feature code map