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
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:8090and 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 apostgres://…URL. - MYCRM_MAIL
logwrites sign-in links to the journal;sendgridactually sends them.- MYCRM_SENDGRID_KEY
- Your SendGrid API key, when mail is
sendgrid. - MYCRM_MAIL_FROM
- The sending address, plus
MYCRM_MAIL_FROM_NAMEfor the display name. - MYCRM_MASTER_KEY
- Optional. Base64 of 32 random bytes. If you leave it unset,
<data>/master.keyis 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
/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"
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.
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
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.
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.