docker-compose.ymlโข7.08 kB
version: '3.8'
services:
pfsense-mcp:
build:
context: .
dockerfile: Dockerfile
args:
BUILD_DATE: ${BUILD_DATE:-$(date -u +'%Y-%m-%dT%H:%M:%SZ')}
VCS_REF: ${VCS_REF:-$(git rev-parse --short HEAD)}
VERSION: ${VERSION:-2.0.0}
image: pfsense-mcp:${VERSION:-2.0.0}
container_name: pfsense-mcp-server
restart: unless-stopped
user: "1000:1000"
environment:
# MCP Configuration
MCP_MODE: ${MCP_MODE:-http}
MCP_HOST: 0.0.0.0
MCP_PORT: 8000
MCP_WORKERS: ${MCP_WORKERS:-4}
# pfSense Connection
PFSENSE_URL: ${PFSENSE_URL}
PFSENSE_VERSION: ${PFSENSE_VERSION:-ce}
PFSENSE_CONNECTION_METHOD: ${PFSENSE_CONNECTION_METHOD:-rest}
VERIFY_SSL: ${VERIFY_SSL:-true}
CONNECTION_TIMEOUT: ${CONNECTION_TIMEOUT:-30}
# Authentication (REST)
PFSENSE_API_KEY: ${PFSENSE_API_KEY}
PFSENSE_API_SECRET: ${PFSENSE_API_SECRET}
# Authentication (XML-RPC)
PFSENSE_USERNAME: ${PFSENSE_USERNAME}
PFSENSE_PASSWORD: ${PFSENSE_PASSWORD}
# Authentication (SSH)
PFSENSE_SSH_HOST: ${PFSENSE_SSH_HOST}
PFSENSE_SSH_PORT: ${PFSENSE_SSH_PORT:-22}
PFSENSE_SSH_USERNAME: ${PFSENSE_SSH_USERNAME}
PFSENSE_SSH_KEY_PATH: /config/ssh/id_rsa
# Security
MCP_ACCESS_LEVEL: ${MCP_ACCESS_LEVEL:-READ_ONLY}
MCP_USER_ID: ${MCP_USER_ID:-default_user}
IP_WHITELIST: ${IP_WHITELIST:-}
# Caching
CACHE_TTL: ${CACHE_TTL:-300}
REDIS_URL: redis://:${REDIS_PASSWORD:-changeme}@redis:6379/0
# Circuit Breaker
CIRCUIT_BREAKER_THRESHOLD: ${CIRCUIT_BREAKER_THRESHOLD:-5}
CIRCUIT_BREAKER_TIMEOUT: ${CIRCUIT_BREAKER_TIMEOUT:-60}
# Logging
LOG_LEVEL: ${LOG_LEVEL:-INFO}
# Monitoring
OTEL_ENABLED: ${OTEL_ENABLED:-false}
OTEL_ENDPOINT: ${OTEL_ENDPOINT:-otel-collector:4317}
OTEL_SERVICE_NAME: pfsense-mcp-server
# Production mode
PRODUCTION: ${PRODUCTION:-true}
env_file:
- .env
ports:
- "${MCP_EXTERNAL_PORT:-8000}:8000"
- "${METRICS_PORT:-9090}:9090"
volumes:
- ./data:/data:rw
- ./logs:/logs:rw
- ./config:/config:ro
- ${SSH_KEY_PATH:-./config/ssh}:/config/ssh:ro
healthcheck:
test: ["CMD", "/usr/local/bin/healthcheck"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
depends_on:
redis:
condition: service_healthy
postgres:
condition: service_healthy
networks:
- mcp-network
deploy:
resources:
limits:
cpus: '2'
memory: 1G
reservations:
cpus: '0.5'
memory: 256M
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
- /var/run
- /var/cache
# Redis for distributed caching
redis:
image: redis:7-alpine
container_name: pfsense-mcp-redis
restart: unless-stopped
command: >
redis-server
--requirepass ${REDIS_PASSWORD:-changeme}
--maxmemory 256mb
--maxmemory-policy allkeys-lru
--save 60 1
--appendonly yes
ports:
- "${REDIS_PORT:-6379}:6379"
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "--pass", "${REDIS_PASSWORD:-changeme}", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- mcp-network
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
# PostgreSQL for audit logs (optional)
postgres:
image: postgres:16-alpine
container_name: pfsense-mcp-postgres
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:-mcp}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-changeme}
POSTGRES_DB: ${POSTGRES_DB:-mcp_audit}
PGDATA: /var/lib/postgresql/data/pgdata
ports:
- "${POSTGRES_PORT:-5432}:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
- ./config/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-mcp}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- mcp-network
deploy:
resources:
limits:
cpus: '1'
memory: 1G
# Prometheus for metrics collection
prometheus:
image: prom/prometheus:latest
container_name: pfsense-mcp-prometheus
restart: unless-stopped
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
- '--web.console.templates=/usr/share/prometheus/consoles'
- '--storage.tsdb.retention.time=30d'
ports:
- "${PROMETHEUS_PORT:-9091}:9090"
volumes:
- ./config/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
networks:
- mcp-network
depends_on:
- pfsense-mcp
# Grafana for visualization (optional)
grafana:
image: grafana/grafana:latest
container_name: pfsense-mcp-grafana
restart: unless-stopped
environment:
GF_SECURITY_ADMIN_USER: ${GF_ADMIN_USER:-admin}
GF_SECURITY_ADMIN_PASSWORD: ${GF_ADMIN_PASSWORD:-changeme}
GF_INSTALL_PLUGINS: ${GF_PLUGINS:-}
ports:
- "${GRAFANA_PORT:-3000}:3000"
volumes:
- grafana-data:/var/lib/grafana
- ./config/grafana/provisioning:/etc/grafana/provisioning:ro
networks:
- mcp-network
depends_on:
- prometheus
# OpenTelemetry Collector (optional)
otel-collector:
image: otel/opentelemetry-collector-contrib:latest
container_name: pfsense-mcp-otel
restart: unless-stopped
command: ["--config=/etc/otel-collector-config.yaml"]
ports:
- "${OTEL_GRPC_PORT:-4317}:4317" # gRPC
- "${OTEL_HTTP_PORT:-4318}:4318" # HTTP
- "${OTEL_METRICS_PORT:-8888}:8888" # Prometheus metrics
volumes:
- ./config/otel/otel-collector-config.yaml:/etc/otel-collector-config.yaml:ro
networks:
- mcp-network
depends_on:
- prometheus
# Nginx reverse proxy (optional, for production)
nginx:
image: nginx:alpine
container_name: pfsense-mcp-nginx
restart: unless-stopped
ports:
- "${NGINX_HTTP_PORT:-80}:80"
- "${NGINX_HTTPS_PORT:-443}:443"
volumes:
- ./config/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./config/nginx/conf.d:/etc/nginx/conf.d:ro
- ./config/ssl:/etc/nginx/ssl:ro
- nginx-cache:/var/cache/nginx
networks:
- mcp-network
depends_on:
- pfsense-mcp
networks:
mcp-network:
driver: bridge
ipam:
config:
- subnet: 172.25.0.0/16
volumes:
redis-data:
driver: local
postgres-data:
driver: local
prometheus-data:
driver: local
grafana-data:
driver: local
nginx-cache:
driver: local