Docs · Get started

Self-hosting

MagpieCRM is one Docker image and one persistent volume. This page takes you from an empty server to a working copy. For every setting, see Environment variables.

Checked against magpiecrm@0.9.23 · Updated

What you need

  • A server with Docker and Docker Compose. The container listens on port 3000 and runs as a non-root user.
  • A public HTTPS address for it, such as https://crm.example.com, behind your own reverse proxy. Links in emails, bounce webhooks and AI apps that connect from the cloud all need to reach it.
  • A SocialFetch API key for prospect data. You pay SocialFetch directly.
  • An account with an email provider, or an SMTP server, to send from.
  • For email verification, a verification server with outbound port 25, or proxies that have it. See Email verification.

Your data is a single JSON file on the volume, with uploaded images in an uploads/ folder next to it.

Run the image

The image is ghcr.io/magpiecrm/magpie-crm-app. Each release is published as a version tag, so pin one rather than latest, which follows every change to the main branch. The current version is 0.9.23; the releases page lists the rest.

Save this as compose.yaml and fill in your own values:

compose.yaml
services:
  magpie:
    image: ghcr.io/magpiecrm/magpie-crm-app:0.9.23
    restart: unless-stopped
    ports: ["3000:3000"]
    environment:
      NODE_ENV: production
      HOME: /data                  # the volume
      DATABASE_PATH: /data/db.json # your data
      PUBLIC_URL: https://crm.example.com
      AUTH_EMAIL: you@example.com
      AUTH_PASSWORD: choose-a-password
      TRACKING_SECRET: generate-me # set once
      SUPPRESSION_SECRET: generate-me # set once, never rotate
      WEBHOOK_SECRET: generate-me  # turns on bounce and complaint webhooks
      SOCIALFETCH_API_KEY: sfk_...
    volumes: [magpie-data:/data]
volumes:
  magpie-data:

Then run docker compose up -d. HOME points at the volume because the container gives its user ownership of $HOME at start, which makes the volume writable.

Generate the secrets

Generate each secret separately:

Terminal
openssl rand -hex 32   # TRACKING_SECRET
openssl rand -hex 32   # SUPPRESSION_SECRET
openssl rand -hex 32   # WEBHOOK_SECRET
  • TRACKING_SECRET is required with NODE_ENV=production. It signs tracking and unsubscribe links and encrypts the provider keys you save in Settings. Set it once: changing it makes those saved keys unreadable.
  • SUPPRESSION_SECRET is recommended. It keys the hashes behind the opt-out, unsubscribe and bounce lists, and falls back to TRACKING_SECRET. Never rotate it, or people who opted out come back.
  • WEBHOOK_SECRET turns on the bounce and complaint webhooks. Without it they refuse every request. See Sending and deliverability.

Secrets live in the environment

They can't be changed in the app. Set them where you deploy, before the first start.

First sign-in

Open your PUBLIC_URL (or port 3000 on the server) and sign in with AUTH_EMAIL and AUTH_PASSWORD. That's the first login. If you forget its password, change AUTH_PASSWORD and restart: the password is reset to the new value.

Set PUBLIC_URL to the address people reach the app on. It's used for links the server builds for others to open: tracking and unsubscribe links, images in emails, survey links and webhook addresses. Unset, the app uses the host of the incoming request.

Fill in Settings

  1. Data source: add your SocialFetch API key (it starts sfk_) and press Test connection. A key saved here takes priority over SOCIALFETCH_API_KEY.
  2. Sending: choose your provider, enter its credentials, set a default sender and send a test email. Add the addresses you send from under Sender addresses. Until a provider is set up, email is only logged, not sent.
  3. Email verification: connect your verification server with its URL and secret, then press Test verification. See Email verification.
  4. Team and login: add the people who should sign in, each with an email and a password, and change your own password. There are no roles: everyone can do everything.

Optional: add your own Anthropic or OpenAI API key under Copilot, and create keys for AI apps under Connect AI apps (see MCP server).

Updating

  1. Back up the volume first. It holds all your data.
  2. Change the image tag in compose.yaml to the newer version, then pull and restart:
    Terminal
    docker compose pull
    docker compose up -d

A new version reads the previous version's data: data changes are additive, and there's no migration command to run. Anything you need to do yourself is in the release notes.

Running from source

You need Bun installed. Put the same variables in a .env file in the project root, then build and start:

Terminal
git clone https://github.com/magpiecrm/magpie-crm-app.git
cd magpie-crm-app
bun install && bun run build && bun run start

Without DATABASE_PATH the data file is local_db.json in the working directory. The full guide, including every variable, is in the README on GitHub.

Something wrong or missing? Email pele@magpiecrm.com or open an issue.