|
|
--- |
|
|
title: 'Docker Setup' |
|
|
description: 'Deploy MCPHub using Docker and Docker Compose' |
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
This guide covers deploying MCPHub using Docker, including development and production configurations. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
|
docker pull mcphub/mcphub:latest |
|
|
|
|
|
|
|
|
docker run -d \ |
|
|
--name mcphub \ |
|
|
-p 3000:3000 \ |
|
|
-v $(pwd)/mcp_settings.json:/app/mcp_settings.json \ |
|
|
mcphub/mcphub:latest |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
|
git clone https://github.com/your-username/mcphub.git |
|
|
cd mcphub |
|
|
|
|
|
|
|
|
docker build -t mcphub:local . |
|
|
|
|
|
|
|
|
docker run -d \ |
|
|
--name mcphub \ |
|
|
-p 3000:3000 \ |
|
|
-v $(pwd)/mcp_settings.json:/app/mcp_settings.json \ |
|
|
mcphub:local |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Create a `docker-compose.yml` file: |
|
|
|
|
|
```yaml |
|
|
version: '3.8' |
|
|
|
|
|
services: |
|
|
mcphub: |
|
|
image: mcphub/mcphub:latest |
|
|
|
|
|
|
|
|
container_name: mcphub |
|
|
ports: |
|
|
- '3000:3000' |
|
|
environment: |
|
|
- NODE_ENV=production |
|
|
- PORT=3000 |
|
|
- JWT_SECRET=${JWT_SECRET:-your-jwt-secret} |
|
|
- DATABASE_URL=postgresql://mcphub:password@postgres:5432/mcphub |
|
|
volumes: |
|
|
- ./mcp_settings.json:/app/mcp_settings.json:ro |
|
|
- ./servers.json:/app/servers.json:ro |
|
|
- mcphub_data:/app/data |
|
|
depends_on: |
|
|
postgres: |
|
|
condition: service_healthy |
|
|
restart: unless-stopped |
|
|
networks: |
|
|
- mcphub-network |
|
|
|
|
|
postgres: |
|
|
image: postgres:15-alpine |
|
|
container_name: mcphub-postgres |
|
|
environment: |
|
|
- POSTGRES_DB=mcphub |
|
|
- POSTGRES_USER=mcphub |
|
|
- POSTGRES_PASSWORD=password |
|
|
volumes: |
|
|
- postgres_data:/var/lib/postgresql/data |
|
|
- ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro |
|
|
ports: |
|
|
- '5432:5432' |
|
|
healthcheck: |
|
|
test: ['CMD-SHELL', 'pg_isready -U mcphub -d mcphub'] |
|
|
interval: 10s |
|
|
timeout: 5s |
|
|
retries: 5 |
|
|
restart: unless-stopped |
|
|
networks: |
|
|
- mcphub-network |
|
|
|
|
|
volumes: |
|
|
postgres_data: |
|
|
mcphub_data: |
|
|
|
|
|
networks: |
|
|
mcphub-network: |
|
|
driver: bridge |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
```yaml |
|
|
version: '3.8' |
|
|
|
|
|
services: |
|
|
nginx: |
|
|
image: nginx:alpine |
|
|
container_name: mcphub-nginx |
|
|
ports: |
|
|
- '80:80' |
|
|
- '443:443' |
|
|
volumes: |
|
|
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro |
|
|
- ./ssl:/etc/nginx/ssl:ro |
|
|
- nginx_logs:/var/log/nginx |
|
|
depends_on: |
|
|
- mcphub |
|
|
restart: unless-stopped |
|
|
networks: |
|
|
- mcphub-network |
|
|
|
|
|
mcphub: |
|
|
image: mcphub/mcphub:latest |
|
|
container_name: mcphub-app |
|
|
expose: |
|
|
- '3000' |
|
|
environment: |
|
|
- NODE_ENV=production |
|
|
- PORT=3000 |
|
|
- JWT_SECRET=${JWT_SECRET} |
|
|
- JWT_EXPIRES_IN=${JWT_EXPIRES_IN:-24h} |
|
|
- DATABASE_URL=postgresql://mcphub:${POSTGRES_PASSWORD}@postgres:5432/mcphub |
|
|
- OPENAI_API_KEY=${OPENAI_API_KEY} |
|
|
- REDIS_URL=redis://redis:6379 |
|
|
volumes: |
|
|
- ./mcp_settings.json:/app/mcp_settings.json:ro |
|
|
- ./servers.json:/app/servers.json:ro |
|
|
- mcphub_data:/app/data |
|
|
- mcphub_logs:/app/logs |
|
|
depends_on: |
|
|
postgres: |
|
|
condition: service_healthy |
|
|
redis: |
|
|
condition: service_healthy |
|
|
restart: unless-stopped |
|
|
networks: |
|
|
- mcphub-network |
|
|
healthcheck: |
|
|
test: ['CMD', 'wget', '--quiet', '--tries=1', '--spider', 'http://localhost:3000/health'] |
|
|
interval: 30s |
|
|
timeout: 10s |
|
|
retries: 3 |
|
|
|
|
|
postgres: |
|
|
image: postgres:15-alpine |
|
|
container_name: mcphub-postgres |
|
|
environment: |
|
|
- POSTGRES_DB=mcphub |
|
|
- POSTGRES_USER=mcphub |
|
|
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD} |
|
|
volumes: |
|
|
- postgres_data:/var/lib/postgresql/data |
|
|
- ./backups:/backups |
|
|
healthcheck: |
|
|
test: ['CMD-SHELL', 'pg_isready -U mcphub -d mcphub'] |
|
|
interval: 10s |
|
|
timeout: 5s |
|
|
retries: 5 |
|
|
restart: unless-stopped |
|
|
networks: |
|
|
- mcphub-network |
|
|
|
|
|
redis: |
|
|
image: redis:7-alpine |
|
|
container_name: mcphub-redis |
|
|
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD} |
|
|
volumes: |
|
|
- redis_data:/data |
|
|
healthcheck: |
|
|
test: ['CMD', 'redis-cli', 'ping'] |
|
|
interval: 10s |
|
|
timeout: 5s |
|
|
retries: 5 |
|
|
restart: unless-stopped |
|
|
networks: |
|
|
- mcphub-network |
|
|
|
|
|
volumes: |
|
|
postgres_data: |
|
|
redis_data: |
|
|
mcphub_data: |
|
|
mcphub_logs: |
|
|
nginx_logs: |
|
|
|
|
|
networks: |
|
|
mcphub-network: |
|
|
driver: bridge |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
Create a `.env` file for Docker Compose: |
|
|
|
|
|
```env |
|
|
|
|
|
NODE_ENV=production |
|
|
JWT_SECRET=your-super-secret-jwt-key-change-this |
|
|
JWT_EXPIRES_IN=24h |
|
|
|
|
|
|
|
|
POSTGRES_PASSWORD=your-secure-database-password |
|
|
|
|
|
|
|
|
REDIS_PASSWORD=your-secure-redis-password |
|
|
|
|
|
|
|
|
OPENAI_API_KEY=your-openai-api-key |
|
|
|
|
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Create `docker-compose.dev.yml`: |
|
|
|
|
|
```yaml |
|
|
version: '3.8' |
|
|
|
|
|
services: |
|
|
mcphub-dev: |
|
|
build: |
|
|
context: . |
|
|
dockerfile: Dockerfile.dev |
|
|
container_name: mcphub-dev |
|
|
ports: |
|
|
- '3000:3000' |
|
|
- '5173:5173' |
|
|
- '9229:9229' |
|
|
environment: |
|
|
- NODE_ENV=development |
|
|
- PORT=3000 |
|
|
- DATABASE_URL=postgresql://mcphub:password@postgres:5432/mcphub |
|
|
volumes: |
|
|
- .:/app |
|
|
- /app/node_modules |
|
|
- /app/frontend/node_modules |
|
|
depends_on: |
|
|
- postgres |
|
|
command: pnpm dev |
|
|
networks: |
|
|
- mcphub-dev |
|
|
|
|
|
postgres: |
|
|
image: postgres:15-alpine |
|
|
container_name: mcphub-postgres-dev |
|
|
environment: |
|
|
- POSTGRES_DB=mcphub |
|
|
- POSTGRES_USER=mcphub |
|
|
- POSTGRES_PASSWORD=password |
|
|
ports: |
|
|
- '5432:5432' |
|
|
volumes: |
|
|
- postgres_dev_data:/var/lib/postgresql/data |
|
|
networks: |
|
|
- mcphub-dev |
|
|
|
|
|
volumes: |
|
|
postgres_dev_data: |
|
|
|
|
|
networks: |
|
|
mcphub-dev: |
|
|
driver: bridge |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
Create `Dockerfile.dev`: |
|
|
|
|
|
```dockerfile |
|
|
FROM node:20-alpine |
|
|
|
|
|
|
|
|
RUN npm install -g pnpm |
|
|
|
|
|
|
|
|
WORKDIR /app |
|
|
|
|
|
|
|
|
COPY package.json pnpm-lock.yaml ./ |
|
|
COPY frontend/package.json ./frontend/ |
|
|
|
|
|
|
|
|
RUN pnpm install |
|
|
|
|
|
|
|
|
COPY . . |
|
|
|
|
|
|
|
|
EXPOSE 3000 5173 9229 |
|
|
|
|
|
|
|
|
CMD ["pnpm", "dev"] |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
|
docker-compose -f docker-compose.dev.yml up -d |
|
|
|
|
|
|
|
|
docker-compose -f docker-compose.dev.yml logs -f mcphub-dev |
|
|
|
|
|
|
|
|
docker-compose -f docker-compose.dev.yml down |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
|
docker-compose up -d |
|
|
|
|
|
|
|
|
docker-compose logs -f mcphub |
|
|
|
|
|
|
|
|
docker-compose down |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Create your `mcp_settings.json`: |
|
|
|
|
|
```json |
|
|
{ |
|
|
"mcpServers": { |
|
|
"fetch": { |
|
|
"command": "uvx", |
|
|
"args": ["mcp-server-fetch"] |
|
|
}, |
|
|
"playwright": { |
|
|
"command": "npx", |
|
|
"args": ["@playwright/mcp@latest", "--headless"] |
|
|
}, |
|
|
"amap": { |
|
|
"command": "npx", |
|
|
"args": ["-y", "@amap/amap-maps-mcp-server"], |
|
|
"env": { |
|
|
"AMAP_MAPS_API_KEY": "your-api-key" |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
For production, use Docker secrets: |
|
|
|
|
|
```yaml |
|
|
version: '3.8' |
|
|
|
|
|
services: |
|
|
mcphub: |
|
|
image: mcphub/mcphub:latest |
|
|
environment: |
|
|
- JWT_SECRET_FILE=/run/secrets/jwt_secret |
|
|
- DATABASE_PASSWORD_FILE=/run/secrets/db_password |
|
|
secrets: |
|
|
- jwt_secret |
|
|
- db_password |
|
|
|
|
|
secrets: |
|
|
jwt_secret: |
|
|
file: ./secrets/jwt_secret.txt |
|
|
db_password: |
|
|
file: ./secrets/db_password.txt |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Add backup service to your `docker-compose.yml`: |
|
|
|
|
|
```yaml |
|
|
services: |
|
|
backup: |
|
|
image: postgres:15-alpine |
|
|
container_name: mcphub-backup |
|
|
environment: |
|
|
- PGPASSWORD=${POSTGRES_PASSWORD} |
|
|
volumes: |
|
|
- ./backups:/backups |
|
|
- ./scripts/backup.sh:/backup.sh:ro |
|
|
command: /bin/sh -c "chmod +x /backup.sh && /backup.sh" |
|
|
depends_on: |
|
|
- postgres |
|
|
profiles: |
|
|
- backup |
|
|
networks: |
|
|
- mcphub-network |
|
|
``` |
|
|
|
|
|
Create `scripts/backup.sh`: |
|
|
|
|
|
```bash |
|
|
|
|
|
BACKUP_FILE="/backups/mcphub_$(date +%Y%m%d_%H%M%S).sql" |
|
|
pg_dump -h postgres -U mcphub -d mcphub > "$BACKUP_FILE" |
|
|
echo "Backup created: $BACKUP_FILE" |
|
|
|
|
|
|
|
|
find /backups -name "mcphub_*.sql" -mtime +7 -delete |
|
|
``` |
|
|
|
|
|
Run backup: |
|
|
|
|
|
```bash |
|
|
docker-compose --profile backup run --rm backup |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Add to your application: |
|
|
|
|
|
```javascript |
|
|
// In your Express app |
|
|
app.get('/health', (req, res) => { |
|
|
res.json({ |
|
|
status: 'healthy', |
|
|
timestamp: new Date().toISOString(), |
|
|
uptime: process.uptime(), |
|
|
memory: process.memoryUsage(), |
|
|
version: process.env.npm_package_version, |
|
|
}); |
|
|
}); |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
```yaml |
|
|
services: |
|
|
mcphub: |
|
|
|
|
|
healthcheck: |
|
|
test: ['CMD', 'wget', '--quiet', '--tries=1', '--spider', 'http://localhost:3000/health'] |
|
|
interval: 30s |
|
|
timeout: 10s |
|
|
retries: 3 |
|
|
start_period: 60s |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
Add automatic updates: |
|
|
|
|
|
```yaml |
|
|
services: |
|
|
watchtower: |
|
|
image: containrrr/watchtower |
|
|
container_name: mcphub-watchtower |
|
|
volumes: |
|
|
- /var/run/docker.sock:/var/run/docker.sock |
|
|
environment: |
|
|
- WATCHTOWER_CLEANUP=true |
|
|
- WATCHTOWER_POLL_INTERVAL=3600 |
|
|
- WATCHTOWER_INCLUDE_STOPPED=true |
|
|
restart: unless-stopped |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Container fails to start**: Check logs with `docker-compose logs mcphub` |
|
|
|
|
|
**Database connection errors**: Ensure PostgreSQL is healthy and accessible |
|
|
|
|
|
**Port conflicts**: Check if ports 3000/5432 are already in use |
|
|
|
|
|
**Volume mount issues**: Verify file paths and permissions |
|
|
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
|
docker-compose ps |
|
|
|
|
|
|
|
|
docker-compose logs -f [service_name] |
|
|
|
|
|
|
|
|
docker-compose exec mcphub sh |
|
|
|
|
|
|
|
|
docker-compose exec postgres psql -U mcphub -d mcphub |
|
|
|
|
|
|
|
|
docker-compose restart mcphub |
|
|
|
|
|
|
|
|
docker-compose up --build -d |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
```yaml |
|
|
services: |
|
|
mcphub: |
|
|
|
|
|
deploy: |
|
|
resources: |
|
|
limits: |
|
|
memory: 512M |
|
|
cpus: '0.5' |
|
|
reservations: |
|
|
memory: 256M |
|
|
cpus: '0.25' |
|
|
``` |
|
|
|
|
|
This Docker setup provides a complete containerized environment for MCPHub with development and production configurations. |
|
|
|