Docker Deployment
Deploy Zero using Docker Compose for quick single-server or small-scale deployments. This is the fastest way to get a self-hosted Zero instance running.
Prerequisites: Ensure you've reviewed the
requirements before proceeding.
Quick Start
# Clone the repository
git clone https://zero.xaltrax.com/contact.git
cd zero
# Copy environment template
cp .env.example .env
# Edit configuration
nano .env
# Start all services
docker compose up -d Configuration
Environment Variables
Edit the .env file with your settings:
# Domain Configuration
DOMAIN=zero.yourdomain.com
API_URL=https://api.yourdomain.com
CONSOLE_URL=https://console.yourdomain.com
# Database
POSTGRES_PASSWORD=your-secure-password-here
POSTGRES_DB=zero
# Redis
REDIS_PASSWORD=your-redis-password
# JWT Secret (generate with: openssl rand -base64 32)
JWT_SECRET=your-jwt-secret-here
# Encryption Key (generate with: openssl rand -base64 32)
ENCRYPTION_KEY=your-encryption-key-here
# VPN Configuration
VPN_ENDPOINT=vpn.yourdomain.com
VPN_PORT=51820
# Optional: SMTP for notifications
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=notifications@yourdomain.com
SMTP_PASSWORD=your-smtp-password
# Optional: SSO Configuration
OIDC_ISSUER_URL=https://auth.yourdomain.com
OIDC_CLIENT_ID=zero
OIDC_CLIENT_SECRET=your-oidc-secret Docker Compose File
The included docker-compose.yml deploys:
- zero-api - REST API server
- zero-web - Management console
- postgres - PostgreSQL 16 database
- redis - Redis 7 cache
- wireguard - VPN server
- prometheus - Metrics collection (optional)
- grafana - Dashboards (optional)
Service Configuration
version: '3.8'
services:
api:
image: ghcr.io/zero/zero-api:latest
restart: unless-stopped
ports:
- "8080:8080"
environment:
- DATABASE_URL=postgres://zero:${POSTGRES_PASSWORD}@postgres:5432/zero
- REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379
- JWT_SECRET=${JWT_SECRET}
- ENCRYPTION_KEY=${ENCRYPTION_KEY}
depends_on:
- postgres
- redis
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/api/v1/health"]
interval: 30s
timeout: 10s
retries: 3
postgres:
image: postgres:16-alpine
restart: unless-stopped
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=zero
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=zero
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
wireguard:
image: ghcr.io/zero/zero-vpn:latest
restart: unless-stopped
cap_add:
- NET_ADMIN
- SYS_MODULE
ports:
- "51820:51820/udp"
volumes:
- wireguard_data:/etc/wireguard
environment:
- VPN_ENDPOINT=${VPN_ENDPOINT}
- API_URL=http://api:8080
volumes:
postgres_data:
redis_data:
wireguard_data: SSL/TLS Setup
Using Let's Encrypt (Recommended)
# Install Caddy as reverse proxy
docker run -d \
--name caddy \
--network zero_default \
-p 80:80 -p 443:443 \
-v caddy_data:/data \
-v caddy_config:/config \
-v ./Caddyfile:/etc/caddy/Caddyfile \
caddy:latest Create a Caddyfile:
api.yourdomain.com {
reverse_proxy api:8080
}
console.yourdomain.com {
reverse_proxy web:3000
} Using Custom Certificates
# Mount your certificates
volumes:
- ./certs/cert.pem:/etc/ssl/certs/zero.pem
- ./certs/key.pem:/etc/ssl/private/zero.key Database Initialization
On first run, initialize the database:
# Run migrations
docker compose exec api zero-api migrate up
# Create admin user
docker compose exec api zero-api admin create \
--email admin@yourdomain.com \
--password your-secure-password
# Create organization
docker compose exec api zero-api org create \
--name "Your Organization" \
--admin admin@yourdomain.com Verification
# Check all services are running
docker compose ps
# Check API health
curl https://api.yourdomain.com/api/v1/health
# Check logs
docker compose logs -f api
# Test database connection
docker compose exec postgres psql -U zero -c "SELECT version();" Backup & Restore
Automated Backup
#!/bin/bash
# backup.sh - Run daily via cron
BACKUP_DIR=/var/backups/zero
DATE=$(date +%Y%m%d_%H%M%S)
# Backup PostgreSQL
docker compose exec -T postgres pg_dump -U zero zero | \
gzip > $BACKUP_DIR/postgres_$DATE.sql.gz
# Backup Redis
docker compose exec -T redis redis-cli --pass $REDIS_PASSWORD BGSAVE
docker cp zero-redis-1:/data/dump.rdb $BACKUP_DIR/redis_$DATE.rdb
# Backup WireGuard keys
docker cp zero-wireguard-1:/etc/wireguard $BACKUP_DIR/wireguard_$DATE
# Cleanup old backups (keep 30 days)
find $BACKUP_DIR -mtime +30 -delete Restore
# Restore PostgreSQL
gunzip -c backup.sql.gz | docker compose exec -T postgres psql -U zero zero
# Restore Redis
docker cp redis_backup.rdb zero-redis-1:/data/dump.rdb
docker compose restart redis Updating
# Pull latest images
docker compose pull
# Restart with new images
docker compose up -d
# Run any new migrations
docker compose exec api zero-api migrate up Monitoring
Enable Prometheus and Grafana for monitoring:
# In docker-compose.yml, uncomment:
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana Troubleshooting
| Issue | Solution |
|---|---|
| API not starting | Check docker compose logs api for errors |
| Database connection failed | Verify POSTGRES_PASSWORD matches in .env |
| VPN not working | Ensure UDP 51820 is open in firewall |
| SSL errors | Check certificate paths and permissions |
Next Steps
- Kubernetes Deployment - For larger deployments
- VPN Server Configuration - Advanced VPN setup
- API Documentation - Integrate with your systems