Docker Compose Service Setup Prompt
Context
Use this prompt when deploying a new service using Docker Compose on Pacing Agency's Hetzner infrastructure. Common use cases include:
- Deploying self-hosted applications (n8n, TwentyCRM, Notifuse, Remark42)
- Setting up databases (PostgreSQL, Redis, MongoDB)
- Running web services with reverse proxy (Nginx, Caddy)
- Multi-container applications
- Development environments
This prompt will help you:
- Create a production-ready docker-compose.yml file
- Configure volumes, networks, and environment variables
- Set up proper security and resource limits
- Implement health checks and restart policies
- Document the deployment
Prerequisites
- Server access - SSH access to Hetzner server
- Docker installed - Docker Engine and Docker Compose V2
- Service requirements - Know what the service needs (ports, volumes, databases)
- Environment variables - Credentials, API keys, configuration values
- Domain/subdomain - If web service, DNS should be configured
See Hetzner Tool Documentation for server details and Docker best practices.
Prompt Template
I need to deploy a new service using Docker Compose on a Hetzner server with the following requirements:
**Service Information:**
- Service name: [SERVICE_NAME]
- Purpose: [SERVICE_PURPOSE]
- Docker image: [DOCKER_IMAGE] (and version/tag)
- Server: [SERVER_NAME] (from Hetzner documentation)
**Service Requirements:**
- Exposed ports: [PORT_LIST] (e.g., 80, 443, 5678)
- Volumes/storage: [VOLUME_REQUIREMENTS]
- Database: [DATABASE_REQUIREMENTS] (if needed)
- Memory limit: [MEMORY_LIMIT]
- CPU limit: [CPU_LIMIT]
- Reverse proxy: [PROXY_REQUIREMENTS] (Nginx/Caddy/Traefik/None)
**Environment Variables:**
- Required env vars: [ENV_VAR_LIST]
- Secrets: [SECRET_LIST] (passwords, API keys, tokens)
- Configuration: [CONFIG_LIST]
**Network Configuration:**
- Public/private: [NETWORK_TYPE]
- Custom domain: [DOMAIN] (if applicable)
- SSL certificate: [SSL_REQUIREMENTS]
**Data Persistence:**
- Volumes to create: [VOLUME_LIST]
- Backup requirements: [BACKUP_REQUIREMENTS]
- Data location: [DATA_PATH]
Please provide:
1. **Complete docker-compose.yml file**:
- Service definitions
- Volume configurations
- Network setup
- Environment variables
- Health checks
- Restart policies
- Resource limits
2. **Environment file (.env) template**:
- All required variables
- Example values
- Security notes
3. **Deployment script**:
- Pre-deployment checks
- Service startup commands
- Verification steps
- Rollback procedure
4. **Reverse proxy configuration** (if applicable):
- Nginx/Caddy config
- SSL certificate setup
- Domain routing
5. **Health check and monitoring setup**:
- Container health checks
- Logging configuration
- Restart policies
6. **Documentation template** for adding to service tool doc
Include:
- Security best practices
- Performance optimizations
- Backup procedures
- Update/upgrade process
- Troubleshooting guide
Format with clear sections and code blocks.
Variables to Customize
| Variable | Description | Example |
|---|---|---|
[SERVICE_NAME] | Service/application name | "n8n", "twentycrm", "notifuse" |
[SERVICE_PURPOSE] | What the service does | "Workflow automation for client integrations" |
[DOCKER_IMAGE] | Docker image to use | "n8nio/n8n:latest", "twentycrm/twenty:latest" |
[SERVER_NAME] | Hetzner server name | "n8n2", "twenty-crm-prod-2", "remark42" |
[PORT_LIST] | Ports to expose | "5678" (n8n), "3000" (TwentyCRM), "80, 443" (web) |
[VOLUME_REQUIREMENTS] | Storage needs | "10GB for data", "5GB for PostgreSQL" |
[DATABASE_REQUIREMENTS] | Database needs | "PostgreSQL 15", "Redis 7", "None" |
[MEMORY_LIMIT] | RAM limit | "2GB", "4GB", "None" |
[CPU_LIMIT] | CPU limit | "2 cores", "50% of one core", "None" |
[PROXY_REQUIREMENTS] | Reverse proxy | "Nginx with SSL", "Caddy", "None (direct)" |
[ENV_VAR_LIST] | Environment variables | "N8N_HOST, N8N_PORT, DB_CONNECTION_URL" |
[SECRET_LIST] | Sensitive data | "Database password, API keys, JWT secret" |
[CONFIG_LIST] | Configuration | "Webhook URL, timezone, language" |
[NETWORK_TYPE] | Network visibility | "Public (80/443)", "Private (internal only)" |
[DOMAIN] | Custom domain | "n8n.pacing.agency", "crm.pacing.agency" |
[SSL_REQUIREMENTS] | SSL setup | "Let's Encrypt auto", "Cloudflare proxy" |
[VOLUME_LIST] | Volume names | "n8n_data", "postgres_data" |
[BACKUP_REQUIREMENTS] | Backup needs | "Daily database backup", "Weekly volume snapshot" |
[DATA_PATH] | Where data is stored | "/var/lib/docker/volumes", "/data/service-name" |
Expected Output
The AI should provide:
1. docker-compose.yml File
# Example: n8n with PostgreSQL
version: '3.8'
services:
n8n:
image: n8nio/n8n:latest
container_name: n8n
restart: unless-stopped
ports:
- "5678:5678"
environment:
- N8N_HOST=${N8N_HOST}
- N8N_PORT=5678
- N8N_PROTOCOL=${N8N_PROTOCOL}
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=${DB_NAME}
- DB_POSTGRESDB_USER=${DB_USER}
- DB_POSTGRESDB_PASSWORD=${DB_PASSWORD}
- WEBHOOK_URL=${WEBHOOK_URL}
- GENERIC_TIMEZONE=${TIMEZONE}
volumes:
- n8n_data:/home/node/.n8n
depends_on:
postgres:
condition: service_healthy
networks:
- n8n_network
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:5678/healthz"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
postgres:
image: postgres:15-alpine
container_name: n8n_postgres
restart: unless-stopped
environment:
- POSTGRES_DB=${DB_NAME}
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_NON_ROOT_USER=${DB_USER}
- POSTGRES_NON_ROOT_PASSWORD=${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- n8n_network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
interval: 10s
timeout: 5s
retries: 5
volumes:
n8n_data:
name: n8n_data
postgres_data:
name: n8n_postgres_data
networks:
n8n_network:
name: n8n_network
driver: bridge
2. .env File Template
# n8n Configuration
N8N_HOST=n8n.pacing.agency
N8N_PROTOCOL=https
N8N_PORT=5678
WEBHOOK_URL=https://n8n.pacing.agency/
GENERIC_TIMEZONE=Europe/London
# Database Configuration
DB_NAME=n8n
DB_USER=n8n_user
DB_PASSWORD=CHANGE_THIS_SECURE_PASSWORD_123
# Security - Generate secure passwords
# You can use: openssl rand -base64 32
3. Deployment Script
#!/bin/bash
# deploy.sh - Deploy n8n service
set -e # Exit on error
echo "🚀 Deploying n8n service..."
# Check prerequisites
echo "✅ Checking prerequisites..."
command -v docker >/dev/null 2>&1 || { echo "❌ Docker is required"; exit 1; }
command -v docker compose >/dev/null 2>&1 || { echo "❌ Docker Compose V2 is required"; exit 1; }
# Check .env file exists
if [ ! -f .env ]; then
echo "❌ .env file not found"
echo "📝 Please create .env file from .env.example"
exit 1
fi
# Backup existing data (if updating)
if [ "$(docker ps -q -f name=n8n)" ]; then
echo "📦 Backing up existing data..."
docker compose exec -T n8n sh -c 'tar czf /tmp/n8n_backup_$(date +%Y%m%d_%H%M%S).tar.gz /home/node/.n8n'
fi
# Pull latest images
echo "📥 Pulling latest images..."
docker compose pull
# Stop and remove old containers
echo "🛑 Stopping existing containers..."
docker compose down
# Start services
echo "▶️ Starting services..."
docker compose up -d
# Wait for services to be healthy
echo "⏳ Waiting for services to be healthy..."
sleep 10
docker compose ps
# Verify services are running
echo "✅ Verifying services..."
if [ "$(docker compose ps -q n8n | xargs docker inspect -f '{{.State.Health.Status}}')" == "healthy" ]; then
echo "✅ n8n is healthy"
else
echo "❌ n8n is not healthy"
docker compose logs n8n
exit 1
fi
# Show logs
echo "📋 Recent logs:"
docker compose logs --tail=20
echo "✅ Deployment complete!"
echo "🌐 Access n8n at: https://n8n.pacing.agency"
4. Nginx Reverse Proxy Config (if needed)
# /etc/nginx/sites-available/n8n.conf
server {
listen 80;
listen [::]:80;
server_name n8n.pacing.agency;
# Redirect to HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name n8n.pacing.agency;
# SSL Configuration (Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/n8n.pacing.agency/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/n8n.pacing.agency/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
# Proxy to n8n
location / {
proxy_pass http://localhost:5678;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
# Timeouts for long-running workflows
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
}
5. Backup Script
#!/bin/bash
# backup.sh - Backup n8n data and database
BACKUP_DIR="/backups/n8n"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
echo "📦 Backing up n8n data..."
docker compose exec -T n8n tar czf - /home/node/.n8n > "$BACKUP_DIR/n8n_data_$DATE.tar.gz"
echo "📦 Backing up PostgreSQL database..."
docker compose exec -T postgres pg_dump -U n8n_user n8n | gzip > "$BACKUP_DIR/n8n_db_$DATE.sql.gz"
# Keep only last 7 days of backups
find $BACKUP_DIR -name "*.gz" -mtime +7 -delete
echo "✅ Backup complete: $BACKUP_DIR"
Follow-up Actions
After deploying the service:
1. Document in Service Tool Doc
Add deployment details to the appropriate tool doc (e.g., tools/n8n.md):
## Deployment
**Server**: [SERVER_NAME]
**Docker Compose**: `/opt/[service-name]/docker-compose.yml`
**Data volumes**: [VOLUME_LIST]
**Access**: https://[DOMAIN]
**Deployment**:
```bash
cd /opt/[service-name]
docker compose up -d
Update:
cd /opt/[service-name]
./deploy.sh
### 2. Set Up Automated Backups
Configure cron job for regular backups:
```bash
# Edit crontab
crontab -e
# Add backup job (daily at 2 AM)
0 2 * * * /opt/[service-name]/backup.sh >> /var/log/backup.log 2>&1
3. Configure Monitoring
Set up monitoring:
- Docker container health checks
- Disk space monitoring
- Service uptime monitoring
- Log rotation
4. Test Disaster Recovery
Verify backups work:
# Test restore to a new server/container
# 1. Copy backup files
# 2. Deploy fresh instance
# 3. Restore data
# 4. Verify service works
5. Document Team Access
Update team documentation:
- Who has SSH access
- Where credentials are stored
- How to access logs
- Emergency procedures
Related Documentation
- Hetzner Tool Documentation - Server details
- Docker Best Practices - Container management
- n8n Documentation - Example deployment
- Architecture - Infrastructure overview
Success Criteria
Before considering deployment complete, verify:
✅ Service is running and accessible
✅ Health checks are passing
✅ Data is persisting across restarts
✅ Backups are configured and tested
✅ Logs are accessible and rotated
✅ Resource limits are appropriate
✅ Security is configured (SSL, firewall)
✅ Monitoring is set up
✅ Documentation is updated
✅ Team has access and knows how to operate
Common Issues
Issue: Container keeps restarting
Symptoms: Container status shows "Restarting"
Solutions:
- Check container logs:
docker compose logs [service-name] - Common causes:
- Port already in use
- Missing environment variables
- Volume permission issues
- Memory limit too low
- Check resource usage:
docker stats - Verify dependencies are healthy:
docker compose ps
Issue: Cannot connect to database
Symptoms: Service logs show database connection errors
Solutions:
- Check database container is running:
docker compose ps postgres - Verify database credentials in .env:
cat .env | grep DB_ - Check network connectivity:
docker compose exec [service] ping postgres - Check database logs:
docker compose logs postgres - Verify database is ready:
docker compose exec postgres pg_isready
Issue: Out of disk space
Symptoms: Containers fail, "no space left on device" errors
Solutions:
- Check disk usage:
df -h
du -sh /var/lib/docker/* - Clean up Docker resources:
docker system prune -a --volumes
# WARNING: This removes unused data - Check volume sizes:
docker system df -v - Consider adding additional Hetzner volume
Issue: Service accessible locally but not from internet
Symptoms: Can access via localhost but not via domain
Solutions:
- Check firewall rules:
ufw status
# Ensure ports 80, 443 are open - Verify DNS is configured:
dig [DOMAIN] - Check Nginx/proxy is running:
systemctl status nginx - Test from server:
curl http://localhost:[PORT] - Check SSL certificate:
certbot certificates
Examples
Example 1: n8n with PostgreSQL
See full example in Expected Output section above.
Purpose: Workflow automation server
Services: n8n + PostgreSQL
Ports: 5678
Domain: n8n.pacing.agency
Example 2: TwentyCRM
version: '3.8'
services:
twentycrm:
image: twentycrm/twenty:latest
container_name: twentycrm
restart: unless-stopped
ports:
- "3000:3000"
environment:
- PORT=3000
- SERVER_URL=https://crm.pacing.agency
- PG_DATABASE_URL=postgresql://twenty:password@postgres:5432/twenty
volumes:
- twenty_data:/app/.local-storage
depends_on:
- postgres
networks:
- twenty_network
postgres:
image: postgres:15-alpine
container_name: twenty_postgres
restart: unless-stopped
environment:
- POSTGRES_DB=twenty
- POSTGRES_USER=twenty
- POSTGRES_PASSWORD=CHANGE_ME
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- twenty_network
volumes:
twenty_data:
postgres_data:
networks:
twenty_network:
Example 3: Remark42 Comments
version: '3.8'
services:
remark42:
image: umputun/remark42:latest
container_name: remark42
restart: unless-stopped
ports:
- "8080:8080"
environment:
- REMARK_URL=https://comments.pacing.agency
- SECRET=${SECRET}
- ADMIN_SHARED_ID=${ADMIN_ID}
- SITE=pacing
- AUTH_GOOGLE_CID=${GOOGLE_CLIENT_ID}
- AUTH_GOOGLE_CSEC=${GOOGLE_CLIENT_SECRET}
volumes:
- remark42_data:/srv/var
volumes:
remark42_data:
Last updated: 2026-01-07
Tested on: Docker Engine 24.0, Docker Compose V2
Estimated time: 25 minutes (setup + testing)