Docker Deployment¶
Deploy MarchProxy using Docker and Docker Compose for development, testing, and production environments.
Quick Start¶
Prerequisites¶
- Docker 20.10+
- Docker Compose 2.0+
- 4GB RAM minimum
- 20GB storage
Basic Deployment¶
-
Clone and configure:
-
Start services:
-
Verify deployment:
Production Deployment¶
Environment Configuration¶
Create a production environment file:
# .env.production
MARCHPROXY_ENV=production
DEBUG=false
LOG_LEVEL=info
# Strong passwords (generate secure values)
POSTGRES_PASSWORD=$(openssl rand -base64 32)
REDIS_PASSWORD=$(openssl rand -base64 32)
SECRET_KEY=$(openssl rand -base64 64)
GRAFANA_PASSWORD=$(openssl rand -base64 16)
# Database
DATABASE_URL=postgresql://marchproxy:${POSTGRES_PASSWORD}@postgres:5432/marchproxy
# Enterprise features
LICENSE_KEY=PENG-XXXX-XXXX-XXXX-XXXX-ABCD
CLUSTER_API_KEY=$(openssl rand -base64 32)
# Performance
ENABLE_XDP=true
WORKER_THREADS=4
Production Docker Compose¶
# docker-compose.prod.yml
version: '3.8'
services:
manager:
image: penguintech/marchproxy-manager:latest
restart: always
environment:
- MARCHPROXY_ENV=production
- DEBUG=false
volumes:
- manager_data:/app/data
- ./certs:/app/certs:ro
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '1.0'
memory: 1G
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/healthz"]
interval: 30s
timeout: 10s
retries: 3
proxy:
image: penguintech/marchproxy-proxy:latest
restart: always
privileged: true # Required for eBPF/XDP
network_mode: host # Required for packet capture
environment:
- ENABLE_XDP=true
- WORKER_THREADS=4
volumes:
- ./certs:/app/certs:ro
deploy:
resources:
limits:
cpus: '4.0'
memory: 4G
reservations:
cpus: '2.0'
memory: 2G
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/healthz"]
interval: 30s
timeout: 10s
retries: 3
postgres:
image: postgres:15-alpine
restart: always
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_USER: marchproxy
POSTGRES_DB: marchproxy
volumes:
- postgres_data:/var/lib/postgresql/data
- ./scripts/postgres-init.sql:/docker-entrypoint-initdb.d/init.sql
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
redis:
image: redis:7-alpine
restart: always
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
volumes:
manager_data:
postgres_data:
redis_data:
SSL Certificate Setup¶
# Create certificates directory
mkdir -p certs
# Option 1: Use Let's Encrypt
certbot certonly --standalone \
-d proxy.company.com \
--cert-path ./certs/server.crt \
--key-path ./certs/server.key
# Option 2: Use existing certificates
cp /path/to/your/certificate.crt certs/server.crt
cp /path/to/your/private.key certs/server.key
# Option 3: Generate self-signed (development only)
openssl req -x509 -newkey rsa:4096 \
-keyout certs/server.key \
-out certs/server.crt \
-days 365 -nodes \
-subj "/CN=proxy.company.com"
# Set proper permissions
chmod 600 certs/server.key
chmod 644 certs/server.crt
chown root:root certs/*
High Availability Setup¶
For HA deployment with multiple proxy instances:
# docker-compose.ha.yml
version: '3.8'
services:
manager:
deploy:
replicas: 2
placement:
constraints:
- node.role == manager
proxy:
deploy:
replicas: 3
placement:
max_replicas_per_node: 1
postgres:
deploy:
replicas: 1
placement:
constraints:
- node.labels.postgres == true
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
- manager
- proxy
Load Balancer Configuration¶
# nginx.conf for load balancing
upstream manager_backend {
least_conn;
server manager_1:8000;
server manager_2:8000;
}
upstream proxy_backend {
least_conn;
server proxy_1:8080;
server proxy_2:8080;
server proxy_3:8080;
}
server {
listen 80;
listen 443 ssl;
server_name proxy.company.com;
ssl_certificate /etc/nginx/certs/server.crt;
ssl_certificate_key /etc/nginx/certs/server.key;
location / {
proxy_pass http://manager_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /proxy/ {
proxy_pass http://proxy_backend/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Monitoring Setup¶
Integrated Monitoring Stack¶
# docker-compose.monitoring.yml
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
restart: always
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention.time=30d'
grafana:
image: grafana/grafana:latest
restart: always
ports:
- "3000:3000"
environment:
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD}
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/dashboards:/etc/grafana/provisioning/dashboards:ro
- ./grafana/datasources:/etc/grafana/provisioning/datasources:ro
loki:
image: grafana/loki:latest
restart: always
ports:
- "3100:3100"
volumes:
- loki_data:/loki
- ./loki.yml:/etc/loki/local-config.yaml:ro
promtail:
image: grafana/promtail:latest
restart: always
volumes:
- /var/log:/var/log:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- ./promtail.yml:/etc/promtail/config.yml:ro
volumes:
prometheus_data:
grafana_data:
loki_data:
Prometheus Configuration¶
# prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'marchproxy-manager'
static_configs:
- targets: ['manager:8000']
metrics_path: '/metrics'
- job_name: 'marchproxy-proxy'
static_configs:
- targets: ['proxy:8081']
metrics_path: '/metrics'
- job_name: 'postgres'
static_configs:
- targets: ['postgres_exporter:9187']
- job_name: 'redis'
static_configs:
- targets: ['redis_exporter:9121']
Security Hardening¶
Container Security¶
# Security-hardened service configuration
services:
manager:
security_opt:
- no-new-privileges:true
user: "1000:1000"
read_only: true
tmpfs:
- /tmp
- /var/cache
volumes:
- manager_data:/app/data
- ./certs:/app/certs:ro
proxy:
security_opt:
- no-new-privileges:true
cap_add:
- NET_ADMIN # Required for eBPF/XDP
- SYS_ADMIN # Required for eBPF loading
cap_drop:
- ALL
Network Security¶
# Network isolation
networks:
frontend:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/24
backend:
driver: bridge
internal: true
ipam:
config:
- subnet: 172.21.0.0/24
services:
manager:
networks:
- frontend
- backend
proxy:
networks:
- frontend
postgres:
networks:
- backend
redis:
networks:
- backend
Backup and Recovery¶
Database Backup¶
#!/bin/bash
# backup.sh - Database backup script
BACKUP_DIR="/backup/marchproxy"
DATE=$(date +%Y%m%d_%H%M%S)
CONTAINER_NAME="marchproxy_postgres_1"
mkdir -p ${BACKUP_DIR}
# Create database backup
docker exec ${CONTAINER_NAME} pg_dump -U marchproxy marchproxy | \
gzip > ${BACKUP_DIR}/marchproxy_${DATE}.sql.gz
# Backup environment and compose files
cp .env ${BACKUP_DIR}/env_${DATE}
cp docker-compose.yml ${BACKUP_DIR}/compose_${DATE}.yml
# Clean old backups (keep 30 days)
find ${BACKUP_DIR} -name "*.sql.gz" -mtime +30 -delete
echo "Backup completed: ${BACKUP_DIR}/marchproxy_${DATE}.sql.gz"
Volume Backup¶
#!/bin/bash
# volume-backup.sh - Volume backup script
docker run --rm \
-v marchproxy_postgres_data:/source:ro \
-v /backup:/backup \
alpine tar czf /backup/postgres_data_$(date +%Y%m%d).tar.gz -C /source .
docker run --rm \
-v marchproxy_manager_data:/source:ro \
-v /backup:/backup \
alpine tar czf /backup/manager_data_$(date +%Y%m%d).tar.gz -C /source .
Recovery Procedure¶
#!/bin/bash
# restore.sh - Database restore script
BACKUP_FILE="$1"
if [ -z "$BACKUP_FILE" ]; then
echo "Usage: $0 <backup_file.sql.gz>"
exit 1
fi
# Stop services
docker-compose down
# Restore database
docker-compose up -d postgres
sleep 10
gunzip -c ${BACKUP_FILE} | docker exec -i marchproxy_postgres_1 psql -U marchproxy marchproxy
# Start all services
docker-compose up -d
echo "Restore completed from: ${BACKUP_FILE}"
Performance Tuning¶
System Optimization¶
# /etc/sysctl.d/99-marchproxy.conf
# Network performance tuning
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.core.rmem_default = 65536
net.core.wmem_default = 65536
net.netfilter.nf_conntrack_max = 1048576
# Memory optimization
vm.swappiness = 10
vm.dirty_ratio = 15
vm.dirty_background_ratio = 5
# Apply settings
sysctl -p /etc/sysctl.d/99-marchproxy.conf
Docker Optimization¶
# /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2",
"default-ulimits": {
"nofile": {
"Name": "nofile",
"Hard": 65536,
"Soft": 65536
}
}
}
# Restart Docker daemon
sudo systemctl restart docker
Troubleshooting¶
Common Deployment Issues¶
-
Permission Errors:
-
Port Conflicts:
-
Memory Issues:
-
eBPF Failures:
Log Analysis¶
# View service logs
docker-compose logs -f manager
docker-compose logs -f proxy
# Export logs
docker-compose logs --no-color > marchproxy-logs.txt
# Monitor resource usage
docker stats
Migration¶
Version Upgrades¶
# Backup before upgrade
./backup.sh
# Pull new images
docker-compose pull
# Update with zero downtime
docker-compose up -d --no-deps manager
docker-compose up -d --no-deps proxy
# Verify upgrade
curl http://localhost:8000/version
curl http://localhost:8080/version
Next: Kubernetes Deployment