Spaces:
Running
Download docs/deploy-all-services.md from Benaah/MicProtocol: direct link, hf CLI and curl.
- Browser
- Download file 17.9 kB
-
https://huggingface.co/spaces/Benaah/MicProtocol/resolve/main/docs/deploy-all-services.md
- Command line
-
hf download hf://spaces/Benaah/MicProtocol/docs/deploy-all-services.md
-
curl -L -o deploy-all-services.md https://huggingface.co/spaces/Benaah/MicProtocol/resolve/main/docs/deploy-all-services.md
MicProtocol β Full Deployment Guide (All Services)
This guide covers deploying the complete MicProtocol stack β core platform, real-time engine, and all self-hosted integrations β on a single server using Docker Compose.
Prerequisites
| Requirement | Minimum | Recommended |
|---|---|---|
| OS | Ubuntu 22.04 / Debian 12 | Ubuntu 24.04 LTS |
| CPU | 8 cores | 16+ cores |
| RAM | 16 GB | 32+ GB |
| Disk | 80 GB SSD | 200+ GB NVMe |
| Docker | 24.0+ | 27+ |
| Docker Compose | v2.20+ | v2.29+ |
| Domain | 1 root domain | Wildcard DNS (*.yourdomain.com) |
Architecture Overview
Caddy (TLS + Reverse Proxy)
ββββββββββββββββββββββββββββββββ
β *.yourdomain.com β :3000 β
β api.* β :4000 β
β realtime.* β :4001 (WS) β
β admin.* β :3006 β
ββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββΌββββββββββββββββββββββ
β β β
ββββββΌβββββ βββββββΌββββββ ββββββββΌβββββββ
β Web β β API β β Admin β
β :3000 ββββββΆβ :4000 ββββββββββ :3006 β
βββββββββββ βββββββ¬ββββββ βββββββββββββββ
β
ββββββββββββββββΌβββββββββββββββββββ
β β β
ββββββΌβββββ ββββββΌβββββ βββββββΌββββββ
β Postgres β β Redis β β Meilisearchβ
β :5432 β β :6379 β β :7700 β
ββββββββββββ βββββββββββ ββββββββββββββ
β
βββββββββββΌβββββββββββββββββββββββββββββββββββ
β β β β β β
βββββΌββββ ββββΌβββ ββββββΌββββ ββββΌβββ ββββΌβββ ββββΌβββ
βCal.comβ βChat-β βForm- β βDocu-β βList-β βUmamiβ
β :3002 β βwoot β βbricks β βmensoβ βmonk β β:3003β
βββββββββ β:3005β β :3001 β β:3004β β:9000β βββββββ
βββββββ ββββββββββ βββββββ βββββββ
Step 1: Generate Secrets
Run the secrets generator to produce strong random values for every service:
cd /path/to/MicProtocol
bash scripts/generate-secrets.sh > .env.secrets
Review the output, then merge it into your .env file. Never commit .env to git.
Step 2: Configure Environment
Copy the example and fill in your values:
cp .env.example .env
Required Variables
At minimum, set these before the first boot:
| Variable | Where to get it |
|---|---|
POSTGRES_PASSWORD |
Generated by generate-secrets.sh |
REDIS_PASSWORD |
Generated by generate-secrets.sh |
COOKIE_SECRET |
Generated by generate-secrets.sh |
CLERK_SECRET_KEY |
Clerk Dashboard β API Keys |
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY |
Clerk Dashboard β API Keys |
WEB_URL |
Your public web app URL (e.g. https://yourdomain.com) |
API_URL |
Your public API URL (e.g. https://api.yourdomain.com) |
RESEND_API_KEY |
Resend Dashboard (or your SMTP relay) |
R2_ACCESS_KEY_ID |
Cloudflare R2 dashboard |
R2_SECRET_ACCESS_KEY |
Cloudflare R2 dashboard |
R2_ENDPOINT |
Cloudflare R2 endpoint |
R2_BUCKET |
R2 bucket name |
Self-Hosted Integration Variables
Each integration needs its own secrets (all generated by generate-secrets.sh):
| Integration | Key Variables |
|---|---|
| Cal.com | CALCOM_NEXTAUTH_SECRET, CALCOM_ENCRYPTION_KEY, CALCOM_WEBHOOK_SECRET, CALCOM_API_KEY |
| Chatwoot | CHATWOOT_SECRET_KEY_BASE, CHATWOOT_WEBHOOK_SECRET, CHATWOOT_API_KEY |
| Formbricks | FORMBRICKS_NEXTAUTH_SECRET, FORMBRICKS_ENCRYPTION_KEY, FORMBRICKS_CRON_SECRET, FORMBRICKS_HUB_API_KEY, FORMBRICKS_CUBE_API_SECRET, FORMBRICKS_WEBHOOK_SECRET |
| Documenso | DOCUMENSO_NEXTAUTH_SECRET, DOCUMENSO_ENCRYPTION_KEY, DOCUMENSO_ENCRYPTION_SECONDARY_KEY, DOCUMENSO_SIGNING_PASSPHRASE |
| Listmonk | LISTMONK_ADMIN_PASSWORD, LISTMONK_API_TOKEN, LISTMONK_WEBHOOK_SECRET |
| Umami | UMAMI_APP_SECRET |
| LiveKit | LIVEKIT_API_KEY, LIVEKIT_API_SECRET |
| mic-realtime | MIC_REALTIME_INTERNAL_TOKEN, MIC_REALTIME_SHARED_SECRET, MIC_REALTIME_PUBLIC_URL |
Production URLs
Replace all http://localhost:* URLs with your actual domain:
# Public-facing
WEB_URL=https://yourdomain.com
API_URL=https://api.yourdomain.com
NEXT_PUBLIC_API_URL=https://api.yourdomain.com
# Self-hosted integration public URLs
CALCOM_URL=https://cal.yourdomain.com
CHATWOOT_URL=https://support.yourdomain.com
DOCUMENSO_URL=https://sign.yourdomain.com
FORMBRICKS_URL=https://surveys.yourdomain.com
LISTMONK_URL=https://mail.yourdomain.com
NEXT_PUBLIC_UMAMI_URL=https://analytics.yourdomain.com
# Real-time (MUST be wss:// in production)
MIC_REALTIME_PUBLIC_URL=wss://realtime.yourdomain.com
NEXT_PUBLIC_MIC_REALTIME_URL=wss://realtime.yourdomain.com
Step 3: Configure DNS
For wildcard TLS to work, you need a DNS-01 challenge. Add these DNS records:
| Record | Type | Value |
|---|---|---|
@ |
A | Your server IP |
* |
A | Your server IP |
Or use CNAME records if your DNS provider supports wildcard CNAMEs.
Step 4: Generate Documenso Signing Certificate
Documenso requires a PKCS#12 signing certificate:
mkdir -p scripts/documenso-cert
# Generate self-signed cert (replace with your details)
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 3650 -nodes \
-subj "/CN=Documenso Signing/O=MicProtocol"
# Convert to PKCS#12
openssl pkcs12 -export -out cert.p12 -inkey key.pem -in cert.pem \
-passout pass:${DOCUMENSO_SIGNING_PASSPHRASE}
# Move to the expected location
mv cert.p12 scripts/documenso-cert/
rm -f key.pem cert.pem
Step 5: Start Core Infrastructure
Start the shared infrastructure first β these must be healthy before anything else:
# Start Postgres, Redis, Meilisearch, MinIO
docker compose up -d postgres redis meilisearch minio minio-createbuckets
# Wait for health checks to pass
docker compose ps # All should show "healthy"
Verify Postgres is ready:
docker exec -it micprotocol-postgres pg_isready -U micprotocol
The init-databases.sql script runs automatically on first boot, creating databases for: chatwoot, calcom, documenso, formbricks, listmonk, umami.
Step 6: Start the API and Worker
docker compose up -d api worker
The API will:
- Run Prisma migrations against the
micprotocoldatabase - Start the NestJS server on
:4000 - Expose tRPC, REST, and webhook endpoints
Verify:
curl -s http://localhost:4000/health
Step 7: Start the Real-Time Engine
docker compose up -d mic-realtime
Verify:
curl -s http://localhost:4001/healthz
Important: MIC_REALTIME_INTERNAL_TOKEN and MIC_REALTIME_SHARED_SECRET must be strong random strings. The service fails closed at startup if they are missing or set to defaults.
Step 8: Start Web and Admin
docker compose up -d web admin
Verify:
curl -s -o /dev/null -w "%{http_code}" http://localhost:3000 # Web
curl -s -o /dev/null -w "%{http_code}" http://localhost:3006 # Admin
Step 9: Start Self-Hosted Integrations
Start all integrations (or selectively enable ones you need):
# Start everything at once
docker compose up -d
# OR start individual services:
docker compose up -d calcom # Scheduling
docker compose up -d chatwoot-web chatwoot-worker # Live chat
docker compose up -d formbricks-migrate formbricks-hub-migrate formbricks formbricks-hub formbricks-cube # Surveys
docker compose up -d documenso # E-signatures
docker compose up -d listmonk # Email marketing
docker compose up -d umami # Analytics
docker compose up -d livekit # WebRTC recording
Integration Startup Order
Some services have dependencies that Docker Compose handles automatically:
Postgres (healthy)
βββ formbricks-migrate (runs once)
β βββ formbricks-hub-migrate (runs once)
β βββ formbricks-cube (healthy)
β βββ formbricks-hub (healthy)
β βββ formbricks (healthy)
βββ calcom (depends on Postgres + Redis)
βββ chatwoot-web + chatwoot-worker (depends on Postgres + Redis)
βββ documenso (depends on Postgres)
βββ listmonk (depends on Postgres)
βββ umami (depends on Postgres)
Step 10: Start Dev SMTP (Optional)
For local development, Mailhog captures all outbound email:
docker compose up -d mailhog
- SMTP server:
localhost:1025 - Web UI:
http://localhost:8025
In production, replace with your transactional SMTP relay (Resend, SES, Postmark, etc.) by setting SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASSWORD.
Step 11: Start CLIP Scorer (Optional)
The CLIP scoring engine is CPU/GPU intensive. Start it only if you need AI-powered clip scoring:
docker compose up -d clip-scorer
Resource requirements:
- CPU: 2 cores minimum
- Memory: 2 GB minimum
- Optional GPU: Cuts inference time by 5-10x
Step 12: Configure Caddy (TLS + Reverse Proxy)
The Caddyfile handles TLS termination and routing. Set the ROOT_DOMAIN and CLOUDFLARE_API_TOKEN environment variables:
export ROOT_DOMAIN=yourdomain.com
export CLOUDFLARE_API_TOKEN=your_cloudflare_api_token
Start Caddy:
docker compose up -d caddy
Or install Caddy on the host and run it with the provided Caddyfile:
# Install Caddy
sudo apt install -y caddy
# Copy the Caddyfile
sudo cp Caddyfile /etc/caddy/Caddyfile
# Set environment
export ROOT_DOMAIN=yourdomain.com
export CLOUDFLARE_API_TOKEN=your_token
# Start
sudo systemctl restart caddy
Caddy Routing Table
| Host | Upstream | Protocol |
|---|---|---|
yourdomain.com / *.yourdomain.com |
web:3000 | HTTPS |
api.yourdomain.com |
api:4000 | HTTPS |
realtime.yourdomain.com |
mic-realtime:4001 | WSS |
admin.yourdomain.com |
admin:3006 | HTTPS |
Step 13: Run Database Migrations
If this is a fresh deployment, run Prisma migrations:
docker exec -it micprotocol-api npx prisma migrate deploy
Or generate the Prisma client and push the schema:
docker exec -it micprotocol-api npx prisma generate
docker exec -it micprotocol-api npx prisma db push
Step 14: Post-Deployment Setup
Cal.com
- Open
https://cal.yourdomain.com - Create admin account
- Go to Settings β API Keys β generate a key
- Set
CALCOM_API_KEYin.env - Restart the API:
docker compose restart api
Chatwoot
- Open
https://support.yourdomain.com - Complete the setup wizard
- Go to Settings β Agents β create an agent
- Go to Settings β Inboxes β create a website inbox
- Copy the inbox ID to
CHATWOOT_INBOX_ID - Copy the website token to
NEXT_PUBLIC_CHATWOOT_WEBSITE_TOKEN - Restart the API
Formbricks
- Open
https://surveys.yourdomain.com - Create admin account
- Go to Settings β Environments β copy the environment ID
- Set
NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID - Go to Settings β API Keys β create a key
- Set
FORMBRICKS_API_KEY - Restart the API
Documenso
- Open
https://sign.yourdomain.com - Create admin account
- Go to Settings β API β create a key
- Set
DOCUMENSO_API_KEY - Restart the API
Listmonk
- Open
https://mail.yourdomain.com - Log in with
LISTMONK_ADMIN_USER/LISTMONK_ADMIN_PASSWORD - Go to Settings β API β generate a token
- Set
LISTMONK_API_TOKEN - Create a mailing list and copy its UUID to
NEXT_PUBLIC_LISTMONK_LIST_UUID - Configure webhooks: POST to
http://api:4000/integrations/webhooks/listmonkwith headerx-listmonk-secret: <LISTMONK_WEBHOOK_SECRET> - Restart the API
Umami
- Open
https://analytics.yourdomain.com - Log in with default credentials (admin/umami)
- Change the admin password
- Add a website and copy the website ID to
NEXT_PUBLIC_UMAMI_WEBSITE_ID - Restart the web app
LiveKit
- The recording studio connects to LiveKit on port 7880
- For internet-facing deployments, ensure UDP port 7882 is open
- If behind a firewall, configure a TURN server or set
rtc.use_external_ip: true
Health Checks
Verify all services are running:
# Core
curl -s http://localhost:4000/health # API
curl -s http://localhost:4001/healthz # mic-realtime
curl -s http://localhost:3000 # Web
curl -s http://localhost:3006 # Admin
# Integrations
curl -s http://localhost:3002/api/health # Cal.com
curl -s http://localhost:3005/health # Chatwoot
curl -s http://localhost:3001/api/health # Formbricks
curl -s http://localhost:3004/api/health # Documenso
curl -s http://localhost:9000/health # Listmonk
curl -s http://localhost:3003/api/health # Umami
curl -s http://localhost:7880/health # LiveKit
# Consolidated check
curl -s http://localhost:4000/integrations/health | jq
Port Reference
| Port | Service | Protocol |
|---|---|---|
| 3000 | Web (Next.js) | HTTP |
| 3001 | Formbricks | HTTP |
| 3002 | Cal.com | HTTP |
| 3003 | Umami | HTTP |
| 3004 | Documenso | HTTP |
| 3005 | Chatwoot | HTTP |
| 3006 | Admin | HTTP |
| 4000 | API (NestJS) | HTTP |
| 4001 | mic-realtime | HTTP/WS |
| 5432 | PostgreSQL | TCP |
| 6379 | Redis | TCP |
| 7700 | Meilisearch | HTTP |
| 7880 | LiveKit | HTTP |
| 7881 | LiveKit | TCP |
| 7882 | LiveKit | UDP |
| 8025 | Mailhog UI | HTTP |
| 9000 | Listmonk | HTTP |
| 9001 | MinIO API | HTTP |
| 9090 | MinIO Console | HTTP |
| 1025 | Mailhog SMTP | TCP |
Resource Limits
Default limits from docker-compose.yml:
| Service | CPUs | Memory |
|---|---|---|
| API | 2 | 2 GB |
| Worker | 1 | 1 GB |
| CLIP Scorer | 2 | 2 GB |
| mic-realtime | 1.5 | 1 GB |
Other services have no explicit limits. Tune based on your hardware.
Common Operations
Stop everything
docker compose down # Keep data
docker compose down -v # Wipe all data (destructive)
Update a single service
docker compose pull <service>
docker compose up -d --no-deps <service>
Update Formbricks (requires migration re-run)
docker compose up formbricks-migrate
docker compose up formbricks-hub-migrate
docker compose up -d --no-deps formbricks formbricks-hub formbricks-cube
View logs
docker compose logs -f api # API logs
docker compose logs -f mic-realtime # Real-time logs
docker compose logs -f chatwoot-web # Chatwoot logs
Restart a service
docker compose restart api
Enter a container
docker exec -it micprotocol-api sh
docker exec -it micprotocol-postgres psql -U micprotocol
Troubleshooting
Service won't start
- Check logs:
docker compose logs <service> - Verify env vars are set in
.env - Check that dependent services are healthy:
docker compose ps
Database connection refused
- Ensure Postgres is healthy:
docker exec micprotocol-postgres pg_isready - Verify
DATABASE_URLuses the container hostname (postgres), notlocalhost
Real-time WebSocket not connecting
- Ensure
MIC_REALTIME_PUBLIC_URLis awss://URL in production - Check that
MIC_REALTIME_INTERNAL_TOKENandMIC_REALTIME_SHARED_SECRETare set - Verify Caddy is routing
realtime.*correctly
Formbricks won't start
- Ensure all 5 Formbricks containers start in order
- Check that
SKIP_STARTUP_MIGRATION=trueis set on the web container - Verify Cube.js is healthy before Formbricks web starts
Outbound email not working
- Check
SMTP_HOST,SMTP_PORT,SMTP_USER,SMTP_PASSWORDin.env - In dev, ensure Mailhog is running:
docker compose up -d mailhog - Check Mailhog UI at
http://localhost:8025
Disabling Services
Any integration can be removed by deleting its block from docker-compose.yml and omitting its env vars from .env. The API degrades gracefully β missing integrations return false from health checks and log warnings rather than crashing.
Security Checklist
- All default passwords changed
-
.envnot committed to git - Firewall configured (only ports 80, 443, and SSH open)
- TLS working via Caddy
-
MIC_REALTIME_INTERNAL_TOKENandMIC_REALTIME_SHARED_SECRETare strong random values - Encryption keys (
*_ENCRYPTION_KEY) generated and backed up (never rotate after first use) - Webhook secrets configured on both sides
- SMTP relay configured (not Mailhog) in production
-
DEV_AUTH_BYPASS_ENABLED=falsein production