Skip to main content
This is the recommended install. You download one file, set a few secrets, and run one command. PostgreSQL and the app start together; the app creates the schema and runs the scheduled jobs itself. There is no repository to clone.
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

No 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 ${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):
Option B: edit the file. Open 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.
Keep INTEGRATION_CREDENTIALS_KEY safe and never change it after you connect integrations. It encrypts every saved integration credential, and a database restored without it cannot read them.
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

This starts two containers from two images (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.
Choose Create admin account. You become the owner of the new organization and are signed in. The account is verified immediately, so this step needs no email and no Resend.
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_KEY and AUTH_EMAIL_FROM (Resend); without them each link is written to docker compose logs app, where you can copy it.
  • Put it on a domain with HTTPS: Going to production.

Settings

Set any of these in docker-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 new docker-compose.yml (it names the new release’s image) and start it:
If you edited values into the old file, copy them across (keeping them in .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:
The second command adds the table the scheduler records its runs in. Until it has run, the app runs no scheduled jobs. Details: Scheduled jobs.

Backups

Two things must be backed up together:
  1. The database, in the db-data volume. Dump it with pg_dump:
  2. Your INTEGRATION_CREDENTIALS_KEY (the .env file, or your edited docker-compose.yml). A database restored without it cannot decrypt the saved integrations, and each one has to be reconnected.
Call recordings live in Cloudflare R2, not in the database; back up that bucket separately. More in Backups and restore.

Stopping and removing

docker compose down -v also deletes the db-data volume: all your data. Use it only to start over.
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 bundled db, download the override file next to docker-compose.yml:
Add to .env:
then run 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: set APP_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

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 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.
Set PORT=3001 (any free port) in .env and run docker compose up -d again.
More: Troubleshooting.

The full docker-compose.yml

This is the file in the repository root, for copying if you cannot download it.

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.