1
Check the requirements
- A Linux, macOS or Windows machine with Docker and Docker Compose (any current version; 2.24 or newer if you use your own PostgreSQL).
- About 5 minutes. The first start downloads the image.
- For a public server: a domain pointing at it and an HTTPS reverse proxy (see Going to production).
2
Create a folder and get docker-compose.yml
curl? Create docker-compose.yml in the folder with your editor and paste the full file below.3
Set your secrets
Every setting is listed by name in the file as Option B: edit the file. Open
${NAME:-default}. The ones you must replace are marked # CHANGEME and carry a changeme-... placeholder: your public APP_URL and four secrets. You can set them in either of two ways, and mix them freely.Option A: write a .env file. Docker Compose reads a .env next to docker-compose.yml, and a value there wins over the default in the file. This one command writes it with fresh random secrets (replace the APP_URL line with your own address; leave it as is to try ReachCrew on your own machine):docker-compose.yml and replace each changeme-... value after the :- with the output of openssl rand -hex 32. Leave APP_URL pointing where people will reach ReachCrew.On
http://localhost the app starts even with the placeholders, so you can try it out without setting anything. With any other APP_URL it refuses to start (the log says which names still have a CHANGEME placeholder) until each secret is replaced, because the placeholders are public knowledge.4
Start it
postgres:18-alpine and ghcr.io/rishav887/reachcrew):Check that it is up and watch the logs:
5
Create your admin account
Open your
APP_URL (http://localhost:3000 by default). While no account exists, every page sends you to /setup. Fill in:- Name: your name.
- Organization: the name of your workspace. Everything in ReachCrew belongs to an organization.
- Email and Password: what you will sign in with.
6
Next steps
- Connect your services in Settings: Google Workspace for Gmail, Unipile for LinkedIn and WhatsApp, Cloudflare R2 for recordings, OpenRouter for AI, and enrichment providers. They are connected inside the app, per organization, never in this file. Overview: Integrations.
- Invite teammates from Settings, Members. Invitation email needs
RESEND_API_KEYandAUTH_EMAIL_FROM(Resend); without them each link is written todocker compose logs app, where you can copy it. - Put it on a domain with HTTPS: Going to production.
Settings
Set any of these indocker-compose.yml or in .env (a .env value wins). Everything not marked CHANGEME is optional.
Every other variable in the configuration reference can be added to the
environment block the same way. Run docker compose up -d again after any change to recreate the containers.
Upgrading
Back up first (see Backups), read the release notes for any migration, then download the newdocker-compose.yml (it names the new release’s image) and start it:
.env avoids this). The app only creates a schema in an empty database; it does not upgrade an existing one. Migration steps are in Upgrading.
From 0.2.0: the new file has two containers, not four. Replace your docker-compose.yml with the new one, then:
Backups
Two things must be backed up together:-
The database, in the
db-datavolume. Dump it withpg_dump: -
Your
INTEGRATION_CREDENTIALS_KEY(the.envfile, or your editeddocker-compose.yml). A database restored without it cannot decrypt the saved integrations, and each one has to be reconnected.
Stopping and removing
Do not scale
app to more than one replica: the outreach sender loop has no distributed lock, and two instances would each send.Use your own PostgreSQL
To use a PostgreSQL 16+ you already run (a hosted one, for example) instead of the bundleddb, download the override file next to docker-compose.yml:
.env:
docker compose up -d as usual. The bundled db is not started (POSTGRES_PASSWORD goes unused), and the app creates the schema in your database on first start, so it must be empty then. This needs Docker Compose 2.24 or newer.
Build from source
To run your own changes instead of the published image, clone the repository and run:Going to production
Before real users arrive: setAPP_URL to your public HTTPS address, replace every CHANGEME, put HTTPS in front of port 3000 (Your own domain adds Caddy with one more file), and connect Resend so invitations are emailed. Going to production covers the domain, HTTPS, email, webhooks and backups in full.
Troubleshooting
The app exits: APP_URL is ... but these still have their CHANGEME placeholder
The app exits: APP_URL is ... but these still have their CHANGEME placeholder
You set a public
APP_URL but left a changeme-... secret. Replace each name the message lists (openssl rand -hex 32), then run docker compose up -d.The app cannot reach the database after I changed POSTGRES_PASSWORD
The app cannot reach the database after I changed POSTGRES_PASSWORD
The database stores its password on its first start; a later change is ignored by it while the app uses the new one. Set the old value back, or change the password inside PostgreSQL (
ALTER USER reachcrew PASSWORD '...') first.Sign-in links point at localhost
Sign-in links point at localhost
Set
APP_URL to your public address and run docker compose up -d again.Port 3000 is already in use
Port 3000 is already in use
Set
PORT=3001 (any free port) in .env and run docker compose up -d again.The full docker-compose.yml
This is the file in the repository root, for copying if you cannot download it.docker-compose.yml
docker-compose.yml
Next
Going to production
Domain, HTTPS, email, backups, upgrades.
Integrations
Connect Gmail, Unipile, R2, OpenRouter.
Configuration reference
Every environment variable.
Troubleshooting
Real error messages and fixes.