MyCRM
Self-hosting

One binary. Your server. About an afternoon.

MyCRM is a single static Go binary with the web UI compiled into it. There is no Node runtime to install, no container registry to log into, no cache and no message queue. If you can run systemctl, you can run this.

What you need

The box

  • Linux on x86-64 with systemd
  • One vCPU and 1 GB of memory is comfortable at small-team scale
  • Disk for the database and the data directory — contacts and events are small; plan for growth in events, not records
  • No Docker required. Native is the supported path

The network

  • A DNS name pointing at the box
  • TLS — the Caddy config below obtains and renews the certificate
  • Outbound HTTPS to whatever you connect (your commerce backend, Stripe, SendGrid) and to your mail provider
  • Nothing inbound except 80 and 443. The app itself binds to loopback
The install

Six steps, in order.

1. Build the binary

From a checkout of the source, on any machine with a Go toolchain:

GOOS=linux GOARCH=amd64 go build -o mycrm ./cmd/mycrm

Copy mycrm and the contents of deploy/ to the target box.

2. Run the installer

As root, from the directory holding those files. It is idempotent, so re-running it on an upgrade is safe.

sudo ./install.sh ./mycrm

It creates a mycrm system user, makes /opt/mycrm/data, installs the binary and the systemd unit, copies the example environment file to /opt/mycrm/mycrm.env with mode 600, and enables the service. The unit runs with NoNewPrivileges, ProtectSystem=strict, ProtectHome and a single writable path.

3. Fill in the environment file

Edit /opt/mycrm/mycrm.env. Every setting has a command-line equivalent; mycrm -h lists them.

MYCRM_ADDR
Listen address. Keep it on 127.0.0.1:8090 and let the reverse proxy hold the public port.
MYCRM_BASE_URL
Your public URL. Sign-in links are built from it, so a wrong value emails your team a link that does not work.
MYCRM_DATA
Data directory. Holds the master key and, by default, the SQLite database.
MYCRM_DB
Leave unset for SQLite at <data>/mycrm.db, or set a postgres://… URL.
MYCRM_MAIL
log writes sign-in links to the journal; sendgrid actually sends them.
MYCRM_SENDGRID_KEY
Your SendGrid API key, when mail is sendgrid.
MYCRM_MAIL_FROM
The sending address, plus MYCRM_MAIL_FROM_NAME for the display name.
MYCRM_MASTER_KEY
Optional. Base64 of 32 random bytes. If you leave it unset, <data>/master.key is generated on first boot.
MYCRM_DEV
Never set this on a server that is reachable from the internet. In dev mode sign-in links come back in the API response, which is account takeover for anyone who can reach the port.

Then sudo systemctl restart mycrm.

4. Back up the master key

Do this before you put real data in. /opt/mycrm/data/master.key seals every connector credential in the database. Lose it and your records survive, but the stored API keys do not — you will re-enter every one of them by hand. Copy it somewhere that is not the same disk, and treat it like a password.

5. Create the first admin

There is no signup page and no default password to change, because there are no passwords.

sudo -u mycrm /opt/mycrm/mycrm -data /opt/mycrm/data \
  user add you@example.com -name "You" -role admin

Then visit /login, type that address, and follow the link that arrives. Turn on TOTP from the account menu → Profile & security once you are in. Help: getting in walks the whole sequence, including what an expired link looks like.

6. Put a reverse proxy in front

The Caddy snippet ships in deploy/Caddyfile.snippet. Caddy handles the certificate for you.

crm.example.com {
    encode zstd gzip
    reverse_proxy 127.0.0.1:8090
}

Nginx or HAProxy work equally well — MyCRM only needs the proxy to pass the Host header and terminate TLS.

Then: connect something

Connectors are normally added from Settings → Connectors in the UI, where the credential is sealed as you save it — Help: connectors has the required fields for each kind, and the webhook URL SendGrid needs. The CLI does the same thing if you prefer to script provisioning:

sudo -u mycrm /opt/mycrm/mycrm -data /opt/mycrm/data \
  connector add apihub -url https://api.example.com -key "$PARTNER_KEY"
Day two

Running it after the install.

SQLite or PostgreSQL

Both dialects run the same schema and the same test suite. SQLite is one file, needs no server, and is the right answer for a team of five. Move to PostgreSQL when you want concurrent writers, streaming backups or a replica — it is a change to one environment variable plus a data migration.

Updates

Replace the binary and restart the unit. Schema changes apply on boot. Because the license is perpetual and the binary is yours, an update is something you choose to do, not something that happens to you on a Tuesday.

Backups

Copy the data directory and the database together, from the same moment. For SQLite that is one directory. For PostgreSQL it is the data directory plus a dump. A database restored without its matching master.key keeps every record and loses every sealed credential.

Health checks

/healthz answers when the process is up; /readyz answers only when the database is reachable. Point your monitoring at /readyz — that is the one that catches a full disk.

Scope

What self-hosting does and does not include.

Included

  • The same binary our hosted instances run. There is no hosted-only feature
  • The web UI, embedded — no separate front-end to build or serve
  • Both database engines, both supported
  • The install script, systemd unit and Caddy snippet
  • The full REST API and scoped API keys
  • Endpoint-by-endpoint API documentation in the source tree

Not included

  • Access to your instance. We cannot see your data, which also means we cannot look at it to debug something for you
  • Your backups, your monitoring, your operating-system patching
  • Automatic updates. You choose when
  • Any phone-home. The binary makes no outbound calls except the connectors you configure and the mail provider you set
Where the documentation lives. The install script, systemd unit and Caddy snippet are in deploy/; the HTTP contract is in docs/API.md; the design rationale is in docs/PLAN.md. They ship with the source rather than living on this site, so the docs you read are the ones matching the binary you are running. Ask us for repository access. Day-to-day use of the running instance is on the Help page.
Stuck at step three?

We will walk it with you.

Send us what you are running — distribution, database, proxy — and we will tell you what is different about your setup before you find out the hard way.