Install
openclaw skills install compose-prodGenerate production-grade docker-compose.yml for any project. Includes health checks for every service, network segmentation (frontend/backend/db), resource limits, log rotation, restart policies, secrets management, and backup volumes. Stack-agnostic — works with Node.js, Python, Go, Java, Ruby, PHP, or any Dockerized app. Use when the user says 'docker compose', 'production compose', 'dockerize', 'containerize', or needs a production-ready Compose file.
openclaw skills install compose-prodGenerate a production-grade docker-compose.yml from any project, with health checks, network segmentation, resource limits, logging, secrets, and backup volumes.
Dockerfile in the project (or enough context to generate one)Scan the project directory to determine:
package.json -> Node.js / Next.js / Remix / etc.requirements.txt / pyproject.toml / Pipfile -> Pythongo.mod -> Gopom.xml / build.gradle -> JavaGemfile -> Rubycomposer.json -> PHPCargo.toml -> RustDockerfile EXPOSE, framework defaults, or askpg, prisma, psycopg, sqlalchemy+postgresql -> PostgreSQLredis, ioredis, bull, celery[redis] -> Redismongoose, mongodb, pymongo, motor -> MongoDBmysql2, mysqlclient, pymysql -> MySQL.env, .env.local, .env.example for required varsGenerate the full Compose file following EVERY rule below. Do NOT skip any section.
# Production Docker Compose
# Generated for: <project-name>
# Stack: <detected-stack>
# Run: docker compose up -d
# Validate: docker compose config
services:
app:
build:
context: .
dockerfile: Dockerfile
container_name: <project-name>-app
restart: unless-stopped
ports:
- "127.0.0.1:${APP_PORT:-3000}:${APP_PORT:-3000}"
env_file:
- .env
networks:
- frontend
- backend
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:${APP_PORT:-3000}/health || curl -f http://localhost:${APP_PORT:-3000}/ || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
reservations:
memory: 256M
cpus: '0.25'
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
depends_on:
# Add database services here with condition: service_healthy
Key rules for the app service:
127.0.0.1 — never expose directly to 0.0.0.0. Use a reverse proxy (Nginx/Traefik/Caddy) for external traffic.env_file instead of inline environment with secrets.restart: unless-stopped.Include ONLY the databases detected in Phase 1. Every database MUST have: health check, volume, resource limits, logging, restart policy, and be on the database network only.
PostgreSQL:
postgres:
image: postgres:17-alpine
container_name: <project-name>-postgres
restart: unless-stopped
volumes:
- pgdata:/var/lib/postgresql/data
- pgbackup:/backups
environment:
POSTGRES_DB: ${POSTGRES_DB:-app}
POSTGRES_USER: ${POSTGRES_USER:-app}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
networks:
- database
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-app} -d ${POSTGRES_DB:-app}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
reservations:
memory: 256M
cpus: '0.25'
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
Redis:
redis:
image: redis:7-alpine
container_name: <project-name>-redis
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD:-changeme} --maxmemory 256mb --maxmemory-policy allkeys-lru
volumes:
- redisdata:/data
networks:
- database
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-changeme}", "ping"]
interval: 10s
timeout: 3s
retries: 3
start_period: 10s
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
reservations:
memory: 64M
cpus: '0.1'
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
MongoDB:
mongo:
image: mongo:8
container_name: <project-name>-mongo
restart: unless-stopped
volumes:
- mongodata:/data/db
- mongobackup:/backups
environment:
MONGO_INITDB_ROOT_USERNAME: ${MONGO_USER:-admin}
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD:?MONGO_PASSWORD is required}
MONGO_INITDB_DATABASE: ${MONGO_DB:-app}
networks:
- database
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')", "-u", "${MONGO_USER:-admin}", "-p", "${MONGO_PASSWORD}", "--authenticationDatabase", "admin", "--quiet"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
reservations:
memory: 256M
cpus: '0.25'
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
MySQL:
mysql:
image: mysql:9
container_name: <project-name>-mysql
restart: unless-stopped
volumes:
- mysqldata:/var/lib/mysql
- mysqlbackup:/backups
environment:
MYSQL_DATABASE: ${MYSQL_DB:-app}
MYSQL_USER: ${MYSQL_USER:-app}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:?MYSQL_PASSWORD is required}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:?MYSQL_ROOT_PASSWORD is required}
networks:
- database
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
reservations:
memory: 256M
cpus: '0.25'
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
ALWAYS define three isolated networks. Services connect ONLY to the networks they need:
networks:
frontend:
driver: bridge
name: <project-name>-frontend
backend:
driver: bridge
name: <project-name>-backend
database:
driver: bridge
name: <project-name>-database
internal: true # No external connectivity for the database network
Network assignment rules:
frontend, backend, AND database (it bridges all three)database ONLY — never frontendbackend and database — never frontenddatabase network MUST be internal: true to block external accessDefine named volumes for ALL persistent data. Include backup volumes for databases:
volumes:
pgdata:
driver: local
name: <project-name>-pgdata
pgbackup:
driver: local
name: <project-name>-pgbackup
redisdata:
driver: local
name: <project-name>-redisdata
mongodata:
driver: local
name: <project-name>-mongodata
mongobackup:
driver: local
name: <project-name>-mongobackup
mysqldata:
driver: local
name: <project-name>-mysqldata
mysqlbackup:
driver: local
name: <project-name>-mysqlbackup
Only include volumes for services that are actually in the Compose file.
For higher security, use Docker Compose file-based secrets instead of env_file for sensitive values:
secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
file: ./secrets/api_key.txt
Then reference in services:
services:
app:
secrets:
- db_password
- api_key
environment:
DB_PASSWORD_FILE: /run/secrets/db_password
Secret rules:
env_file approach — it works everywhere and most teams know it.secrets: approach when the user asks for tighter security.secrets/ directory with .gitignore to exclude it.Create a .env.example file listing ALL environment variables used in the Compose file with safe placeholder values:
# Application
APP_PORT=3000
NODE_ENV=production
# PostgreSQL
POSTGRES_DB=app
POSTGRES_USER=app
POSTGRES_PASSWORD=CHANGE_ME_STRONG_PASSWORD
# Redis
REDIS_PASSWORD=CHANGE_ME_STRONG_PASSWORD
# MongoDB
MONGO_DB=app
MONGO_USER=admin
MONGO_PASSWORD=CHANGE_ME_STRONG_PASSWORD
Offer to add these based on the project's needs. Ask the user before including:
Nginx reverse proxy (if no external proxy exists):
nginx:
image: nginx:alpine
container_name: <project-name>-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
networks:
- frontend
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
memory: 128M
cpus: '0.5'
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
depends_on:
app:
condition: service_healthy
Worker / queue processor:
worker:
build:
context: .
dockerfile: Dockerfile
container_name: <project-name>-worker
restart: unless-stopped
command: <worker-command> # e.g., "npm run worker", "celery -A app worker"
env_file:
- .env
networks:
- backend
- database
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
depends_on:
app:
condition: service_healthy
After generating, run validation:
docker compose config
This checks:
If validation fails, fix the issue and re-validate. Do NOT deliver an invalid Compose file.
Tell the user:
docker compose up -ddocker compose logs -fdocker compose ps (shows health status)docker compose downdocker compose down -v (warn: destroys volumes).env.example to .env and fill in real valuestest: ["CMD-SHELL", "exit 0"] as a placeholder and comment that the user should replace it.json-file driver with max-size: 10m and max-file: 3.unless-stopped for all production services.internal: true./backups for dump scripts.container_name: <project>-<service> for easy identification.docker compose config before delivering.For microservice projects with multiple apps:
database networkbackend networkfrontenddepends_on to express the dependency graphcurl may not be in slim images — use wget or a custom binary)docker network inspectdocker compose config to see the expanded and validated config