Deployment
Koltrix is designed to run on a single VPS (or scale out later). The recommended target is a 4 vCPU / 8 GB Linux box with at least 80 GB disk.
One-liner installer
From a fresh checkout:
git clone https://github.com/koltrix/koltrix.git && cd koltrix
./scripts/install.shThe installer:
- Verifies Docker and Docker Compose v2 are installed.
- Copies
.env.exampleto.envand fills random secrets. - Builds every container.
- Starts the stack and waits for
/health. - Prints next steps.
Production checklist
- Point
app.koltrix.com,api.koltrix.com, anddocs.koltrix.comat the server IP. The wildcard A record makes any tenant subdomain work too. - Issue a TLS cert: certbot with the Cloudflare DNS-01 plugin works well for wildcards through Cloudflare proxy.
sudo apt install python3-certbot-dns-cloudflare
echo "dns_cloudflare_api_token = $CF_TOKEN" | sudo tee /root/.secrets/cloudflare.ini
sudo chmod 600 /root/.secrets/cloudflare.ini
sudo certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
--cert-name koltrix.com \
-d "koltrix.com" -d "*.koltrix.com"- Edit
/etc/nginx/sites-available/koltrixto use the wildcard cert and reload nginx. - Add a PTR record at your hosting provider so reverse-DNS resolves
<your-ip>→mail.koltrix.com. - Set production Clerk + Stripe + AI keys in
.env. Restart:
docker compose restartDNS records
| Type | Name | Content | Proxied |
|---|---|---|---|
| A | app | <server IP> | ✓ |
| A | * (wildcard) | <server IP> | ✓ |
| A | mail | <server IP> | ✗ (DNS only) |
| MX | apex | mail.koltrix.com priority 10 | ✗ |
| TXT | apex (SPF) | v=spf1 ip4:<server IP> ~all | ✗ |
| TXT | koltrix._domainkey (DKIM) | public key from Rspamd | ✗ |
| TXT | _dmarc | v=DMARC1; p=quarantine; ... | ✗ |
Backups
- Postgres:
pg_dumpnightly to S3/MinIO. We bundle a sample cron job inscripts/backup-db.sh. - MinIO:
mc mirrorto off-site.
Scaling out
When you outgrow one server:
- Web + API + worker: trivially horizontal — multiple containers behind the nginx upstream. Sessions are JWT; Redis handles queue state.
- Postfix: stays on a single IP per dedicated tenant for deliverability.
- Postgres: move to managed (RDS / Neon / Supabase) when ready.
- Asynq worker: split by queue (we already have
critical,default,low) and scale specialized workers independently.
See Architecture for the service map.