Self-Hosting
Run ApexMCP on your own infrastructure. Full Docker Compose stack — all services included.
Prerequisites
- Docker Engine 24+
- Docker Compose v2 (
docker composenotdocker-compose) openssl(for generating secrets)- 4 GB RAM minimum (8 GB recommended for production)
- Linux (amd64 or arm64) or macOS
Request Access
ApexMCP community images are hosted on GitHub Container Registry (GHCR) and require access approval.
To request access:
Email sales@apexmcp.ai with subject Self-Hosting Access Request and include:
- Your GitHub username
- Your intended use (personal / startup / enterprise)
We’ll grant read access to ghcr.io/andrcami/apexmcp-community/* within 1 business day and send you the .env.example template.
Quick Install
Once access is granted, authenticate with GHCR using your GitHub token:
echo YOUR_GITHUB_TOKEN | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdinThen download and start the stack:
curl -o docker-compose.yml https://apexmcp.ai/install/docker-compose.yml
curl -o .env.example https://apexmcp.ai/install/.env.example
cp .env.example .env
# Edit .env with your values (see Required Environment Variables below)
docker compose up -dDefault dashboard: http://localhost:3000
Community docker-compose.yml
version: "3.9"
services:
web:
image: ghcr.io/andrcami/apexmcp-community/web:latest
ports: ["3000:3000"]
env_file: .env
depends_on: [gateway, postgres, redis]
gateway:
image: ghcr.io/andrcami/apexmcp-community/gateway:latest
ports: ["4000:4000"]
env_file: .env
depends_on: [postgres, redis]
connector-service:
image: ghcr.io/andrcami/apexmcp-community/connector-service:latest
env_file: .env
depends_on: [postgres, redis, credential-vault]
mcp-manager:
image: ghcr.io/andrcami/apexmcp-community/mcp-manager:latest
env_file: .env
depends_on: [postgres, redis]
credential-vault:
image: ghcr.io/andrcami/apexmcp-community/credential-vault:latest
env_file: .env
depends_on: [postgres]
identity-broker:
image: ghcr.io/andrcami/apexmcp-community/identity-broker:latest
env_file: .env
depends_on: [postgres]
postgres:
image: postgres:15-alpine
environment:
POSTGRES_DB: apexmcp
POSTGRES_USER: apexmcp
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:Required Environment Variables
Copy .env.example and fill in:
cp .env.example .envCore
| Variable | Description |
|---|---|
NEXTAUTH_SECRET | Random 32-byte secret for session signing |
NEXTAUTH_URL | Public URL of the web dashboard (e.g. https://app.example.com) |
DATABASE_URL | PostgreSQL connection string for main app database |
Gateway
| Variable | Description |
|---|---|
GATEWAY_JWT_SECRET | Secret for signing internal JWTs |
GATEWAY_PORT | Gateway listen port (default 4000) |
Zitadel (Identity)
| Variable | Description |
|---|---|
ZITADEL_DOMAIN | FQDN for Zitadel (e.g. auth.example.com) |
ZITADEL_ADMIN_PASSWORD | Initial admin password |
ZITADEL_MASTERKEY | 32-character Zitadel master key |
Credential Vault
| Variable | Description |
|---|---|
VAULT_ENCRYPTION_KEY | AES-256 key for credential encryption (base64, 32 bytes) |
VAULT_DATABASE_URL | Separate PostgreSQL database for encrypted credentials |
Stripe (optional — disable billing for self-hosted)
| Variable | Description |
|---|---|
STRIPE_SECRET_KEY | Stripe secret key — omit or leave blank to disable billing |
STRIPE_WEBHOOK_SECRET | Stripe webhook signing secret |
License (Enterprise only)
| Variable | Description |
|---|---|
LICENSE_KEY | Enterprise license key from ApexMCP sales |
LICENSE_SERVER_URL | License validation endpoint (default: https://license.apexmcp.ai) |
Community edition runs without a license key but is limited to 3 connectors and 10,000 tool calls/month. Contact sales@apexmcp.ai for enterprise licensing.
Post-Install: Zitadel OAuth Setup
After starting the stack, configure the OAuth application in Zitadel:
- Open
http://localhost:8080(Zitadel admin) - Log in with credentials printed by
install.sh - Go to Projects → ApexMCP → Applications
- Note the Client ID and Client Secret
- Add to
.env:
ZITADEL_CLIENT_ID=<from step 4>
ZITADEL_CLIENT_SECRET=<from step 4>
ZITADEL_ISSUER=http://localhost:8080- Restart the web service:
docker compose restart webServices and Ports
| Service | Container | Default Port |
|---|---|---|
| Web Dashboard | web | 3000 |
| Docs | docs | 3001 |
| Gateway | gateway | 4000 |
| Connector Service | connector-service | 4001 |
| MCP Manager | mcp-manager | 4002 |
| Credential Vault | credential-vault | 4003 |
| Identity Broker | identity-broker | 4004 |
| License Server | license-server | 4005 |
| Zitadel | zitadel | 8080 |
| PostgreSQL | postgres | 5432 |
| Redis | redis | 6379 |
Upgrading
docker compose pull
docker compose up -dZero-downtime for stateless services. Database migrations run automatically on container start.
To check for available updates:
docker compose imagesBackup
Back up these volumes:
postgres_data— main application databasevault_postgres_data— encrypted credentialszitadel_data— identity and user data
docker compose exec postgres pg_dumpall -U postgres > backup-$(date +%Y%m%d).sqlGetting a License Key
The community edition is open-source and free for self-hosting with limits.
For enterprise features (unlimited connectors, SSO, audit export, SLA, priority support):
Contact sales@apexmcp.ai or see pricing for plan details.
Enterprise license keys are tied to your domain and validated against the ApexMCP license server at startup (with a 7-day grace cache for air-gapped environments).