| name | dokploy-health-patterns |
| description | Health check patterns for different service types in Dokploy templates. Covers HTTP, PostgreSQL, MongoDB, Redis, MySQL, and custom health checks. |
| version | 1.0.0 |
| author | Home Lab Infrastructure Team |
Dokploy Health Patterns
When to Use This Skill
- When adding health checks to any Dokploy service
- When configuring service dependencies with
service_healthy - When troubleshooting container startup order issues
- When user asks about "health checks" or "service dependencies"
When NOT to Use This Skill
- For services that don't support health checks (rare, most do)
- For helper services that start instantly (use
service_startedinstead)
Prerequisites
- Understanding of service internals (ports, health endpoints)
- Knowledge of available tools in container (curl, wget, etc.)
Core Pattern
Standard Health Check Template
Every health check follows this structure:
healthcheck:
test: ["CMD", "command", "args"]
interval: 30s # How often to check
timeout: 10s # Max time per check
retries: 3 # Failures before unhealthy
start_period: 30s # Grace period for startup
Configuration Guidelines:
| Parameter | Default | When to Adjust |
|---|---|---|
interval |
30s | Increase for resource-constrained systems |
timeout |
10s | Increase for slow-starting services |
retries |
3 | Increase for flaky services |
start_period |
30s | Increase for complex services (databases, Java apps) |
Health Check Patterns by Service Type
Pattern 1: HTTP Services (curl)
For services with HTTP endpoints (most web apps):
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:${PORT}/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
Variations:
# With specific health endpoint
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
# With API endpoint
test: ["CMD", "curl", "-f", "http://localhost:3000/api/healthz"]
# Silent output
test: ["CMD", "curl", "-sf", "http://localhost:8080/ping"]
Pattern 2: HTTP Services (wget - Alpine-based)
For Alpine-based images without curl:
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:${PORT}"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
Example (Paaster):
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
Pattern 3: PostgreSQL
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
Variations:
# With specific host
test: ["CMD-SHELL", "pg_isready -U postgres -d mydb -h localhost"]
# With default user
test: ["CMD-SHELL", "pg_isready -U postgres"]
# With environment variable interpolation
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-postgres}"]
Pattern 4: MongoDB
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
Variations:
# For older MongoDB (pre-6.0, use mongo instead of mongosh)
test: ["CMD", "mongo", "--eval", "db.adminCommand('ping')"]
# With authentication
test: ["CMD", "mongosh", "-u", "admin", "-p", "${MONGO_PASSWORD}", "--eval", "db.adminCommand('ping')"]
Pattern 5: Redis
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s # Redis starts fast
Variations:
# With password
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
# Check specific key exists
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
Pattern 6: MySQL/MariaDB
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
Variations:
# With credentials
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
# Using mysql client
test: ["CMD-SHELL", "mysql -u root -p${MYSQL_ROOT_PASSWORD} -e 'SELECT 1'"]
Pattern 7: Elasticsearch
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9200/_cluster/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s # ES takes longer to start
Pattern 8: RabbitMQ
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
Pattern 9: Custom Shell Commands
For complex checks using shell scripting:
healthcheck:
test: ["CMD-SHELL", "command1 && command2 || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
Example (ANyONe Relay):
healthcheck:
test: ["CMD-SHELL", "echo 'GETINFO status/circuit-established' | nc -q 1 localhost 9051 | grep -q '250' || exit 1"]
interval: 60s
timeout: 15s
retries: 3
start_period: 120s
Complete Examples
Example 1: Web App with MongoDB (Paaster)
services:
paaster:
image: wardpearce/paaster:3.1.7
depends_on:
mongodb:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
mongodb:
image: mongo:7
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
Example 2: Complex Stack (Paperless-ngx)
services:
paperless:
image: ghcr.io/paperless-ngx/paperless-ngx:2.13
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
gotenberg:
condition: service_started # Helper, doesn't need healthy
tika:
condition: service_started # Helper, doesn't need healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s # Longer for complex app
postgres:
image: postgres:16-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-paperless} -d ${POSTGRES_DB:-paperless}"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s # Redis is fast
gotenberg:
image: gotenberg/gotenberg:8
# No healthcheck needed - stateless helper
tika:
image: apache/tika:2.9.1.0
# No healthcheck needed - stateless helper
Example 3: Git Service with PostgreSQL (Forgejo)
services:
forgejo:
image: codeberg.org/forgejo/forgejo:9
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/healthz"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
postgres:
image: postgres:16-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${FORGEJO_DB_USER:-forgejo} -d ${FORGEJO_DB_NAME:-forgejo}"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
Start Period Recommendations
| Service Type | Recommended start_period |
|---|---|
| Redis | 10s |
| Static file server | 10s |
| Simple web app | 30s |
| Node.js app | 30s |
| PostgreSQL | 30s |
| MongoDB | 30s |
| MySQL | 45s |
| Java/Spring Boot | 60-120s |
| Paperless-ngx | 60s |
| Elasticsearch | 60-120s |
| Custom services | Test and adjust |
Dependency Conditions
When to use service_healthy
depends_on:
database:
condition: service_healthy
Use for:
- Databases (PostgreSQL, MongoDB, Redis, MySQL)
- Services that need initialization time
- Services the app actively connects to on startup
When to use service_started
depends_on:
helper:
condition: service_started
Use for:
- Stateless helper services (Gotenberg, Tika)
- Services called on-demand, not at startup
- Fast-starting auxiliary services
Quality Standards
Mandatory Requirements
- All persistent services have health checks
- Databases use appropriate native health commands
- Web services use HTTP health checks
- Dependencies use
service_healthycondition - Start period appropriate for service type
Testing Health Checks
# Check health status
docker compose ps
# View health check logs
docker inspect --format='{{json .State.Health}}' container_name
Common Pitfalls
Pitfall 1: Wrong tool for image
Issue: curl not available in Alpine images Solution: Use wget for Alpine, curl for Debian/Ubuntu
Pitfall 2: start_period too short
Issue: Service marked unhealthy during startup Solution: Increase start_period for slow-starting services
Pitfall 3: Checking wrong port
Issue: Health check fails, service works Solution: Use internal container port, not mapped port
Pitfall 4: Missing CMD-SHELL for pipes
Issue: Shell commands fail
Solution: Use ["CMD-SHELL", "cmd | grep ..."] for pipes/redirects
Pitfall 5: Health endpoint requires auth
Issue: 401/403 errors in health check Solution: Use unauthenticated health endpoint or add credentials
Integration
Skills-First Approach (v2.0+)
This skill is part of the skills-first architecture - loaded during Generation phase to add health checks after routing configuration.
Related Skills
dokploy-compose-structure: Service dependenciesdokploy-multi-service: Complex dependency chains
Invoked By
/dokploy-createcommand: Phase 3 (Generation) - Step 3
Order in Workflow (Progressive Loading)
dokploy-compose-structure: Create base structuredokploy-traefik-routing: Add routing labels- This skill: Add health checks (Step 3)
dokploy-cloudflare-integration: Add CF integration (if applicable)dokploy-environment-config: Configure environmentdokploy-template-toml: Create template.toml
See: .claude/commands/dokploy-create.md for full workflow