The n8n Management Suite is a comprehensive, production-ready solution designed to automate the deployment and maintenance of self-hosted n8n workflow environments. This suite leverages a robust technology stack—including Docker, Nginx, and PostgreSQL 16—to provide enterprise-grade features such as automated SSL certificate management and a dedicated FastAPI-driven management console. Key functional areas include a sophisticated backup and disaster recovery system, multi-channel notifications via Apprise and NTFY, and optional public website hosting with isolated network security. Users can monitor system health through real-time performance dashboards and manage Docker containers directly via a web interface. The provided documentation offers extensive guidance on REST API integration, secure remote access through Tailscale or Cloudflare Tunnels, and detailed troubleshooting protocols. Overall, the system simplifies complex infrastructure tasks into an interactive setup process suitable for both personal automation and organizational deployments.
- 7. Dashboard
- 7. Backup Management
- 8. Notification System
- 9. System Notifications
-
- Container Management
-
- Workflow Management
-
- Public Website Management
-
- System Monitoring
-
- Settings
- 14. Daily Operations
- 15. SSL Certificate Management
- 16. Database Management
- 17. Container Maintenance
- 18. Backup Best Practices
- 19. Tailscale Integration
- 20. Cloudflare Tunnel
- 21. NFS Backup Storage
- 22. Custom Nginx Configuration
- 23. Environment Variables Reference
- Appendix A: DNS Provider Credential Setup
- Appendix B: Tailscale Auth Key Generation
- Appendix C: Cloudflare Tunnel Token Generation
- Appendix D: n8n API Key Generation
- API Reference - REST API documentation
- Backup Guide - Backup and restore procedures
- Certbot Guide - SSL certificate management with Let's Encrypt
- Cloudflare Guide - Cloudflare Tunnel setup and configuration
- Migration Guide - Upgrading from v2.0 to v3.0
- Notifications Guide - Alert and notification setup
- Tailscale Guide - Tailscale VPN integration
- Troubleshooting - Common issues and solutions
The n8n Management Suite is a comprehensive, production-ready deployment and management solution for self-hosted n8n workflow automation. It combines:
- Automated Deployment: A single interactive script that handles everything from Docker installation to SSL certificate acquisition
- Enterprise Software: PostgreSQL 16 with pgvector for AI/RAG workflows, Nginx reverse proxy with automatic HTTPS, and Let's Encrypt certificate management
- Management Console: A full-featured web application for monitoring, backup management, notifications, and system administration
- Disaster Recovery: Comprehensive backup system with verification, selective restoration, and bare-metal recovery capabilities
- Multi-Channel Notifications: Support for 30+ notification providers through Apprise, plus native NTFY push notifications
- Public Website Hosting: Optional static website hosting alongside your n8n instance with integrated File Browser management
Whether you are running n8n for personal automation or deploying it for an organization, this suite provides the infrastructure, monitoring, and management tools typically found only in expensive enterprise solutions.
- One-command interactive setup with automatic Docker installation
- Automatic SSL/TLS certificate acquisition and renewal via Let's Encrypt
- Certbot / Let's Encrypt support for multiple DNS providers (Cloudflare, AWS Route 53, Google Cloud DNS, DigitalOcean)
- PostgreSQL 16 with pgvector extension for AI vector embeddings
- Nginx reverse proxy with optimized configuration for n8n
- Optional Tailscale VPN and Cloudflare Tunnel integration
- Host a static website (www.yourdomain.com) alongside your n8n instance
- Security-first architecture with complete network isolation:
- Dedicated
nginx_publiccontainer serves only static files nginx_routerprovides hostname-based routing with no internal service access- Public website container has zero connectivity to n8n, database, or management services
- Dedicated
- Integrated File Browser for easy website content management via the Management Console
- Full backup and restore support for website files
- Automatic SSL certificate coverage via wildcard certificates
- Real-time system metrics dashboard (CPU, memory, disk, network)
- Docker container management (start, stop, restart, recreate, alerts, logs)
- Realtime web-based terminal access to any running container
- n8n workflow monitoring and control
- Comprehensive backup, alert and notifications settings management
- Dark/light theme support
- Scheduled and on-demand backups
- Multiple storage backends (local, NFS)
- Backup verification with integrity checking
- Selective workflow restoration - recover any workflow from any backup
- Full system bare-metal recovery
- Grandfather-Father-Son (GFS) retention policies
- Automatic pruning with space management
- 80+ notification providers via Apprise integration
- Native NTFY push notification support via ntfy.sh
- Optional locally hosted and integrated NFTY container
- Email notifications with customizable templates
- Webhook integration for notifications within n8n workflows
- System event notifications with configurable triggers
- L1/L2 escalation support
- Maintenance mode and quiet hours
- API for full notification support from n8n workflows
- Create notification 'groups' from any configured notification channel
flowchart TB
subgraph Internet["Internet"]
User["User Browser"]
Webhook["External Webhooks"]
end
subgraph Docker["Docker Environment"]
subgraph Proxy["Reverse Proxy Layer"]
Router["Nginx Router<br/>:443 HTTPS<br/>(hostname routing)"]
Nginx["Nginx Internal<br/>(n8n services)"]
end
subgraph Core["Core Services"]
N8N["n8n<br/>:5678"]
PG[("PostgreSQL 16<br/>with pgvector")]
end
subgraph Management["Management Layer"]
MGMT["Management Console<br/>/management"]
API["FastAPI Backend"]
end
subgraph PublicWeb["Public Website (Optional)"]
NginxPublic["Nginx Public<br/>(static files only)"]
FileBrowser["File Browser<br/>(content management)"]
end
subgraph Optional["Optional Services"]
NTFY["NTFY Server"]
Portainer["Portainer"]
Adminer["Adminer"]
Dozzle["Dozzle"]
Tailscale["Tailscale"]
end
subgraph SSL["Certificate Management"]
Certbot["Certbot"]
end
end
subgraph External["External Services"]
LE["Let's Encrypt"]
DNS["DNS Provider API"]
end
User --> Router
Webhook --> Router
Router -->|"n8n.domain.com"| Nginx
Router -->|"www.domain.com"| NginxPublic
Nginx --> N8N
Nginx --> MGMT
N8N --> PG
MGMT --> API
API --> PG
API --> N8N
API --> FileBrowser
Certbot --> LE
Certbot --> DNS
Security Note: When public website hosting is enabled, the
nginx_routercontainer handles hostname-based routing. Thenginx_publiccontainer serving www.yourdomain.com has no network access to internal services (n8n, PostgreSQL, Management Console). This isolation ensures that even if the public website were compromised, attackers cannot reach your workflow automation infrastructure.
| Component | Purpose |
|---|---|
| Nginx | Reverse proxy handling HTTPS termination, routing, and security headers |
| n8n | Workflow automation engine |
| PostgreSQL | Primary database with pgvector for AI/ML vector operations |
| Management Console | Web-based administration interface |
| FastAPI Backend | REST API powering the management console |
| Redis | Status caching for sub-50ms response times on system metrics |
| n8n_status | Continuous system metrics collector feeding Redis cache |
| Certbot | Optional Automatic SSL certificate acquisition and renewal |
| NTFY | Optional self-hosted push notification server |
| Portainer | Optional container management UI |
| Adminer | Optional database administration UI |
| Dozzle | Optional real-time log viewer |
| Tailscale | Optional VPN for secure remote access |
| Cloudflared | Optional Cloudflare Tunnel for external access without port forwarding |
| nginx_router | Optional hostname-based routing for public website isolation |
| nginx_public | Optional static file server for public website (network-isolated) |
| File Browser | Optional web-based file management for public website content |
| Technology | Version | Purpose |
|---|---|---|
| Python | 3.11+ | Management console backend |
| FastAPI | Latest | Async web framework for REST API |
| SQLAlchemy | 2.0 | Async ORM for database operations |
| PostgreSQL | 16 | Primary database |
| pgvector | Latest | Vector embeddings for AI/RAG |
| APScheduler | Latest | Task scheduling for backups |
| Bcrypt | Latest | Password hashing |
| Cryptography | Latest | AES-256 encryption |
| Technology | Version | Purpose |
|---|---|---|
| Vue.js | 3 | Frontend framework |
| Vite | Latest | Build tool |
| Pinia | Latest | State management |
| Vue Router | Latest | Client-side routing |
| Tailwind CSS | Latest | Styling framework |
| Chart.js | Latest | Metrics visualization |
| Axios | Latest | HTTP client |
| Technology | Purpose |
|---|---|
| Docker | Container runtime |
| Docker Compose | Container orchestration |
| Nginx | Reverse proxy and SSL termination |
| Certbot | Let's Encrypt certificate automation |
| Let's Encrypt | Free SSL/TLS certificates |
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 2 cores | 4+ cores |
| RAM | 4 GB | 8+ GB |
| Storage | 20 GB | 50+ GB SSD |
| Network | 10 Mbps | 100+ Mbps |
- Operating System: ~5 GB
- Docker Images: ~3 GB
- PostgreSQL Data: Varies with workflow complexity (plan 5-20 GB)
- Backups: Plan for 2-3x your database size
- n8n Data: Varies with execution history settings
Note: If using NFS for backup storage, local storage requirements for backups are reduced.
| Software | Notes |
|---|---|
| Docker | Automatically installed by setup.sh if not present |
| Docker Compose | V2 plugin preferred; automatically configured |
| curl | Required for setup script |
| OpenSSL | Required for key generation |
The setup script will automatically install these if not present:
- Docker Engine
- Docker Compose plugin
- Required Docker images
- curl
- OpenSSL
| Operating System | Versions | Notes |
|---|---|---|
| Ubuntu | 20.04, 22.04, 24.04 | Recommended |
| Debian | 11, 12 | Fully supported |
| CentOS | 8, 9 | Stream versions |
| RHEL | 8, 9 | Enterprise Linux |
| Fedora | 38+ | Latest releases |
| Rocky Linux | 8, 9 | RHEL-compatible |
| AlmaLinux | 8, 9 | RHEL-compatible |
| macOS | 10.15+ | Requires Docker Desktop |
| Windows | 10/11 | Via WSL2 with Docker Desktop |
| Environment | Support Level | Notes |
|---|---|---|
| Proxmox LXC | Supported | Requires nesting=1 and lxc.apparmor.profile: unconfined |
| WSL2 | Supported | Requires Docker Desktop for Windows |
| Virtual Machines | Supported | Any hypervisor (Proxmox, VMware, VirtualBox, Hyper-V, KVM) |
- Port 443 must be accessible from the internet for webhook functionality
- Consider using Tailscale or Cloudflare Tunnel for secure remote access
SSL certificate acquisition requires API access to your DNS provider for DNS-01 challenge validation. The following providers are supported:
| Provider | Required Credentials | Recommended |
|---|---|---|
| Cloudflare | API Token with Zone:DNS:Edit permission | Yes |
| AWS Route 53 | Access Key ID + Secret Access Key | Yes |
| Google Cloud DNS | Service Account JSON key | Yes |
| DigitalOcean | API Token with read/write access | Yes |
| Manual | None (requires manual DNS record creation) | No |
Recommendation: Cloudflare is recommended due to fast DNS propagation (60 seconds) and straightforward API token creation.
Before running the setup script, gather the following information:
| Item | Description | Where to Get It |
|---|---|---|
| Domain Name | The domain for your n8n instance (e.g., n8n.example.com) |
Your domain registrar |
| DNS Provider Credentials | API credentials for your DNS provider | See Appendix A |
| Email Address | For Let's Encrypt certificate notifications | Your email |
| Admin Password | Password for the management console (min 8 characters) | Create a strong password |
| Item | Description | When Needed |
|---|---|---|
| Tailscale Auth Key | Pre-authenticated key for Tailscale VPN | If using Tailscale for secure access |
| Cloudflare Tunnel Token | Token for Cloudflare Zero Trust tunnel | If using Cloudflare Tunnel |
| NFS Server Details | Server address and export path | If using NFS for backup storage |
The setup script now automatically handles system preparation for you:
- OS Auto-Detection: Detects your operating system (Ubuntu, Debian, CentOS, RHEL, Rocky, AlmaLinux, Fedora, openSUSE, Arch Linux, Alpine)
- Package Manager Detection: Automatically uses the correct package manager (apt, dnf, yum, zypper, pacman, apk)
- System Updates: Optionally updates your system packages
- Utility Installation: Installs required utilities (curl, git, openssl, jq) if missing
- Privilege Handling: Uses sudo only when necessary (not when running as root)
When you run ./setup.sh, you'll see:
┌─────────────────────────────────────────────────────────────────────────────┐
│ System Preparation │
└─────────────────────────────────────────────────────────────────────────────┘
ℹ Detected OS: Ubuntu 22.04 (debian family)
ℹ Package Manager: apt
Would you like to update system packages? [Y/n]: y
Updating system packages...
✓ System packages updated successfully
Checking required utilities...
✓ curl is installed
✓ git is installed
✓ openssl is installed
✓ jq is installed
✓ System preparation complete
Note: The script will automatically check for system updates and apply them as part of the setup!
Ensure your domain points to your server's IP address:
- Log in to your DNS provider's control panel
- Create an A record pointing your domain to your server's public IP
- Wait for DNS propagation (typically 5-30 minutes)
Verify DNS resolution:
# Check if domain resolves to your server
dig +short n8n.yourdomain.com
# Or using nslookup
nslookup n8n.yourdomain.comBefore configuring DNS, it's important to understand the two main approaches for exposing your n8n instance to the internet:
┌─────────────────────────────────────────────────────────────────────────────┐
│ TRADITIONAL PORT FORWARDING │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Internet Users │
│ │ │
│ ▼ │
│ n8n.yourdomain.com ──────► A Record: 203.0.113.50 │
│ │ (Your public IP) │
│ ▼ │
│ Your Router (Port 443) ──► Port Forward to Server │
│ │ │
│ ▼ │
│ Your Server (Nginx:443) ──► n8n Container │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ ✓ Direct connection - lowest latency │
│ ✓ Full control over your infrastructure │
│ ✗ Requires static IP or DDNS │
│ ✗ Port 443 must be open in firewall/router │
│ ✗ Your server's IP is exposed to the internet │
└─────────────────────────────────────────────────────────────────────────────┘
DNS Configuration for Port Forwarding:
- Create an A Record pointing to your server's public IP address
- Open port 443 on your router/firewall
- The domain should resolve to your server's public IP
┌─────────────────────────────────────────────────────────────────────────────┐
│ CLOUDFLARE TUNNEL │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Internet Users │
│ │ │
│ ▼ │
│ n8n.yourdomain.com ──────► CNAME: xxxxx.cfargotunnel.com │
│ │ (Cloudflare Tunnel endpoint) │
│ ▼ │
│ Cloudflare Edge Network │
│ │ DDoS Protection, WAF, Caching │
│ ▼ │
│ ═══════ Encrypted Tunnel ═══════ │
│ │ (Outbound connection from your server) │
│ ▼ │
│ cloudflared Container ──► Nginx ──► n8n Container │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ ✓ NO open ports required - server initiates outbound connection │
│ ✓ Your server IP is HIDDEN from the internet │
│ ✓ Built-in DDoS protection and WAF │
│ ✓ Works behind CGNAT or dynamic IPs │
│ ✓ Zero Trust access policies available │
│ ✗ Slightly higher latency (traffic routes through Cloudflare) │
│ ✗ Requires Cloudflare account and domain on Cloudflare │
└─────────────────────────────────────────────────────────────────────────────┘
DNS Configuration for Cloudflare Tunnel:
- Domain DNS must be managed by Cloudflare
- Tunnel automatically creates CNAME records pointing to your tunnel
- No A record needed - DNS points to Cloudflare, not your server
- The domain will NOT resolve to your server's IP (this is expected!)
| Factor | Port Forwarding | Cloudflare Tunnel |
|---|---|---|
| Home/Residential Network | Challenging (CGNAT, dynamic IP) | ✓ Recommended |
| Business/Static IP | ✓ Works well | ✓ Works well |
| Security Priority | Good with proper firewall | ✓ Better (hidden IP) |
| Latency Sensitive | ✓ Lower latency | Slightly higher |
| Complex Firewall/NAT | May need port forwarding | ✓ No config needed |
| Multi-site Deployment | Complex | ✓ Easy |
During setup, the script will ask early on:
┌─────────────────────────────────────────────────────────────────────────────┐
│ Connectivity Method │
└─────────────────────────────────────────────────────────────────────────────┘
How will users access your n8n instance?
1) Port Forwarding / Direct Access
Your domain's A record points directly to your server's public IP.
Port 443 must be accessible from the internet.
2) Cloudflare Tunnel
No open ports required. Cloudflare Tunnel creates a secure outbound
connection. Your domain must use Cloudflare DNS.
Enter your choice [1-2]:
If you choose Cloudflare Tunnel, the setup script will:
- Validate that your domain resolves to your server's INTERNAL IP (e.g., 192.168.x.x)
- Show a warning if the domain IP doesn't match any local IP on this server
- The cloudflared daemon uses this internal IP as its routing endpoint
- Prompt for your Cloudflare Tunnel token
- Configure the cloudflared container automatically
If you choose Port Forwarding, the setup script will:
- Skip IP validation (no automatic check)
- Perform an nslookup on your domain and display the resolved IP
- Inform you that this IP should be the EXTERNAL IP on your firewall
- Tell you to forward port 443 to this server's internal IP (where n8n is installed)
- Configure direct SSL termination via Nginx
The fastest way to get started is using the one-line installer:
curl -fsSL https://raw.githubusercontent.com/rjsears/n8n_nginx/main/install.sh | bashThis will:
- Check for and install
gitif needed - Clone the repository
- Automatically launch the setup wizard
Testing a specific branch: Use the
BRANCHenvironment variable:curl -fsSL https://raw.githubusercontent.com/rjsears/n8n_nginx/main/install.sh | BRANCH=dev bash
If you prefer to clone manually:
# Clone the repository
git clone https://github.com/rjsears/n8n_nginx.git
# Navigate to the directory
cd n8n_nginx
# Make setup script executable and run it
chmod +x setup.sh
./setup.shThe setup script supports two installation methods: Interactive Setup (guided wizard) and Unattended Installation (pre-configured).
For automated deployments, you can use a pre-configuration file to skip the interactive prompts:
cp setup-config.example setup-configEdit setup-config with your values. Key settings include:
# Required
DOMAIN=n8n.example.com
SSL_METHOD=certbot # certbot, existing, or none
LETSENCRYPT_EMAIL=admin@example.com
DNS_PROVIDER=cloudflare
CLOUDFLARE_API_TOKEN=your-api-token
# Auto-generated if left blank
POSTGRES_PASSWORD=
N8N_ENCRYPTION_KEY=
MGMT_SECRET_KEY=
# Optional - Tailscale (auto-enables when key provided)
TAILSCALE_AUTH_KEY=tskey-auth-xxxxx
# Optional - Cloudflare Tunnel (auto-enables when token provided)
CLOUDFLARE_TUNNEL_TOKEN=
# Fully unattended mode
AUTO_CONFIRM=true./setup.sh --config setup-config- Credentials: If
POSTGRES_PASSWORD,N8N_ENCRYPTION_KEY, orADMIN_PASSare left blank, secure random values are auto-generated and displayed at the end of setup - Service Enablement: Tailscale and Cloudflare Tunnel are automatically enabled when their auth keys/tokens are provided
- Validation: The script validates all settings (domain format, DNS credentials, NFS connectivity) and prompts for corrections if needed (unless
AUTO_CONFIRM=true)
See setup-config.example for all available options including:
- Storage settings (local, NFS)
- Compression settings
- Retention policies
- Optional services (Adminer, Dozzle, Portainer)
- Access control (IP whitelisting)
╔═══════════════════════════════════════════════════════════════════════════╗
║ n8n HTTPS Interactive Setup v3.0.0 ║
╚═══════════════════════════════════════════════════════════════════════════╝
This script will guide you through setting up a production-ready
n8n instance with HTTPS, PostgreSQL, and optional automatic SSL
configuration and renewal.
Features:
- Automated SSL certificates via Let's Encrypt
- DNS-01 challenge (no port 80/443 exposure needed)
- PostgreSQL 16 with pgvector for AI/RAG workflows
- Nginx reverse proxy with security headers
- Automatic certificate renewal every 12 hours
Ready to begin? [Y/n]:
If you run the script as root (common for server administrators), you'll see a note:
╔═══════════════════════════════════════════════════════════════════════════╗
║ n8n HTTPS Interactive Setup v3.0.0 ║
╚═══════════════════════════════════════════════════════════════════════════╝
╔═══════════════════════════════════════════════════════════════════════════╗
║ NOTE ║
║ You are running this script as root. While this will work, it's ║
║ recommended to run as a regular user (the script uses sudo internally). ║
╚═══════════════════════════════════════════════════════════════════════════╝
Continue as root? [Y/n]: y
The script intelligently handles different execution contexts:
| Scenario | sudo for commands | Docker group prompt |
|---|---|---|
| Running as root | Not needed | Skipped |
Running via sudo ./setup.sh |
Not needed | Offered (for real user) |
| Running as regular user | Used when needed | Offered |
The script checks if Docker and Docker Compose are installed. If not, it offers to install them automatically.
When running as a regular user:
┌─────────────────────────────────────────────────────────────────────────────┐
│ Docker Environment Check │
└─────────────────────────────────────────────────────────────────────────────┘
✓ Docker is installed (version: 24.0.7)
✓ Docker daemon is running
✓ Docker Compose is available (version: 2.21.0)
When running as root:
┌─────────────────────────────────────────────────────────────────────────────┐
│ Docker Environment Check │
└─────────────────────────────────────────────────────────────────────────────┘
✓ Docker is installed (version: 24.0.7)
✓ Docker daemon is running
✓ Docker Compose is available (version: 2.21.0)
✓ Running as root - no sudo required for Docker commands
If Docker is not installed (regular user):
⚠ Docker is not installed
Would you like to install Docker? [Y/n]: y
───────────────────────────────────────────────────────────────────────────────
Installing Docker and Docker Compose...
ℹ Detected ubuntu 22.04
ℹ Updating package index...
ℹ Installing prerequisites...
ℹ Adding Docker GPG key...
ℹ Adding Docker repository...
ℹ Installing Docker Engine and Docker Compose...
✓ Docker and Docker Compose installed successfully!
ℹ Verifying installation...
✓ Docker is working correctly
Would you like to add your user to the docker group? (recommended) [Y/n]: y
✓ User added to docker group
⚠ You will need to log out and back in for this to take effect
If Docker is not installed (as root):
⚠ Docker is not installed
Would you like to install Docker? [Y/n]: y
───────────────────────────────────────────────────────────────────────────────
Installing Docker and Docker Compose...
ℹ Detected ubuntu 22.04
ℹ Updating package index...
ℹ Installing prerequisites...
ℹ Adding Docker GPG key...
ℹ Adding Docker repository...
ℹ Installing Docker Engine and Docker Compose...
✓ Docker and Docker Compose installed successfully!
ℹ Verifying installation...
✓ Docker is working correctly
✓ Running as root - no docker group membership needed
On macOS (with Homebrew):
┌─────────────────────────────────────────────────────────────────────────────┐
│ Docker Environment Check │
└─────────────────────────────────────────────────────────────────────────────┘
⚠ Docker is not installed
Would you like to install Docker? [Y/n]: y
───────────────────────────────────────────────────────────────────────────────
Installing Docker and Docker Compose...
ℹ Detected macOS
ℹ Homebrew detected
Install Docker Desktop using Homebrew? [Y/n]: y
ℹ Installing Docker Desktop via Homebrew...
✓ Docker Desktop installed!
IMPORTANT: You need to start Docker Desktop manually:
1. Open Docker from Applications folder
2. Complete the Docker Desktop setup wizard
3. Wait for Docker to start (whale icon in menu bar)
4. Run this script again
Have you started Docker Desktop and it's running? [y/N]: y
✓ Docker is running!
On WSL2:
┌─────────────────────────────────────────────────────────────────────────────┐
│ Docker Environment Check │
└─────────────────────────────────────────────────────────────────────────────┘
⚠ Docker is not installed
Would you like to install Docker? [Y/n]: y
───────────────────────────────────────────────────────────────────────────────
Installing Docker and Docker Compose...
ℹ Detected WSL (Windows Subsystem for Linux)
You have two options for Docker in WSL:
Option 1: Docker Desktop for Windows (recommended):
1. Download Docker Desktop from: https://www.docker.com/products/docker-desktop/
2. Install and enable 'Use WSL 2 based engine' in settings
3. Enable integration with your WSL distro in Settings > Resources > WSL Integration
4. Run this script again
Option 2: Native Docker in WSL2:
Install Docker directly in your WSL distro (requires WSL2)
Would you like to install Docker natively in WSL2? [y/N]: y
ℹ Installing Docker natively in WSL...
ℹ Detected ubuntu 22.04 in WSL
ℹ Updating package index...
ℹ Installing prerequisites...
ℹ Adding Docker GPG key...
ℹ Adding Docker repository...
ℹ Installing Docker Engine and Docker Compose...
ℹ Starting Docker daemon...
✓ Docker and Docker Compose installed successfully!
⚠ Note: You may need to start Docker manually after WSL restarts:
sudo service docker start
┌─────────────────────────────────────────────────────────────────────────────┐
│ System Requirements Check │
└─────────────────────────────────────────────────────────────────────────────┘
✓ Disk space: 45GB available (5GB required)
✓ Memory: 4GB total (2GB required)
✓ Port 443 is available
✓ OpenSSL is available
✓ curl is available
✓ Internet connectivity OK
┌─────────────────────────────────────────────────────────────────────────────┐
│ DNS Provider Configuration │
└─────────────────────────────────────────────────────────────────────────────┘
Let's Encrypt uses DNS validation to issue SSL certificates.
This requires API access to your DNS provider.
Select your DNS provider:
1) Cloudflare
2) AWS Route 53
3) Google Cloud DNS
4) DigitalOcean
5) Other (manual configuration)
Enter your choice [1-5]: 1
───────────────────────────────────────────────────────────────────────────────
Cloudflare API Configuration
You need a Cloudflare API token with the following permissions:
- Zone:DNS:Edit (for your domain's zone)
Create one at: https://dash.cloudflare.com/profile/api-tokens
Enter your Cloudflare API token [hidden]:
✓ Cloudflare credentials saved to cloudflare.ini
The script validates your domain and checks if it resolves to your server:
┌─────────────────────────────────────────────────────────────────────────────┐
│ Domain Configuration │
└─────────────────────────────────────────────────────────────────────────────┘
Enter the fully qualified domain name where n8n will be accessible.
Example: n8n.yourdomain.com
Enter your n8n domain [n8n.example.com]: n8n.mycompany.com
───────────────────────────────────────────────────────────────────────────────
Validating domain configuration...
ℹ Resolving n8n.mycompany.com...
✓ Domain resolves to: 192.168.113.50
✓ Domain IP matches this server
ℹ Testing connectivity to 192.168.113.50...
✓ Host 192.168.113.50 is reachable
If domain doesn't match server IP:
⚠ Domain IP (198.51.100.25) does not match any local IP
Local IP addresses on this machine:
- 192.168.113.50
- 10.0.0.5
IMPORTANT:
The domain n8n.mycompany.com points to 198.51.100.25
but this server's IPs are different.
This will cause the n8n stack to fail because:
- SSL certificate validation will fail
- Webhooks won't reach this server
- The n8n UI won't be accessible
╔═══════════════════════════════════════════════════════════════════════════╗
║ WARNING ║
║ The domain validation found issues that may prevent n8n from working. ║
║ Please ensure your DNS is properly configured before continuing. ║
╚═══════════════════════════════════════════════════════════════════════════╝
Do you understand the risks and want to continue? [y/N]:
How your domain should be configured depends on how external traffic reaches your n8n server:
Option 1: Cloudflare Tunnel
If you're using Cloudflare Tunnel, your domain MUST resolve to the INTERNAL IP address of your server (an RFC1918 private IP like 192.168.x.x, 10.x.x.x, or 172.16-31.x.x).
┌─────────────────────────────────────────────────────────────────────────────┐
│ CLOUDFLARE TUNNEL - DNS Configuration │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ n8n.yourdomain.com ──► Local host Record/Internal DNS Sever: 192.168.113.50 │
│ (Your server's INTERNAL IP) │
│ │
│ Why Internal IP? │
│ The cloudflared daemon performs a LOCAL host lookup for your domain │
│ and uses that IP (192.168.113.50) as the routing endpoint. │
│ │
│ Example: host n8n.mycompany.com → 192.168.113.50 │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Setup Script Behavior for Cloudflare Tunnel:
- Validates that your domain resolves to your server's INTERNAL IP
- The cloudflared daemon performs a local host lookup for your domain
- This internal IP is used as the tunnel's routing endpoint
- Prompts for your Cloudflare Tunnel token
- Configures the cloudflared container automatically
Option 2: Port Forwarding (No Cloudflare Tunnel)
If you're NOT using Cloudflare Tunnel and are instead using traditional port forwarding through your router/firewall, your domain should resolve to your EXTERNAL (public) IP address.
┌─────────────────────────────────────────────────────────────────────────────┐
│ PORT FORWARDING - DNS Configuration │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ n8n.yourdomain.com ──────► A Record: 203.0.113.1 │
│ (Your firewall's EXTERNAL/PUBLIC IP) │
│ │
│ Your firewall/router must forward port 443 to your server: │
│ External:443 ──────► Internal Server: 192.168.113.50:443 │
│ │
│ Example: n8n.mycompany.com → A → 203.0.113.1 (public IP) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Setup Script Behavior for Port Forwarding:
- Skips IP validation (no automatic check)
- Performs an nslookup on your domain and displays the resolved IP
- Informs you that this IP should be the EXTERNAL IP on your firewall
- Tells you to forward port 443 to your server's internal IP (where n8n is installed)
- Example: If your server's internal IP is 192.168.50.50, port 443 on your firewall should forward to 192.168.50.50:443
Important Notes:
- SSL certificates are required for both methods - n8n requires HTTPS for webhooks and CORS compliance
- Both methods use DNS-01 challenge for Let's Encrypt (no port 80 exposure needed)
┌─────────────────────────────────────────────────────────────────────────────┐
│ PostgreSQL Database Configuration │
└─────────────────────────────────────────────────────────────────────────────┘
Configure your PostgreSQL database settings.
These credentials will be used by n8n to store data.
Database name [n8n]:
Database username [n8n]:
Enter a strong password for the database.
Leave blank to auto-generate a secure password.
Database password [hidden]:
✓ Generated secure database password
✓ pgvector extension automatically created
┌─────────────────────────────────────────────────────────────────────────────┐
│ Container Names Configuration │
└─────────────────────────────────────────────────────────────────────────────┘
The following default container names will be used:
PostgreSQL: n8n_postgres
n8n: n8n
Nginx: n8n_nginx
Certbot: n8n_certbot
Would you like to customize these names? [y/N]: n
✓ Container names configured
┌─────────────────────────────────────────────────────────────────────────────┐
│ Let's Encrypt Email Configuration │
└─────────────────────────────────────────────────────────────────────────────┘
Let's Encrypt requires an email address for:
- Certificate expiration notifications
- Account recovery
Email address for Let's Encrypt [admin@mycompany.com]:
┌─────────────────────────────────────────────────────────────────────────────┐
│ Timezone Configuration │
└─────────────────────────────────────────────────────────────────────────────┘
Detected system timezone: America/New_York
Use America/New_York as the timezone for n8n? [Y/n]:
✓ Timezone set to: America/New_York
┌─────────────────────────────────────────────────────────────────────────────┐
│ Encryption Key Configuration │
└─────────────────────────────────────────────────────────────────────────────┘
n8n uses an encryption key to secure credentials stored in the database.
This key should be kept secret and backed up securely.
✓ Generated secure encryption key using OpenSSL
⚠ IMPORTANT: Save your encryption key in a secure location!
If you lose this key, you will not be able to decrypt stored credentials.
┌─────────────────────────────────────────────────────────────────────────────┐
│ Portainer Agent Configuration │
└─────────────────────────────────────────────────────────────────────────────┘
Portainer is a popular container management UI.
If you're running Portainer on another server, you can install
the Portainer Agent here to manage this n8n stack remotely.
Are you using Portainer to manage your containers? [y/N]: y
✓ Portainer Agent will be included in docker-compose.yaml
The agent will be accessible on port 9001.
Add this server to Portainer using: <this-server-ip>:9001
┌─────────────────────────────────────────────────────────────────────────────┐
│ Configuration Summary │
└─────────────────────────────────────────────────────────────────────────────┘
Domain & URL:
Domain: n8n.mycompany.com
URL: https://n8n.mycompany.com
DNS Provider:
Provider: cloudflare
Credentials file: cloudflare.ini
Database:
Name: n8n
User: n8n
Password: [configured]
Container Names:
PostgreSQL: n8n_postgres
n8n: n8n
Nginx: n8n_nginx
Certbot: n8n_certbot
Other Settings:
Email: admin@mycompany.com
Timezone: America/New_York
Encryption key: [configured]
Portainer Agent: enabled
───────────────────────────────────────────────────────────────────────────────
Is this configuration correct? [Y/n]:
┌─────────────────────────────────────────────────────────────────────────────┐
│ Generating Configuration Files │
└─────────────────────────────────────────────────────────────────────────────┘
[1/4] Generating docker-compose.yaml
✓ docker-compose.yaml generated
[2/4] Generating nginx.conf
✓ nginx.conf generated
[3/4] Saving configuration backup
✓ Configuration saved to /home/user/n8n_nginx/.n8n_setup_config
[4/4] Creating Let's Encrypt Docker volume
✓ Volume 'letsencrypt' created
✓ All configuration files generated successfully!
Would you like to deploy the stack now? [Y/n]: y
┌─────────────────────────────────────────────────────────────────────────────┐
│ Deploying n8n Stack │
└─────────────────────────────────────────────────────────────────────────────┘
[1/6] Starting PostgreSQL database
Waiting for PostgreSQL to be ready...
✓ PostgreSQL is running and healthy
[2/6] Obtaining SSL certificate from Let's Encrypt
Domain: n8n.mycompany.com
This uses DNS-01 challenge (no ports 80/443 exposure required)
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for n8n.mycompany.com
Waiting 60 seconds for DNS propagation
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/n8n.mycompany.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/n8n.mycompany.com/privkey.pem
✓ SSL certificate obtained successfully!
[3/6] Copying certificates to Docker volume
✓ Certificates copied to Docker volume
[4/6] Starting all services
Waiting for services to start...
✓ All services started
[5/6] Verifying services
Checking PostgreSQL...
✓ PostgreSQL is responding
✓ PostgreSQL authentication successful
Checking n8n...
✓ n8n is responding
Checking Nginx...
✓ Nginx configuration is valid
Container Status:
NAMES STATUS PORTS
n8n_postgres Up 2 minutes (healthy)
n8n Up About a minute
n8n_nginx Up About a minute 0.0.0.0:443->443/tcp
n8n_certbot Up About a minute
[6/6] Testing SSL certificate and connectivity
Testing HTTPS connectivity to https://n8n.mycompany.com...
✓ SSL certificate is valid
notBefore=Nov 29 00:00:00 2025 GMT
notAfter=Feb 27 23:59:59 2026 GMT
✓ n8n is accessible via HTTPS
✓ All connectivity tests passed!
╔═══════════════════════════════════════════════════════════════════════════╗
║ Setup Complete! ║
╚═══════════════════════════════════════════════════════════════════════════╝
Your n8n instance is now running!
Access your n8n instance:
https://n8n.mycompany.com
Useful Commands:
View logs: docker compose logs -f
View n8n logs: docker compose logs -f n8n
Stop services: docker compose down
Start services: docker compose up -d
Restart services: docker compose restart
View status: docker compose ps
Important Files:
Docker Compose: /home/user/n8n_nginx/docker-compose.yaml
Nginx Config: /home/user/n8n_nginx/nginx.conf
DNS Credentials: /home/user/n8n_nginx/cloudflare.ini
Setup Config: /home/user/n8n_nginx/.n8n_setup_config
Security Reminders:
- Create your n8n owner account immediately
- Back up your encryption key securely
- Keep your DNS credentials file secure (chmod 600)
- SSL certificates auto-renew every 12 hours
───────────────────────────────────────────────────────────────────────────────
Thank you for using n8n Management Setup Script v3.0.0
Created by Richard J. Sears - richard@n8nmanagement.net
After installation is complete, you need to perform initial configuration of both n8n and the management console.
- Open your browser and navigate to
https://n8n.your-domain.com - You will see the n8n setup page
- Create your owner account:
- Enter your email address
- Create a password
- Enter your first and last name
- Click Next to complete setup
[Screenshot placeholder: n8n initial setup - owner account creation]
After creating your account, you will be taken to the n8n editor. Before proceeding, note the following:
- Your n8n instance is now accessible at
https://n8n.your-domain.com - Webhooks are accessible at
https://n8n.your-domain.com/webhook/ - The editor is fully functional and ready for workflow creation
- Navigate to
https://n8n.your-domain.com/management - Enter the admin credentials you created during setup
- Click Login
[Screenshot placeholder: Management console login screen]
After logging in, you will see the following options:
- Dashboard: View CPU, memory, disk usage, basic system overview
- Backups: Configure and manage system and n8n backups
- Notifications: Configure, create and manage notification channels and optionally expose them to n8n
- Containers: View and manage all system containers
- Flows: Backup, activate, deactivate and download flows from n8n
- System: View system health, network information and gain container terminal access
- Settings: Configure various system, security, access control, appearance, n8n API and debug settings
[Screenshot placeholder: Dashboard overview with all widgets]
The management console communicates with n8n through its REST API. You need to configure this connection for full functionality.
- In n8n, click your profile icon (bottom left)
- Select Settings
- Navigate to API in the left sidebar
- Click Create an API key
- Give it a name (e.g., "Management Console")
- Copy the generated API key
[Screenshot placeholder: n8n Settings > API > Create API key]
Important: The API key is shown only once. Copy it immediately.
- In the management console, go to Settings
- Click the API tab
- Paste your n8n API key
- Click Save
[Screenshot placeholder: Settings > API tab with API key field]
- Click Test Connection
- You should see a success message
- If the test fails, verify:
- The API key is correct
- n8n is running (
docker compose ps) - Network connectivity between containers
API Connection Test
-------------------
Status: Connected
n8n Version: 1.xx.x
Workflows: 0
Active Workflows: 0
To verify everything is working correctly, you can deploy the test workflows.
You can use these later to test your webhook enabled notifications.
The management console can deploy sample workflows to verify:
- Webhook functionality
- n8n execution
- API connectivity
- Go to Flows in the management console
- Click Deploy Test Workflow
- The system will:
- Create a simple webhook workflow
- Activate the workflow
- Test the webhook endpoint
- Verify the response
- Check the results
Test Workflow Deployment
------------------------
Workflow Created: Yes
Workflow Activated: Yes
Webhook Test: Passed
Response Time: 45ms
Status: All tests passed
[Screenshot placeholder: Test workflow verification results]
The management console supports IP-based access control to restrict who can access the administrative interface.
By default, the management console is accessible from common internal IP ranges:
10.0.0.0/8(Private Class A)172.16.0.0/12(Private Class B)192.168.0.0/16(Private Class C)100.64.0.0/10(Carrier-grade NAT / Tailscale)
- Go to Settings > Security
- In the Allowed Subnets section, click Add
- Enter the CIDR notation for the allowed range
- Add a description
- Click Save
| Example | CIDR | Description |
|---|---|---|
| Single IP | 203.0.113.50/32 |
Your office IP |
| Small network | 203.0.113.0/24 |
Office network |
| Tailscale | 100.64.0.0/10 |
Tailscale network |
[Screenshot placeholder: Settings > Security > Allowed Subnets]
If you enabled Tailscale during setup, your management console is automatically accessible via your Tailscale network:
- Tailscale assigns IPs in the
100.64.0.0/10range - This range is allowed by default
- Access the console using the Tailscale IP or MagicDNS name
# Find your Tailscale IP
tailscale ip
# Access via Tailscale
https://your-machine.tailnet-name.ts.net/managementThe dashboard provides an at-a-glance overview of your system's health and status.
[Screenshot placeholder: Complete dashboard with all widgets]
| Component | Description |
|---|---|
| System Overview | Real-time CPU, memory, and disk usage with graphs, host uptime |
| Container Status | Health status of all Docker containers |
| Network I/O | Current I/O of the n8n_management container nic |
| Download History | One hour download network history |
| Upload History | One hour upload network history |
The metrics panel displays:
- CPU Usage: Current and historical CPU utilization
- Memory Usage: RAM usage with available/total
- Disk Usage: Storage utilization for each mount point
- Uptime: This is the uptime of the container host
Quick view of all containers:
- Green indicator: Running and healthy
- Yellow indicator: Running but unhealthy
- Red indicator: Stopped or exited
- Gray indicator: Unknown status
Click any container metric to navigate to the Containers page for details.
The backup system provides comprehensive data protection for your n8n instance.
flowchart LR
subgraph Trigger["Backup Triggers"]
Manual["Manual Trigger"]
Schedule["Scheduled Job"]
end
subgraph Process["Backup Process"]
PGDump["PostgreSQL Dump<br/>(pg_dump)"]
Config["Configuration Files"]
Certs["SSL Certificates"]
Meta["Workflow Metadata<br/>Extraction"]
end
subgraph Storage["Storage"]
Local["Local Storage<br/>/app/backups"]
NFS["NFS Mount<br/>(optional)"]
end
subgraph Verify["Verification"]
Archive["Archive Integrity"]
DBValid["Database Validation"]
Checksum["SHA-256 Checksums"]
end
Manual --> Process
Schedule --> Process
PGDump --> Storage
Config --> Storage
Certs --> Storage
Meta --> Storage
Storage --> Verify
| Component | Contents | Format |
|---|---|---|
| PostgreSQL Database | All n8n data (workflows, credentials, executions) | pg_dump custom format |
| Configuration Files | .env, docker-compose.yaml, nginx.conf | Original files |
| SSL Certificates | Let's Encrypt certificates | Certificate files |
| Workflow Metadata | Extracted workflow details for browsing | JSON manifest |
| Option | Location | Use Case |
|---|---|---|
| Local | /app/backups (Docker volume) |
Single-server deployments |
| NFS | Network mount point | Off-site backup storage |
The Backup History page displays all backups with their status and details.
[Screenshot placeholder: Backup history table with multiple entries]
| Status | Meaning |
|---|---|
| Completed | Backup finished successfully |
| In Progress | Backup currently running |
| Failed | Backup encountered an error |
| Verified | Backup passed verification |
| Protected | Backup protected from automatic deletion |
Click any backup to view its contents without restoring:
-
Workflows Tab: List of all workflows in the backup
- Workflow name and ID
- Active/inactive status
- Node count
- Created/updated dates
-
Credentials Tab: Credential types (no sensitive data shown)
- Credential name
- Type (e.g., OAuth2, API Key)
- Associated workflows
-
Configuration Tab: Configuration files included
- File name and path
- File size
- Checksum
[Screenshot placeholder: Backup contents dialog showing workflows]
To prevent automatic deletion of important backups:
- Click the backup row
- Click Protect
- The backup will be excluded from retention policies
Protected backups show a shield icon in the list.
- Navigate to Backups
- Click Create Backup
- Select backup options:
- Backup Type: Full or n8n database only
- Compression: gzip, zstd, or none
- Verify after backup: Toggle to automatically verify backup integrity after completion
- Click Start Backup
When Verify after backup is enabled:
- The backup completes normally
- Verification automatically starts
- Archive integrity and database validation are performed
- Results are shown in the progress modal
This is recommended for critical backups where you want immediate confirmation of backup validity.
[Screenshot placeholder: Create backup dialog with options]
A progress modal shows:
- Current step (e.g., "Dumping database")
- Progress percentage
- Elapsed time
- Log output
[Screenshot placeholder: Backup progress with percentage and logs]
- Go to Backups and click Configure
- Select the Schedule tab
- Configure:
- Enable Scheduled Backups: Toggle on
- Frequency: Hourly, Daily, Weekly, or Monthly
- Time: When to run (for daily/weekly/monthly)
- Day: Which day (for weekly/monthly)
- Click Save Changes
[Screenshot placeholder: Backup schedule creation form]
| Frequency | Description | Typical Use |
|---|---|---|
| Hourly | Every hour | High-change environments |
| Daily | Once per day at specified time | Standard production |
| Weekly | Once per week on specified day | Long-term archives |
| Monthly | Once per month on specified day | Compliance archives |
Verification ensures backups are valid and can be restored.
The verification process:
- Archive Integrity: Tests that the backup archive is not corrupted
- Database Validation: Runs
pg_restore --listto validate the dump - Checksum Verification: Compares SHA-256 checksums
- Manifest Validation: Verifies all expected files are present
- In Backup History, click a backup
- Click Verify
- Wait for verification to complete
- Review the verification report
Verification Report
-------------------
Archive Integrity: Passed
Database Validation: Passed
Checksum Match: Passed
Files Verified: 15/15
Status: Backup is valid and restorable
[Screenshot placeholder: Verification report dialog]
Configure automatic verification to run after backups complete:
- Go to Backups and click Configure
- Select the Verification tab
- Enable Auto-Verification
- Choose verification frequency:
- Every backup (frequency = 1): Verify every backup immediately
- Every 3rd, 5th, or 10th: Verify periodically to balance thoroughness and performance
- Custom frequency: Enter any number from 1-100
| Frequency | Use Case |
|---|---|
| Every backup | Critical production environments requiring maximum assurance |
| Every 3rd | Balanced approach for most deployments |
| Every 5th-10th | High-volume backup schedules where verification overhead matters |
[Screenshot placeholder: Verification tab with frequency options]
Restore individual workflows from a backup:
- In Backup History, click a backup
- Click View Contents
- Go to the Workflows tab
- Select the workflows to restore
- Click Restore Selected
[Screenshot placeholder: Workflow selection for restore]
If a workflow already exists:
| Option | Behavior |
|---|---|
| Rename | Restore with "(restored)" suffix |
| Skip | Do not restore this workflow |
| Overwrite | Replace the existing workflow |
[Screenshot placeholder: Restore conflict resolution options]
When restoring workflows:
- Credentials are restored if they do not exist
- Existing credentials are not overwritten
- Workflows are linked to matching credentials by name
For bare-metal recovery or disaster recovery:
- Click System Restore on a backup
- Review the warnings:
- All current data will be replaced
- n8n will be restarted
- Users will be logged out
- Confirm the restoration
- Wait for the process to complete
flowchart TD
Start[Start System Restore] --> Stop[Stop n8n Service]
Stop --> Backup[Backup Current State]
Backup --> Extract[Extract Backup Archive]
Extract --> RestoreDB[Restore PostgreSQL]
RestoreDB --> RestoreConfig[Restore Config Files]
RestoreConfig --> RestoreCerts[Restore SSL Certs]
RestoreCerts --> Restart[Restart All Services]
Restart --> Verify[Verify Services]
Verify --> Complete[Restoration Complete]
[Screenshot placeholder: System restore warning dialog]
Configure where backups are stored:
Local Storage:
- Default path:
/app/backups - Automatically created during setup
- Persists in Docker volume
NFS Storage:
- Server address (e.g.,
nfs.example.com) - Export path (e.g.,
/export/n8n_backups) - Mount options
[Screenshot placeholder: Backup storage configuration]
| Option | Extension | Speed | Size |
|---|---|---|---|
| gzip | .gz |
Medium | Medium |
| zstd | .zst |
Fast | Small |
| none | (none) | Fastest | Largest |
The Grandfather-Father-Son retention strategy:
| Level | Retention | Purpose |
|---|---|---|
| Daily | Keep 7 days | Recent point-in-time recovery |
| Weekly | Keep 4 weeks | Weekly snapshots |
| Monthly | Keep 6 months | Long-term archives |
| Minimum | Keep 3 oldest | Disaster recovery baseline |
[Screenshot placeholder: GFS retention configuration]
Automatic deletion of old backups:
Time-Based Pruning:
- Delete backups older than X days
- Respects retention policy
Space-Based Pruning:
- Trigger when free space below X%
- Delete oldest unprotected backups
Size-Based Pruning:
- Keep total backup size under X GB
- Delete oldest when exceeded
Critical Space Handling:
- Emergency threshold (default: 5% free)
- Options: Delete oldest immediately or stop backups and alert
[Screenshot placeholder: Pruning configuration page]
Configure notifications for backup events:
- Go to System Notifications
- Find backup-related events:
backup_success- Backup completedbackup_failure- Backup failedbackup_started- Backup beganbackup_pending_deletion- Backup scheduled for deletionbackup_critical_space- Low disk space for backups
- Configure targets (channels/groups)
- Set escalation if needed
The notification system provides multi-channel alerting for system events.
flowchart TB
Event[System Event] --> Evaluate[Rule Evaluation]
Evaluate --> Check{Channel<br/>Enabled?}
Check -->|No| Skip[Skip]
Check -->|Yes| Cooldown{Cooldown<br/>Active?}
Cooldown -->|Yes| Skip
Cooldown -->|No| Route[Route to Channel]
Route --> Apprise[Apprise<br/>30+ Services]
Route --> NTFY[NTFY<br/>Push Notifications]
Route --> Email[Email<br/>SMTP]
Route --> Webhook[Webhook<br/>HTTP POST]
Apprise --> Discord[Discord]
Apprise --> Slack[Slack]
Apprise --> Telegram[Telegram]
Apprise --> More[... 27+ more]
Apprise supports 30+ notification services:
| Category | Services |
|---|---|
| Chat | Discord, Slack, Telegram, Microsoft Teams, Mattermost, Rocket.Chat |
| SMTP, Gmail, SendGrid, Mailgun, AWS SES | |
| Push | Pushover, Pushbullet, Join, Simplepush |
| SMS | Twilio, Nexmo, MessageBird |
| Webhooks | Custom HTTP endpoints, IFTTT, Zapier |
| Other | Home Assistant, Gotify, Matrix, XMPP |
Native NTFY integration provides:
- Mobile push notifications (iOS/Android)
- Desktop notifications
- Email forwarding
- Action buttons
- Priority levels
- Scheduled delivery
Understanding Topics vs Channel Slugs:
| Concept | Purpose | Example |
|---|---|---|
| Topic | What you subscribe to in the NTFY app to receive notifications | backup_alerts |
| Channel Slug | What you use in n8n webhook payloads to route messages | channel:ntfy_backup_alerts |
The topic is the NTFY subscription identifier, while the channel slug is how n8n's notification system routes messages to that topic.
Bidirectional Sync: Topics created in the NTFY Push section automatically create corresponding notification channels, and vice versa. Use the Sync Channels button to ensure both sections are synchronized.
Direct SMTP integration:
- Configurable SMTP server
- TLS/SSL support
- Custom templates
- HTML and plain text
Send HTTP POST requests to any endpoint:
- Custom payload format
- Header configuration
- Authentication support
- Go to Notifications > Channels
- Click Add Channel
- Select Apprise
- Enter the Apprise URL:
discord://webhook_id/webhook_token slack://token_a/token_b/token_c tgram://bot_token/chat_id - Set priority and description
- Click Save
[Screenshot placeholder: Apprise channel configuration]
| Service | URL Format |
|---|---|
| Discord | discord://webhook_id/webhook_token |
| Slack | slack://token_a/token_b/token_c/#channel |
| Telegram | tgram://bot_token/chat_id |
mailto://user:pass@smtp.example.com |
|
| Pushover | pover://user_key@api_token |
- Select NTFY as the type
- Configure:
- Server URL: NTFY server address
- Topic: Topic name (spaces are automatically converted to underscores)
- Priority: Default priority (1-5)
- Authentication: Username/password if required
- Click Save
Local NTFY Server Detection: When adding an NTFY channel that points to your local NTFY server, the system automatically:
- Adds "NTFY: " prefix to the channel name
- Generates a slug in the format
ntfy_{topic_name} - Displays a "Local" badge and megaphone icon to distinguish it from external NTFY channels
- Syncs the topic to the NTFY Push section
Success Dialog: After creating a local NTFY channel, a helpful dialog appears explaining:
- Topic (amber): What you subscribe to in your NTFY app (e.g.,
my_alerts) - Channel Slug (blue): What you use in n8n webhook payloads (e.g.,
channel:ntfy_my_alerts)
Important: Subscribe to the topic in your NTFY app to receive notifications. Use the channel slug in your n8n workflows to send notifications.
After creating a channel:
- Click the channel row
- Click Test
- A test notification is sent
- Verify you received it
Groups allow routing notifications to multiple channels at once.
- Go to Notifications > Groups
- Click Add Group
- Enter a name (e.g., "On-Call Team")
- Select channels to include
- Click Save
[Screenshot placeholder: Notification group configuration]
| Group | Channels | Purpose |
|---|---|---|
| Critical Alerts | SMS + Pushover + Discord | Immediate attention required |
| Daily Summary | Email + Slack | Non-urgent notifications |
| DevOps Team | Discord + PagerDuty | Technical team alerts |
Configure the NTFY integration:
- Go to Notifications > NTFY
- Click Server Settings
- Configure:
- Server URL: Your NTFY server (e.g.,
https://ntfy.shor self-hosted) - Default Topic: Default topic for notifications
- Authentication: Enable if server requires auth
- Username/Password: If authentication enabled
- Server URL: Your NTFY server (e.g.,
[Screenshot placeholder: NTFY server configuration]
Organize notifications with topics:
- Go to NTFY > Topics
- Click New Topic
- Configure:
- Name: Topic identifier (e.g.,
n8n-alerts) - Description: Optional description
- Access Level: Read & Write, Read Only, or Write Only
- Default Priority: Min (1) to Urgent (5)
- Default Tags: Emoji tags (e.g.,
warning,backup) - Require Authentication: Enable if topic needs auth
- Name: Topic identifier (e.g.,
Topic Name Sanitization: Topic names are automatically sanitized to meet NTFY requirements:
- Spaces are converted to underscores (e.g., "my alerts" → "my_alerts")
- Invalid characters are removed (only alphanumeric, dashes, underscores allowed)
- Multiple consecutive underscores/dashes are collapsed
Success Dialog: After creating a topic, a helpful dialog appears explaining:
- Topic (amber): The name to subscribe to in your NTFY app
- Channel Slug (blue): The slug to use in n8n webhook payloads (e.g.,
channel:ntfy_my_alerts)
Sync Channels Button: Click Sync Channels to synchronize topics with the Notification Channels section. This creates corresponding notification channels that can be used in notification groups.
[Screenshot placeholder: NTFY topics list]
Send ad-hoc notifications:
- Go to NTFY > Compose
- Select a topic
- Enter message details:
- Title: Message title
- Message: Body text (supports Markdown)
- Priority: Urgency level
- Tags: Emoji indicators
- Actions: Clickable buttons (optional)
- Click Send
[Screenshot placeholder: NTFY message composition form]
Create reusable message templates:
- Go to NTFY > Templates
- Click Add Template
- Configure:
- Name: Template identifier
- Title Template: With Go template variables
- Body Template: Message body with variables
- Default Priority: Priority level
- Tags: Default tags
Available Template Variables:
| Variable | Description |
|---|---|
{{ .EventType }} |
Type of event (e.g., backup_success) |
{{ .Timestamp }} |
Event timestamp |
{{ .Severity }} |
Event severity level |
{{ .Message }} |
Event message |
{{ .Details }} |
Additional event details (JSON) |
Example Template:
Title: {{ .Severity | upper }}: {{ .EventType }}
Body: {{ .Message }}
Occurred at: {{ .Timestamp | formatTime }}
Details: {{ .Details | toJSON }}
[Screenshot placeholder: NTFY template creation form]
Save frequently used messages:
- Compose a message
- Click Save as Template
- Give it a name
- Access later from Saved Messages
View sent NTFY messages:
- Go to NTFY > History
- View all sent messages with:
- Timestamp
- Topic
- Title/message
- Delivery status
If you enabled NTFY during setup, you have a self-hosted push notification server.
- Web UI:
https://your-domain.com/ntfy/ - API:
https://your-domain.com/ntfy/
Mobile Apps:
- iOS: Download "ntfy" from App Store
- Android: Download "ntfy" from Google Play or F-Droid
Configuration:
- Open the ntfy app
- Add your server:
https://your-domain.com/ntfy/ - Subscribe to your topics
- Enable notifications
Desktop:
- Use the web UI at
https://your-domain.com/ntfy/ - Or install the ntfy CLI tool
| Variable | Default | Description |
|---|---|---|
NTFY_BASE_URL |
(your domain) | Public URL for NTFY |
NTFY_ENABLE_LOGIN |
true |
Require authentication |
NTFY_ENABLE_SIGNUP |
false |
Allow user registration |
NTFY_AUTH_DEFAULT_ACCESS |
read-write |
Default permission level |
Send notifications from n8n workflows to the management console.
POST https://your-domain.com/management/api/notifications/webhook
- Go to Notifications > Channels
- Add a Webhook type channel
- An API key is generated automatically
- Copy the API key for use in n8n
Create an HTTP Request node in n8n:
{
"method": "POST",
"url": "https://your-domain.com/management/api/notifications/webhook",
"headers": {
"X-API-Key": "your-api-key",
"Content-Type": "application/json"
},
"body": {
"title": "Workflow Completed",
"message": "The data sync workflow finished successfully.",
"priority": "normal",
"channel": "default"
}
}📚 Detailed Guide Available: For comprehensive documentation including proper setup order and technical configuration, see docs/NOTIFICATIONS.md.
System notifications automatically alert you to important events.
Events are organized into five categories:
| Event | Description | Default Severity |
|---|---|---|
backup_success |
Backup completed successfully | Info |
backup_failure |
Backup failed | Critical |
backup_started |
Backup began | Info |
backup_pending_deletion |
Backup scheduled for retention deletion | Warning |
backup_critical_space |
Disk space critically low | Critical |
| Event | Description | Default Severity |
|---|---|---|
container_unhealthy |
Container health check failed | Critical |
container_restart |
Container restarted | Warning |
container_stopped |
Container stopped unexpectedly | Critical |
container_started |
Container started | Info |
container_removed |
Container was removed | Warning |
container_healthy |
Container recovered to healthy | Info |
container_high_cpu |
Container CPU above threshold | Warning |
container_high_memory |
Container memory above threshold | Warning |
| Event | Description | Default Severity |
|---|---|---|
security_event |
Security-related event (e.g., failed logins) | Critical |
| Event | Description | Default Severity |
|---|---|---|
certificate_expiring |
SSL certificate expiring soon | Warning |
| Event | Description | Default Severity |
|---|---|---|
disk_space_low |
Disk usage above threshold | Warning |
high_memory |
System memory above threshold | Warning |
high_cpu |
Sustained high CPU usage | Warning |
update_available |
Software update available | Info |
Configure each event type individually:
[Screenshot placeholder: System notification event settings]
| Setting | Description | Options |
|---|---|---|
| Enabled | Whether notifications are sent | On/Off |
| Severity | Priority level | Info, Warning, Critical |
| Frequency | How often to notify | Every time, Once per 15m/30m/1h/4h/12h/day/week |
| Cooldown | Minimum time between notifications | Minutes |
| Thresholds | Trigger conditions | Varies by event type |
Each event category (Backup, Container, Security, SSL, System) includes a Quick Setup section for bulk target assignment:
- Expand an event category (e.g., Container Events)
- Click Apply to All Events in the Quick Setup section
- In the modal, select:
- Target Type: Channel or Group
- Target: The specific channel or group
- Escalation Level: L1 (Primary) or L2 (Escalation)
- Click Apply to All
This adds the selected notification target to all events in that category at once. Events that already have the target configured are automatically skipped to avoid duplicates.
This feature simplifies initial setup when you want consistent notification routing for an entire category of events.
Some events have configurable thresholds:
| Event | Threshold | Default |
|---|---|---|
disk_space_low |
Percent used | 90% |
high_memory |
Percent used | 90% |
high_cpu |
Percent + duration | 90% for 5 minutes |
certificate_expiring |
Days before expiration | 14 days |
L1/L2 escalation ensures critical events are not missed.
- L1 (Primary): First notification sent immediately
- Wait Period: Configurable timeout (default: 30 minutes)
- L2 (Escalation): If not acknowledged, escalate to L2 targets
- Go to System Notifications
- Select an event
- Enable Escalation
- Set Escalation Timeout (minutes)
- Add L2 Targets (different channels/groups than L1)
[Screenshot placeholder: L1/L2 escalation settings]
System-wide notification controls are located at the top of the System Notifications page in the status bar and in the collapsible settings cards below the event categories.
The page includes:
- Status Bar (top): Quick access to Maintenance Mode and Quiet Hours toggles, plus Events Enabled and Rate Limit counters
- Event Categories: All event types organized by category
- Rate Limiting: Collapsible card below the event categories
- Daily Digest: Collapsible card below the event categories
[Screenshot placeholder: System Notifications page]
Temporarily silence all notifications:
- Go to Settings > System Notifications
- Click the Maintenance button in the status bar
- Optionally set an end time
- Add a reason note
While in maintenance mode:
- No notifications are sent
- Events are still logged
- Manual notifications still work
Reduce notification priority during specified hours:
| Setting | Description |
|---|---|
| Enabled | Turn quiet hours on/off |
| Start Time | When quiet hours begin (e.g., 22:00) |
| End Time | When quiet hours end (e.g., 07:00) |
| Action | Reduce priority or mute completely |
Aggregate low-priority notifications:
- Enable Daily Digest
- Set digest time (e.g., 08:00)
- Select which severity levels to include
- Receive a summary email daily
Prevent notification storms:
| Setting | Description | Default |
|---|---|---|
| Max per Hour | Maximum notifications per hour | 50 |
| Emergency Contact | Override channel for rate limit warnings | None |
Container-specific notification settings are managed directly from the Containers view:
- Go to Containers (main menu)
- Click on the container you want to configure
- Go to the Alerts tab
- Configure:
- Enable Notifications: Master on/off for this container
- Monitor Stopped: Stop events
- Monitor Unhealthy: Health check failures
- Monitor Restart: Restart events
- CPU Threshold: Custom CPU limit (%) with slider
- Memory Threshold: Custom memory limit (%) with slider
The notification system enforces a proper setup order to prevent misconfiguration:
-
Global events must be enabled first - Before per-container alerts will work, you must enable the corresponding container event types in Settings > System Notifications > Container Events.
-
Individual toggles reflect global state - Each per-container toggle (Stopped, Unhealthy, High CPU, etc.) is disabled if the corresponding global event is not enabled. A message indicates which events need to be enabled globally.
-
Warning when disabling global events - If you try to disable a global container event that has per-container configurations, a confirmation dialog shows which containers will be affected.
Important: Even with per-container settings configured, notifications won't be sent unless you have notification targets configured in the global Container Events settings.
[Screenshot placeholder: Container Alerts tab]
Prevents notification spam when services rapidly toggle states.
- System tracks event frequency per target
- If events exceed threshold within time window, "flapping" is detected
- During flapping:
- Individual notifications are suppressed
- Summary notifications are sent at intervals
- When stable, a recovery notification is sent
| Setting | Description | Default |
|---|---|---|
| Enabled | Turn flapping detection on/off | Yes |
| Threshold Count | Events to trigger flapping | 3 |
| Threshold Minutes | Time window for counting | 10 |
| Summary Interval | Minutes between summaries | 15 |
| Notify on Recovery | Send notification when stable | Yes |
Monitor and control Docker containers.
[Screenshot placeholder: Container management overview]
Containers are displayed in a collapsible card format:
Collapsed View (default):
- Status icon and color indicator
- Container name and image
- Status badge (Running/Stopped/etc.)
- Health badge (Healthy/Unhealthy)
- Remove button (for stopped containers)
Expanded View (click to expand):
- Recreate button (for N8N project containers)
- Stats grid: Uptime, CPU, Memory, Network
- Memory usage progress bar
- Action buttons
| Action | Description |
|---|---|
| Start | Start a stopped container |
| Stop | Gracefully stop a running container |
| Restart | Stop and start a running container |
| Recreate | Remove and recreate container (with optional image pull) |
| Alerts | Configure container-specific notifications |
| Logs | Display container log output with filtering |
| Terminal | Open interactive terminal session |
| Remove | Delete a stopped container |
Note: Restart, Alerts, Logs, and Terminal buttons are only available for running containers. Stopped containers show only Start and Remove options.
- Click a container to expand it
- Click Logs to open the log viewer
Log Viewer Controls:
- Lines: Select number of lines (50, 100, 200, 500, 1000, or All)
- Since: Filter logs by time (e.g., "1h", "30m", "2024-01-01")
- Follow: Enable real-time log streaming (auto-refreshes every 2 seconds)
- Refresh: Manually refresh logs
- Search: Filter displayed logs by keyword
The search feature filters logs client-side and shows a match count. Use the "Since" field to reduce server load when viewing large log files.
[Screenshot placeholder: Enhanced container log viewer with controls]
Expand a container to view current metrics:
- Uptime: Time since container started
- CPU: Current CPU usage percentage
- Memory: Current memory usage in MB
- Network: Network I/O (download bytes)
- Memory Bar: Visual progress bar showing memory percentage
Monitor and manage n8n workflows.
[Screenshot placeholder: Workflow management page]
View all workflows with:
- Name: Workflow name
- ID: Unique identifier
- Active: Enabled/disabled status
- Nodes: Number of nodes
- Created: Creation date
- Updated: Last modification date
- Search: Filter by workflow name
- Status Filter: Show all, active only, or inactive only
- Sort: By name, date, or status
| Action | Description |
|---|---|
| Activate | Enable workflow execution |
| Deactivate | Disable workflow execution |
| View Executions | See recent execution history |
| Open in n8n | Open workflow in n8n editor |
View recent executions for each workflow:
- Execution ID
- Status (success, error, waiting)
- Start time
- Duration
- Error message (if failed)
[Screenshot placeholder: Workflow execution history]
If you enabled the "Public Website" option during setup, you can host a static website alongside your n8n instance.
The Files tab provides a full-featured file manager (File Browser) for your public website root directory.
- Upload: Upload HTML, CSS, JS, and image files directly
- Edit: Edit code files in the browser
- Organize: Create folders and manage file structure
Your public website is accessible at:
https://www.yourdomain.comhttps://yourdomain.com
Note: This is separate from your n8n instance at
n8n.yourdomain.com.
If using Cloudflare Tunnel, you must add a public hostname for your website:
- Go to Cloudflare Zero Trust > Access > Tunnels
- Select your tunnel > Configure > Public Hostname
- Add a new hostname:
- Subdomain:
www(or leave blank for root) - Domain:
yourdomain.com - Service:
HTTPS->n8n_nginx:443 - Settings: TLS -> No TLS Verify (enabled)
- Subdomain:
Monitor system health and resources.
[Screenshot placeholder: System health overview]
Quick status of all services:
- n8n: API health check
- PostgreSQL: Database connectivity
- Nginx: Configuration validation
- Certbot: Certificate status
- Management: Console health
Real-time visualization of:
- CPU Usage: Usage percentage over time
- Memory Usage: Used/available over time
- Load Average: 1/5/15 minute averages
- Disk I/O: Read/write operations
Storage information for all mount points:
- Mount point
- Total size
- Used space
- Free space
- Usage percentage
- Warning indicators for low space
View certificate information:
- Domain name
- Expiration date
- Days until expiration
- Issuer (Let's Encrypt)
- Last renewal date
[Screenshot placeholder: SSL certificate information]
System Docker details:
- Docker version
- Number of containers (running/total)
- Number of images
- Total volume size
- Network information
Configure the management console.
| Setting | Options |
|---|---|
| Theme | Light, Dark, System |
| Layout | Sidebar, Horizontal |
Change your admin password:
- Enter current password
- Enter new password (minimum 8 characters)
- Confirm new password
- Click Change Password
See Section 5.5 for details.
Configure the connection to n8n:
- API Key: Your n8n API key
- Base URL: n8n editor URL (auto-detected)
- Test Connection: Verify connectivity
Configure SMTP for email notifications:
| Setting | Description |
|---|---|
| SMTP Server | Mail server hostname |
| Port | SMTP port (25, 465, 587) |
| Security | None, TLS, STARTTLS |
| Username | SMTP authentication username |
| Password | SMTP authentication password |
| From Address | Sender email address |
| From Name | Sender display name |
Customize notification emails:
- Go to Settings > Email > Templates
- Select a template
- Edit the HTML/text content
- Use variables for dynamic content
- Preview and save
Enable verbose logging:
- Toggle Debug Mode on
- Log level increases to DEBUG
- More detailed information in logs
- Disable for production use
View version information:
- Management Console version
- API version
- Frontend version
- Build date
- System information
- Dashboard Review: Check the management console dashboard for any alerts
- Backup Status: Verify the most recent backup completed successfully
- Container Health: Ensure all containers show healthy status
- Disk Space: Monitor disk usage, especially on backup storage
| Check | Frequency | Action if Failed |
|---|---|---|
| Container health | Continuous (automated) | Investigate logs, restart if needed |
| Backup completion | Daily | Check backup logs, run manual backup |
| Disk space | Daily | Clean old backups, expand storage |
| Certificate expiration | Weekly | Verify certbot is running |
Review logs regularly for issues:
# View all container logs
docker compose logs --tail=100
# View specific container logs
docker logs n8n --tail=100
docker logs n8n_management --tail=100
# Follow logs in real-time
docker compose logs -fThe system performs automatic health checks:
- PostgreSQL: Connection test every 5 seconds
- n8n: HTTP health endpoint check
- Nginx: Configuration validation on restart
- Management: API health endpoint
Certificates are automatically renewed by Certbot:
- Renewal check runs every 12 hours
- Certificates renew when less than 30 days remain
- Nginx is automatically reloaded after renewal
Force certificate renewal:
# Dry run (test renewal)
docker exec n8n_certbot certbot renew --dry-run
# Force renewal
docker exec n8n_certbot certbot renew --force-renewal
# Reload nginx after renewal
docker exec n8n_nginx nginx -s reload| Issue | Cause | Solution |
|---|---|---|
| Renewal fails | DNS API credentials expired | Update credentials in DNS provider file |
| Certificate not loading | Nginx not reloaded | Restart nginx container |
| Certificate expired | Certbot not running | Check certbot container logs |
# View certificate details
docker exec n8n_certbot certbot certificates
# Check certificate expiration
openssl s_client -connect your-domain.com:443 -servername your-domain.com 2>/dev/null | openssl x509 -noout -datesThe system uses PostgreSQL 16 with pgvector extension for:
- n8n workflow data
- Execution history
- Credential storage
- Management console data
- Vector embeddings for AI workflows
# Connect to database
docker exec -it n8n_postgres psql -U n8n -d n8n
# List databases
docker exec n8n_postgres psql -U n8n -c "\l"
# List tables in n8n database
docker exec n8n_postgres psql -U n8n -d n8n -c "\dt"
# Check database size
docker exec n8n_postgres psql -U n8n -c "SELECT pg_database.datname, pg_size_pretty(pg_database_size(pg_database.datname)) FROM pg_database;"If Adminer is enabled, access it at https://your-domain.com/adminer/
- Select PostgreSQL as system
- Server:
postgres - Username:
n8n(or your configured user) - Password: (from .env file)
- Database:
n8norn8n_management
The pgvector extension enables:
- Vector similarity search
- Embedding storage
- AI/ML integration with n8n
Example usage in n8n SQL queries:
-- Create embeddings table
CREATE TABLE embeddings (
id SERIAL PRIMARY KEY,
content TEXT,
embedding vector(1536)
);
-- Similarity search
SELECT content FROM embeddings
ORDER BY embedding <-> '[0.1, 0.2, ...]'
LIMIT 5;Update to latest images:
# Pull latest images
docker compose pull
# Restart with new images
docker compose up -d
# Remove old images
docker image prune -fIf Dozzle is enabled, access it at https://your-domain.com/logs/
Features:
- Real-time log streaming
- Multi-container view
- Log search and filtering
- Download logs
If Portainer is enabled, access it at https://your-domain.com:9000
Features:
- Visual container management
- Resource monitoring
- Container terminal access
- Image management
- Volume management
Default resource limits can be adjusted in docker-compose.yaml:
services:
n8n:
deploy:
resources:
limits:
cpus: '2'
memory: 4G
reservations:
cpus: '0.5'
memory: 512M| Backup Type | Frequency | Retention | Purpose |
|---|---|---|---|
| Full database | Daily | 7 days | Point-in-time recovery |
| Weekly archive | Weekly | 4 weeks | Weekly snapshots |
| Monthly archive | Monthly | 12 months | Long-term retention |
For disaster recovery, store backups on a separate NFS server:
- Configure NFS server address in settings
- Set NFS export path
- Enable NFS backup storage
- Backups are written to both local and NFS
| Verification | Frequency | Purpose |
|---|---|---|
| Archive integrity | Each backup | Ensure backup is not corrupted |
| Database validation | Weekly | Verify database dump is valid |
| Full restore test | Monthly | Confirm complete recovery works |
- Document recovery procedures
- Test restores regularly
- Store encryption keys securely (separate from backups)
- Maintain off-site backup copies
- Keep configuration files backed up
| Scenario | Recovery Method | Estimated Time |
|---|---|---|
| Single workflow loss | Workflow restore | 5 minutes |
| Database corruption | Database restore | 15-30 minutes |
| Full system loss | Bare-metal recovery | 1-2 hours |
📚 Detailed Guide Available: For comprehensive documentation including account creation, auth key generation, and detailed explanation of subnet routing, see docs/TAILSCALE.md.
If you enabled Tailscale during setup, the container is already configured with:
- TS_ROUTES: Advertises your Docker host IP to the Tailscale network
- TS_SERVE: Exposes your n8n instance via Tailscale's HTTPS proxy
- TS_AUTH_ONCE: Prevents re-authentication on container restarts
For manual setup:
- Generate an auth key at Tailscale Admin Console
- Add to
.env:TAILSCALE_AUTH_KEY=tskey-auth-xxx TAILSCALE_HOST_IP=192.168.1.10 # Your Docker host's local IP - Restart the stack:
docker compose up -d
IMPORTANT: After the Tailscale container starts, you must approve the advertised routes in the Tailscale Admin Console:
- Visit Tailscale Admin - Machines
- Find your n8n-tailscale node in the list
- Click on the node to open its settings
- Look for the Subnets section showing the advertised route (e.g.,
192.168.1.10/32) - Click Approve to enable the route
- If prompted about Serve, enable it to allow HTTPS proxying
Without approving the routes, you won't be able to access your Docker host via the Tailscale network.
Tailscale Serve is configured via TS_SERVE_CONFIG using the tailscale-serve.json file. This proxies HTTPS traffic from your Tailscale Magic DNS name to your n8n domain.
If using setup.sh: The file is generated automatically with your domain.
If configuring manually: Edit tailscale-serve.json and replace your-domain.com with your actual domain:
{
"TCP": { "443": { "HTTPS": true } },
"Web": {
"${TS_CERT_DOMAIN}:443": {
"Handlers": {
"/": { "Proxy": "https://your-actual-domain.com:443" }
}
}
}
}The ${TS_CERT_DOMAIN} placeholder is automatically replaced by Tailscale with your node's FQDN.
To verify serve is enabled:
docker exec n8n_tailscale tailscale serve statusOnce routes are approved, you can access your services from any device on your Tailscale network:
https://n8n-tailscale.your-tailnet.ts.net
This uses Tailscale's HTTPS proxy to securely access n8n.
The advertised route gives you direct access to your Docker host IP via Tailscale:
| Service | URL |
|---|---|
| n8n | https://192.168.1.10 |
| Management Console | https://192.168.1.10/management/ |
| SSH to Docker Host | ssh user@192.168.1.10 |
Replace 192.168.1.10 with your actual TAILSCALE_HOST_IP value.
To restrict management console access to Tailscale only:
- Go to Settings > Security
- Remove public IP ranges
- Keep only
100.64.0.0/10(Tailscale range) - Access via Tailscale IP only
To find the container's Tailscale IP:
docker exec n8n_tailscale tailscale ipIf routes aren't working:
- Check the container logs:
docker logs n8n_tailscale - Verify the route is advertised:
docker exec n8n_tailscale tailscale status - Ensure routes are approved in the admin console
- Check that
TAILSCALE_HOST_IPin.envmatches your Docker host's actual IP
📚 Detailed Guide Available: For comprehensive documentation including account creation, Zero Trust setup, and tunnel configuration, see docs/CLOUDFLARE.md.
Cloudflare Tunnel provides secure access without exposing ports.
- Create a tunnel in Cloudflare Zero Trust
- Copy the tunnel token
- Add to
.env:CLOUDFLARE_TUNNEL_TOKEN=eyJhIjoixxxx - Restart the stack
Configure your Cloudflare DNS:
- In Cloudflare dashboard, go to DNS
- The tunnel automatically creates CNAME records
- Verify records point to your tunnel
Add access policies:
- Go to Access > Applications
- Create an application for n8n
- Add access policies (email, IP, etc.)
- Users must authenticate before accessing
The NFS server must:
- Export a directory with read/write access
- Allow connections from your n8n server
- Have sufficient storage space
On the NFS server (/etc/exports):
/export/n8n_backups 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)
Apply changes:
exportfs -raIn the management console:
- Go to Backups and click Configure
- Select the Storage tab
- Enable NFS storage
- Enter:
- Server:
nfs.example.com - Path:
/export/n8n_backups
- Server:
- Test the connection
- Click Save Changes
| Issue | Cause | Solution |
|---|---|---|
| Mount fails | Firewall blocking | Open NFS ports (2049, 111) |
| Permission denied | Export permissions | Check /etc/exports configuration |
| Slow performance | Network issues | Check network connectivity |
Check NFS status:
docker exec n8n_management cat /app/config/nfs_status.jsonThe nginx configuration is at ./nginx.conf in your project directory.
Add security headers in the server block:
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy strict-origin-when-cross-origin;
add_header Content-Security-Policy "default-src 'self'";Add rate limiting to prevent abuse:
# In http block
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
# In location block
location /webhook/ {
limit_req zone=api burst=20 nodelay;
# ... rest of config
}After modifying nginx.conf:
# Test configuration
docker exec n8n_nginx nginx -t
# Reload nginx
docker exec n8n_nginx nginx -s reloadTip: Environment variables can be managed through the management console at Settings > Environment. This provides a user-friendly interface with health checks and validation.
| Variable | Description | Default |
|---|---|---|
DOMAIN |
Your domain name (used for SSL, URLs, etc.) | Required |
N8N_MANAGEMENT_HOST_IP |
Local IP of Docker host (for backup/restore) | Auto-detected |
MGMT_PORT |
Management console port | 3333 |
TIMEZONE |
System timezone | Auto-detected |
| Variable | Description | Default |
|---|---|---|
POSTGRES_USER |
PostgreSQL username | n8n |
POSTGRES_PASSWORD |
PostgreSQL password | Auto-generated |
POSTGRES_DB |
Database name | n8n |
| Variable | Description | Default |
|---|---|---|
N8N_ENCRYPTION_KEY |
n8n credential encryption | Auto-generated |
MGMT_SECRET_KEY |
Session signing key | Auto-generated |
MGMT_ENCRYPTION_KEY |
Settings encryption key | Auto-generated |
| Variable | Description | Default |
|---|---|---|
ADMIN_USER |
Admin username | admin |
ADMIN_PASS |
Admin password | Set during setup |
ADMIN_EMAIL |
Admin email | Set during setup |
| Variable | Description |
|---|---|
CLOUDFLARE_TUNNEL_TOKEN |
Cloudflare tunnel authentication |
TAILSCALE_AUTH_KEY |
Tailscale pre-auth key |
TAILSCALE_ROUTES |
CIDR routes to advertise (e.g., 192.168.1.0/24) |
NFS_SERVER |
NFS server address |
NFS_PATH |
NFS export path |
NFS_LOCAL_MOUNT |
Local mount point for NFS share |
N8N_API_KEY |
n8n API key for workflow management |
NTFY_BASE_URL |
NTFY server URL for push notifications |
| Variable | Description | Default |
|---|---|---|
N8N_HOST |
n8n hostname | Your domain |
N8N_PROTOCOL |
Protocol | https |
N8N_PORT |
Internal port | 5678 |
WEBHOOK_URL |
Webhook base URL | https://domain/webhook/ |
Symptoms: Docker commands fail, daemon not running
Solutions:
# Check Docker status
sudo systemctl status docker
# Start Docker
sudo systemctl start docker
# Enable Docker on boot
sudo systemctl enable dockerSymptoms: Container creation fails, permission denied errors
Solution:
- On Proxmox host, edit container config
- Add:
lxc.apparmor.profile: unconfined features: nesting=1 - Restart the container
Symptoms: Certificate acquisition fails, DNS challenge fails
Solutions:
- Verify domain resolves correctly:
dig +short your-domain.com - Check DNS provider credentials
- Wait for DNS propagation (up to 5 minutes)
- Verify API token permissions
Symptoms: Certbot fails, SSL errors
Solutions:
- Check certbot logs:
docker logs n8n_certbot - Verify DNS credentials file permissions:
chmod 600 cloudflare.ini - Test DNS challenge manually
- Check rate limits (Let's Encrypt has limits)
Diagnosis:
# Check container status
docker compose ps
# View container logs
docker logs [container_name]
# Check for port conflicts
sudo netstat -tlnp | grep 443Common causes:
- Port already in use
- Missing environment variables
- Volume permission issues
Symptoms: n8n cannot connect, management console errors
Solutions:
# Check PostgreSQL status
docker exec n8n_postgres pg_isready
# View PostgreSQL logs
docker logs n8n_postgres
# Test connection
docker exec n8n_postgres psql -U n8n -c "SELECT 1"Symptoms: Browser shows certificate warning, HTTPS fails
Solutions:
- Check certificate exists:
docker exec n8n_nginx ls -la /etc/letsencrypt/live/ - Verify nginx configuration:
docker exec n8n_nginx nginx -t - Reload nginx:
docker exec n8n_nginx nginx -s reload
Symptoms: External webhooks fail, timeout errors
Checklist:
- Port 443 open in firewall
- Domain DNS correct
- n8n container running
- Webhook URL format correct:
https://domain/webhook/[path]
Symptoms: Login fails, credentials rejected
Solutions:
- Verify credentials (case-sensitive)
- Check IP is in allowed subnets
- View management logs:
docker logs n8n_management - Reset admin password (requires database access)
Symptoms: n8n connection fails, workflows not loading
Solutions:
- Regenerate API key in n8n
- Update key in management console
- Test connection in settings
Symptoms: Backup shows failed status
Diagnosis:
# Check backup logs
docker logs n8n_management | grep -i backup
# Check disk space
df -h
# Check NFS connection (if used)
docker exec n8n_management cat /app/config/nfs_status.jsonSymptoms: Slow response, high resource usage
Solutions:
- Check resource usage:
docker stats - Increase container limits in docker-compose.yaml
- Review n8n execution history settings
- Optimize PostgreSQL (increase shared_buffers)
| Component | Command |
|---|---|
| All containers | docker compose logs |
| n8n | docker logs n8n |
| PostgreSQL | docker logs n8n_postgres |
| Nginx | docker logs n8n_nginx |
| Certbot | docker logs n8n_certbot |
| Management | docker logs n8n_management |
# Last 100 lines
docker logs n8n --tail 100
# Follow logs in real-time
docker logs n8n -f
# Logs since specific time
docker logs n8n --since 2024-01-01T00:00:00
# Logs with timestamps
docker logs n8n -tEnable debug logging in management console:
- Go to Settings
- Enable Debug Mode
- Log level increases to DEBUG
- View detailed logs:
docker logs n8n_management
Remember to disable debug mode in production.
# Overall system health
docker compose ps
# PostgreSQL health
docker exec n8n_postgres pg_isready
# n8n health
curl -k https://localhost/healthz
# Nginx configuration
docker exec n8n_nginx nginx -t
# Certificate status
docker exec n8n_certbot certbot certificates# Start all services
docker compose up -d
# Stop all services
docker compose down
# Restart all services
docker compose restart
# Restart specific service
docker compose restart n8n
# View status
docker compose ps
# View logs
docker compose logs -f
# Pull latest images
docker compose pull
# Rebuild containers
docker compose up -d --build# Connect to PostgreSQL
docker exec -it n8n_postgres psql -U n8n -d n8n
# Backup database
docker exec n8n_postgres pg_dump -U n8n -d n8n -Fc > backup.dump
# Restore database
docker exec -i n8n_postgres pg_restore -U n8n -d n8n < backup.dump
# List tables
docker exec n8n_postgres psql -U n8n -d n8n -c "\dt"# View certificates
docker exec n8n_certbot certbot certificates
# Test renewal
docker exec n8n_certbot certbot renew --dry-run
# Force renewal
docker exec n8n_certbot certbot renew --force-renewal
# Reload nginx
docker exec n8n_nginx nginx -s reload# View backup status
docker exec n8n_management ls -la /app/backups
# Check NFS mount
docker exec n8n_management df -h | grep nfs| File | Purpose |
|---|---|
docker-compose.yaml |
Container definitions |
.env |
Environment variables |
nginx.conf |
Nginx configuration |
cloudflare.ini |
Cloudflare credentials |
.n8n_setup_config |
Setup configuration backup |
| Volume | Contents |
|---|---|
n8n_data |
n8n workflow data |
postgres_data |
PostgreSQL database |
letsencrypt |
SSL certificates |
mgmt_backup_staging |
Backup staging area |
mgmt_logs |
Management console logs |
mgmt_config |
Management configuration |
| Term | Definition |
|---|---|
| Apprise | Multi-service notification library |
| Certbot | Let's Encrypt certificate automation tool |
| DNS-01 Challenge | Domain validation via DNS TXT record |
| GFS | Grandfather-Father-Son backup rotation strategy |
| Let's Encrypt | Free SSL/TLS certificate authority |
| n8n | Workflow automation platform |
| NFS | Network File System for remote storage |
| NTFY | Push notification service |
| pgvector | PostgreSQL extension for vector operations |
| Tailscale | VPN service using WireGuard |
| Webhook | HTTP callback for event notifications |
- Log in to Cloudflare Dashboard
- Click your profile icon (top right)
- Select My Profile
- Go to API Tokens tab
- Click Create Token
- Use the Edit zone DNS template
- Under Permissions, ensure:
- Zone - DNS - Edit
- Under Zone Resources:
- Include - Specific zone - (select your zone)
- Click Continue to summary
- Click Create Token
- Copy the token immediately (shown only once)
[Screenshot placeholder: Cloudflare API token creation steps]
- Log in to AWS Console
- Go to IAM > Users
- Create a new user or select existing
- Attach the following policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:ListHostedZones",
"route53:GetChange"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "route53:ChangeResourceRecordSets",
"Resource": "arn:aws:route53:::hostedzone/YOUR_ZONE_ID"
}
]
}- Create access keys for the user
- Save the Access Key ID and Secret Access Key
- Go to Google Cloud Console
- Navigate to IAM & Admin > Service Accounts
- Click Create Service Account
- Enter a name and description
- Grant the DNS Administrator role
- Click Create Key > JSON
- Save the JSON file securely
- Log in to DigitalOcean
- Go to API > Tokens/Keys
- Click Generate New Token
- Enter a name
- Select Read and Write scopes
- Click Generate Token
- Copy the token immediately (shown only once)
- Log in to Tailscale Admin Console
- Go to Settings > Keys
- Click Generate auth key
- Configure:
- Reusable: Yes (recommended for containers)
- Ephemeral: No
- Expiration: Set appropriate expiration
- Tags: Optional, for access control
- Click Generate key
- Copy the key (starts with
tskey-auth-)
[Screenshot placeholder: Tailscale auth key creation]
- Log in to Cloudflare Zero Trust
- Go to Networks > Tunnels
- Click Create a tunnel
- Select Cloudflared connector
- Enter a tunnel name
- Click Save tunnel
- Copy the tunnel token (long string starting with
eyJ)
Configure the tunnel:
- Add public hostnames for n8n and management console
- Point to
http://nginx:443(internal Docker network) - Enable No TLS Verify for internal routing
[Screenshot placeholder: Cloudflare tunnel configuration]
- Log in to your n8n instance
- Click your profile icon (bottom left)
- Select Settings
- Navigate to API in the left sidebar
- Click + Create an API key
- Enter a label (e.g., "Management Console")
- Click Create
- Copy the API key immediately (shown only once)
[Screenshot placeholder: n8n API key generation]
This project is licensed under the MIT License. See the LICENSE file for details.
- Documentation: This README and docs/ folder
- Issues: GitHub Issues
- API Reference: See API.md
- n8n Community: community.n8n.io
- n8n.io - Workflow automation platform
- Let's Encrypt - Free SSL/TLS certificates
- PostgreSQL - Database
- pgvector - Vector similarity search
- FastAPI - Python web framework
- Vue.js - JavaScript framework
- Tailwind CSS - CSS framework
- Docker - Containerization
- Nginx - Web server
- Apprise - Notification library
- ntfy - Push notifications
- My Amazing and loving family! My family puts up with all my coding and automation projects and encourages me in everything. Without them, my projects would not be possible.
- My brother James, who is a continual source of inspiration to me and others. Everyone should have a brother as awesome as mine!
