A production-ready, scalable, and secure Docker Compose setup for n8n workflow automation with PostgreSQL, Redis, and external Python runners.
- π Production-Ready: Queue-based execution, worker scaling, health checks
- π Security First: Non-root DB users, Redis auth, encrypted credentials
- π Scalable: Separate main/worker containers, external Python runners
- π Persistent: Docker volumes for data, zero-downtime updates
- π Timezone Aware: Proper configuration for scheduled workflows
git clone https://github.com/yourusername/n8n-setup.git
cd n8n-setup
cp .env.example .env# Edit .env file with your secure passwords
nano .env
# Or generate secure passwords:
openssl rand -base64 32 # For N8N_ENCRYPTION_KEY
openssl rand -base64 24 # For REDIS_PASSWORD# Start all services
docker-compose up -d
# Watch logs
docker-compose logs -f
# Check status
docker-compose ps- π Open: http://localhost:5678
- π First login: Create admin account
graph TB
User[π€ User] -->|Port 5678| Main[n8n Main<br/>Web UI & API]
Main -->|Queue Tasks| Redis[Redis Queue<br/>Message Broker]
Redis --> Worker1[n8n Worker #1]
Redis --> Worker2[n8n Worker #2]
Main -->|Python Tasks| Runners[Python Runners]
Main -->|Store Data| Postgres[(PostgreSQL Database)]
style Main fill:#FF6B6B
style Redis fill:#DC382D
style Postgres fill:#336791
graph TB
%% ΠΠ½ΠΈΡΠΈΠ°ΡΠΎΡΡ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ²
User[π€ User / External API]
Schedule[β° Scheduler]
%% ΠΡΠ½ΠΎΠ²Π½ΡΠ΅ ΡΠ΅ΡΠ²ΠΈΡΡ n8n
Main[n8n-main<br/><b>Web UI & API</b><br/>Port: 5678]
Workers[n8n-workers<br/><b>Task Processors</b>]
Runners[n8n-runners<br/><b>Python Executor</b>]
%% ΠΠ½ΡΡΠ°ΡΡΡΡΠΊΡΡΡΠ°
DB[(PostgreSQL<br/><b>Metadata & Results</b>)]
Queue{Redis<br/><b>Message Queue</b>}
Storage[(Shared Volume<br/>n8n_storage)]
%% Π‘Π²ΡΠ·ΠΈ
User -->|HTTP/WebSocket| Main
Schedule -->|Triggers| Main
Main -->|1. Store Workflow| DB
Main -->|2. Queue Tasks| Queue
Queue -->|3. Fetch Tasks| Workers
Queue -->|Tasks with Python| Runners
Workers -->|4. Save Results| DB
Runners -->|Python Results| DB
Main -.->|Mount| Storage
Workers -.->|Mount| Storage
Runners -.->|Mount| Storage
%% ΠΡΡΠΏΠΏΠΈΡΠΎΠ²ΠΊΠ° Π΄Π»Ρ Π½Π°Π³Π»ΡΠ΄Π½ΠΎΡΡΠΈ
subgraph "n8n Application Layer"
Main
Workers
Runners
end
subgraph "Infrastructure Layer"
DB
Queue
Storage
end
%% Π‘ΡΠΈΠ»ΠΈ Π΄Π»Ρ ΡΠ»ΡΡΡΠ΅Π½ΠΈΡ Π²ΠΎΡΠΏΡΠΈΡΡΠΈΡ
classDef service fill:#FF6B6B,color:white,stroke:#333,stroke-width:2px
classDef storage fill:#336791,color:white,stroke:#333,stroke-width:1px
classDef queue fill:#DC382D,color:white,stroke:#333,stroke-width:1px
classDef user fill:#4CAF50,color:white,stroke:#333,stroke-width:2px
class Main,Workers,Runners service
class DB,Storage storage
class Queue queue
class User,Schedule user
| Service | Purpose | Port | Image |
|---|---|---|---|
| n8n-main | Web UI & API gateway | 5678 | n8nio/n8n:latest |
| n8n-worker | Background task processing | - | n8nio/n8n:latest |
| n8n-runners | Python script execution | - | n8nio/runners:latest |
| PostgreSQL | Data persistence | 5432 | postgres:16 |
| Redis | Message queue & cache | 6379 | redis:7 |
# ========== DATABASE ==========
POSTGRES_USER=postgres_root
POSTGRES_PASSWORD=your_secure_password
POSTGRES_DB=n8n
POSTGRES_NON_ROOT_USER=n8n_user
POSTGRES_NON_ROOT_PASSWORD=user_secure_password
# ========== REDIS ==========
REDIS_PASSWORD=your_redis_password
# ========== N8N CORE ==========
N8N_ENCRYPTION_KEY=generate_with_openssl_rand_base64_32
GENERIC_TIMEZONE=Europe/Moscow
TZ=Europe/Moscow
# ========== EXTERNAL RUNNERS ==========
N8N_RUNNERS_ENABLED=true
N8N_RUNNERS_MODE=external
N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0
N8N_RUNNERS_AUTH_TOKEN=your_secure_runner_token# View real-time logs
docker-compose logs -f n8n-main
# Check service health
docker-compose ps
# Monitor resource usage
docker stats
# Access database
docker-compose exec postgres psql -U n8n_user -d n8n# Scale to 3 workers for heavy loads
docker-compose up -d --scale n8n-worker=3
# Scale Python runners
docker-compose up -d --scale n8n-runners=2# Backup database
docker-compose exec postgres pg_dump -U n8n_user n8n > backup_$(date +%Y%m%d).sql
# Backup volumes
tar -czf n8n_backup_$(date +%Y%m%d).tar.gz \
-C $(docker volume inspect n8n-setup_n8n_storage -f '{{.Mountpoint}}') . \
-C $(docker volume inspect n8n-setup_db_storage -f '{{.Mountpoint}}') .
# Restore database
docker-compose exec -T postgres psql -U n8n_user -d n8n < backup_file.sqlEdit docker-compose.yml to add resource limits:
n8n-worker:
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M| Issue | Solution |
|---|---|
| "Python 3 is missing" | Ensure N8N_RUNNERS_ENABLED=true and N8N_RUNNERS_MODE=external are set. Check that the n8n-runners container is running (docker-compose ps). |
| "NOAUTH Authentication required" | Verify the REDIS_PASSWORD in your .env file matches the password configured in the Redis service. Ensure there are no special characters causing issues. |
| Database connection failed | Check PostgreSQL logs: docker-compose logs postgres. Verify the POSTGRES_NON_ROOT_USER and POSTGRES_NON_ROOT_PASSWORD are correct and the user has privileges. |
| Port 5678 already in use | Change the host port in the n8n-main service ports mapping (e.g., - "8080:5678"). Find and stop the process using the port: netstat -ano | findstr :5678 (Windows). |
| Workflows not executing | Check worker status: docker-compose logs n8n-worker. Ensure Redis is healthy (docker-compose ps) and the EXECUTIONS_MODE=queue is set. |
| "Failed to start Python task runner" warning | This is normal if using external runners. It confirms the internal runner is disabled. Verify the external runner is connected: docker-compose logs n8n-runners | grep -i connected. |
| n8n-main or worker exits with code 1 | Almost always a configuration error. Check the logs for the specific service just before it crashed: docker-compose logs --tail=50 n8n-main. |
| Dependency failed to start: container ... is unhealthy | The health check for a service (Postgres/Redis) failed. Investigate that specific service's logs: docker-compose logs postgres. |
# Check the status and health of all containers
docker-compose ps
# View the last 50 lines of logs from all services
docker-compose logs --tail=50
# Follow logs in real-time (Ctrl+C to stop)
docker-compose logs -f
# Test PostgreSQL connection and responsiveness
docker-compose exec postgres pg_isready -U n8n_user -d n8n
# Test Redis connection and authentication
docker-compose exec redis redis-cli -a $REDIS_PASSWORD ping
# Check if the external Python runner connected successfully
docker-compose logs n8n-runners | grep -i "connected\|ready\|auth"
# Inspect the environment variables inside a running container
docker-compose exec n8n-main env | grep N8N_
# Check Docker volume usage and location
docker volume ls
docker volume inspect n8n-setup_n8n_storage- Full Restart: Often fixes transient network/startup issues.
docker-compose down
docker-compose up -d
docker-compose logs -f- Check Specific Service Logs: If one service is failing.
# Replace <service_name> with postgres, redis, n8n-main, etc.
docker-compose logs --tail=100 <service_name>- Verify Configuration: Ensure all .env variables are set and used correctly in docker-compose.yml.
# Compare your .env with the expected variables
cat .env- Access Container Shell: For deep inspection.
docker-compose exec n8n-main /bin/sh
# Inside container, you can check processes, installed packages, etc.| Metric | Value | Notes |
|---|---|---|
| Workers per GB RAM | 2-3 workers | 512MB per worker recommended |
| Queue throughput | ~100 tasks/sec | With 3 workers, Redis queue |
| Database connections | 50 concurrent | PostgreSQL with 100 max_connections |
| Startup time | 30-60 seconds | All services healthy |
| Python Runner Latency | < 100ms | Simple scripts on same network |
- Non-root database user configured
- Redis password authentication enabled
- n8n encryption key set (32+ chars)
- External runner auth token configured
- Container health checks implemented
- Volume persistence for data survival
- SSL/TLS encryption (add reverse proxy)
- Firewall rules (limit external access)
- Regular updates (monitor for CVEs)
# Quick start for testing
docker-compose up# Use specific versions (not 'latest')
sed -i 's/:latest/:2.0.2/g' docker-compose.yml
# Add reverse proxy (nginx/traefik)
# Enable SSL certificates
# Set up monitoring (Prometheus/Grafana)- AWS: ECS/EKS with RDS & ElastiCache
- GCP: Cloud Run with Cloud SQL & Memorystore
- Azure: Container Instances with Azure DB & Redis
# 1. Backup data
./scripts/backup.sh
# 2. Pull new images
docker-compose pull
# 3. Update with zero downtime
docker-compose up -d
# 4. Verify
docker-compose ps
docker-compose logs --tail=20 n8n-mainFound a bug? Have a feature request? Contributions are welcome!
- Fork the repository
- Create a feature branch (git checkout -b feature/amazing-feature)
- Commit changes (git commit -m 'Add amazing feature')
- Push to branch (git push origin feature/amazing-feature)
- Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
If this project helped you, please give it a β!
https://api.star-history.com/svg?repos=sedovdmitry/n8n-setup&type=Date
- n8n.io for the amazing workflow automation platform
- Docker community for containerization best practices
- All contributors who help improve this setup
-
GitHub Issues: Found a bug or have a feature request? Open an issue. Please include details like error logs and your configuration (remember to remove passwords!).
-
GitHub Discussions: Have a question, want to share your setup, or discuss best practices? Join the conversation in Discussions.
-
Official n8n Documentation: For in-depth questions about n8n features, nodes, and core concepts, the official docs are the best resource: docs.n8n.io.
-
Community & Support:
- n8n Community Forum: A great place to ask n8n-specific questions: community.n8n.io
- Stack Overflow: Use the
n8ntag for programming and configuration questions.
Debugging Tip: When seeking help, providing logs is crucial. Run docker-compose logs <service_name> and share the relevant error output.
Built with β€οΈ for the n8n community | π³ Docker | π Python | ποΈ PostgreSQL
Happy automating! Your workflows are in good containers.