Self-hosting guide
One Rust binary, one PostgreSQL. If you can run Docker Compose, you can run your own mail platform.
What you need
- A Linux host with Docker (1 vCPU / 1 GB is enough to start).
- A domain, plus DNS control for it.
- Outbound port 25 — many clouds block it by default;
request unblocking (AWS/Hetzner/OVH all have a form for it) or relay
through
smtp_relays. - Reverse DNS (PTR) on your sending IP, matching your SMTP hostname.
Boot the stack
git clone https://github.com/camelmailer/camelmailer && cd camelmailer cp .env.example .env # set POSTGRES_PASSWORD docker compose up -d --build curl http://localhost:5000/health
This starts PostgreSQL, runs migrations, and launches the HTTP API
(:5000), the SMTP server
(:25) and the delivery worker.
First account & first mail
# an admin login for the dashboard docker compose exec web camelmailer make-user you@yourdomain.com Ada Ops --admin # or script everything with a machine key docker compose exec web camelmailer make-admin-api-key ops
Sign in, create an organization → mail server → sending domain → API credential, then send. The API guide covers the calls; the dashboard does the same via clicks.
DNS you must set
| Record | Purpose |
|---|---|
A mail.yourdomain.com | The instance (API + dashboard, TLS via your reverse proxy) |
MX on inbound domains | Receiving replies/bounces → your instance |
TXT SPF | v=spf1 a:mail.yourdomain.com -all on sending domains |
TXT DKIM | Publish the DKIM public key (printed by make dkim / setup) |
TXT DMARC | v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com |
| PTR (reverse DNS) | Sending IP → SMTP hostname; set at your hosting provider |
Production checklist
- Terminate TLS for the API/dashboard at a reverse proxy (Caddy, nginx, Traefik) in front of port 5000.
- Enable SMTP STARTTLS:
smtp_server.tls_enabledwith your certificate. - Set
auth.frontend_urlandweb_server.cors_originsif you host the dashboard on its own origin. - Back up PostgreSQL (that's all the state) —
pg_dumpon a timer is fine to start. - Warm up fresh sending IPs gradually; keep transactional volume steady rather than bursty while reputation builds.
- Upgrades: pull,
docker compose up -d --build— migrations run automatically via the one-shot migrate service.
Configuration
Everything lives in one YAML file
(config/camelmailer.example.yml documents all
groups) or environment variables for the essentials
(DATABASE_URL). Accounts, RBAC, SSO and CORS
are covered in the repository's
docs/authentication.md.
Sizing
The binary is a few dozen MB of RSS per role; PostgreSQL dominates. A 2 vCPU / 4 GB box comfortably handles hundreds of thousands of transactional messages a day. Scale by giving PostgreSQL room first, then add worker replicas.