Skip to main content

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:

  1. Build image from source once (local machine or CI),
  2. Push image to Docker Hub,
  3. 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; set PG_DATABASE_* in .env). Compose project name is twenty (matches the legacy docker-compose.aventora.external-db.yml layout so container/network naming stays consistent).
  • docker-compose.aventora.external-db.yml - thin alias (include: of docker-compose.yml) for existing docs/commands
  • docker-compose.host-network.yml - optional merge when host Postgres only trusts 127.0.0.1 in pg_hba (see Troubleshooting)
  • docker-compose.internal-db.yml - optional local Postgres 16; merged when you use up.sh / up.ps1 with PG_DATABASE_HOST empty or db
  • .env.example - environment template for VPS (see also .env.vps for a filled-out multi-workspace example)
  • build-and-push.sh - build and push image to Docker Hub
  • build-and-push.ps1 - Windows PowerShell build and push script
  • up.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 tag
  • https://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.1
  • aventoraai/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 use aventora-twenty:latest if you load that image locally; otherwise aventoraai/aventora-twenty:2026-04-29.1 (immutable tag) from the registry
  • SERVER_URL=https://crm.yourdomain.com
  • APP_SECRET=<openssl rand -base64 32>
  • PG_DATABASE_HOST and PG_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_PASSWORD
  • HOST_PORT=3000 (change if 3000 is already used, for example 3001)

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_HOST empty or db -> merges docker-compose.internal-db.yml (starts the db service)
  • PG_DATABASE_HOST set to any other value -> docker-compose.yml only (external database; no db container)

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_URL in deploy .env controls 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 .env values.

Multi-workspace setup (local + production)

For multi-workspace mode, use a subdomain-capable base domain and enable:

  • IS_MULTIWORKSPACE_ENABLED=true
  • DEFAULT_SUBDOMAIN=app (or your preferred default)
  • FRONTEND_URL set to the default workspace URL (for example https://app.crm.yourdomain.com)

Notes:

  • SERVER_URL should 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_ORIGINS to a comma-separated explicit allowlist.

Local development tip:

  • Use *.localhost hostnames (for example app.localhost:3004, workspace-a.localhost:3004) so each workspace can be reached on its own subdomain without extra hosts-file mapping.

For private repos, use a Docker Hub access token (not your account password):

  1. In Docker Hub, create an access token.
  2. On VPS, login with username + token:
echo "<DOCKERHUB_TOKEN>" | docker login -u "<DOCKERHUB_USERNAME>" --password-stdin
  1. Verify pull access:
docker pull aventoraai/aventora-twenty:2026-04-29.1
  1. Deploy as usual:
docker compose pull
docker compose up -d

Tips:

  • Token must have permission to read the private repository.
  • Repeat docker login on each VPS node that needs to pull images.
  • If auth fails, run docker logout then login again with a fresh token.

5) Update to a new release

  1. Build/push a new tag (2026-05-01.1)
  2. Change DOCKER_IMAGE in .env
  3. Run:
docker compose pull
docker compose up -d

Notes

  • Prefer immutable tags in production (YYYY-MM-DD.N) instead of only latest.
  • SERVER_URL should 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:

  1. 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
  2. If it still fails, prune build cache and retry:
    • docker builder prune -af
  3. 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.