Skip to main content

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

VariableDescriptionExample
[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

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:

  1. Check container logs:
    docker compose logs [service-name]
  2. Common causes:
    • Port already in use
    • Missing environment variables
    • Volume permission issues
    • Memory limit too low
  3. Check resource usage:
    docker stats
  4. Verify dependencies are healthy:
    docker compose ps

Issue: Cannot connect to database

Symptoms: Service logs show database connection errors

Solutions:

  1. Check database container is running:
    docker compose ps postgres
  2. Verify database credentials in .env:
    cat .env | grep DB_
  3. Check network connectivity:
    docker compose exec [service] ping postgres
  4. Check database logs:
    docker compose logs postgres
  5. 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:

  1. Check disk usage:
    df -h
    du -sh /var/lib/docker/*
  2. Clean up Docker resources:
    docker system prune -a --volumes
    # WARNING: This removes unused data
  3. Check volume sizes:
    docker system df -v
  4. Consider adding additional Hetzner volume

Issue: Service accessible locally but not from internet

Symptoms: Can access via localhost but not via domain

Solutions:

  1. Check firewall rules:
    ufw status
    # Ensure ports 80, 443 are open
  2. Verify DNS is configured:
    dig [DOMAIN]
  3. Check Nginx/proxy is running:
    systemctl status nginx
  4. Test from server:
    curl http://localhost:[PORT]
  5. 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)