Self-hosting n8n on AWS EC2 gives you full control over 350+ integrations and sensitive workflow data, but misconfigured security groups or exposed ports can leak credentials in minutes. Over 16,000 developers used n8n by April 2021, yet many skip hardening steps like reverse proxies, automated TLS, and intrusion prevention. This guide walks you through launching a production-ready n8n instance on EC2 with Docker, Nginx, Let's Encrypt SSL, UFW firewall, and Fail2Ban — following AWS shared-responsibility model and n8n's own deployment recommendations.
Quick Answer: Launch a t3.micro Ubuntu EC2 instance, restrict security groups to SSH (port 22) and HTTPS (port 443) only, install Docker and Docker Compose, deploy n8n behind an Nginx reverse proxy with Let's Encrypt certificates, enable UFW and Fail2Ban, then configure automated backups to S3.
Why Self-Host n8n on AWS EC2?
Cost Control and Data Sovereignty
n8n's cloud plan starts at €20/month for 2,500 executions, while a t3.micro EC2 instance costs ~$7.50/month on-demand (less with Savings Plans). Self-hosting keeps workflow JSON, API keys, and customer data inside your VPC — critical for GDPR, HIPAA, or internal compliance. You also avoid vendor lock-in and can customize the Node.js runtime or add private npm packages.
Performance and Scalability
EC2 lets you vertically scale to t3.medium (2 vCPU, 4 GiB) for heavy workloads or horizontally scale with an Application Load Balancer and EFS-backed n8n data. n8n's queue mode (Redis + PostgreSQL) runs natively on AWS managed services like ElastiCache and RDS, supporting 10,000+ executions/hour without managing Kubernetes.
Prerequisites and AWS Setup
IAM and VPC Preparation
- Create an IAM user with programmatic access and attach
AmazonEC2FullAccess,AmazonS3FullAccess(for backups), andAmazonRoute53FullAccess(if using Route 53 DNS). - Build a VPC with public and private subnets across two Availability Zones. Attach an Internet Gateway to the public subnet route table.
- Reserve an Elastic IP for the EC2 instance so the public IP persists across stops/starts.
Launch the EC2 Instance
- Choose Ubuntu Server 22.04 LTS (HVM), SSD Volume Type, 30 GiB gp3.
- Select
t3.micro(free-tier eligible) ort3.smallfor production. - Create a new key pair (RSA, .pem) and download it — you'll need it for SSH.
- Configure security group: allow inbound TCP 22 (SSH) from your IP only, TCP 80 (HTTP) and 443 (HTTPS) from anywhere. Do NOT open 5678 (n8n default port) to the internet.
- Add tag
Name: n8n-prodand enable termination protection.
Server Hardening and Docker Deployment
Initial OS Hardening
- SSH in:
ssh -i your-key.pem ubuntu@<elastic-ip>. - Update packages:
sudo apt update && sudo apt upgrade -y. - Create a non-root admin user:
sudo adduser n8nadmin && sudo usermod -aG sudo n8nadmin. - Disable root SSH and password auth: edit
/etc/ssh/sshd_config→PermitRootLogin no,PasswordAuthentication no, thensudo systemctl reload sshd. - Enable automatic security updates:
sudo apt install unattended-upgrades -y && sudo dpkg-reconfigure --priority=low unattended-upgrades.
Install Docker and Docker Compose
- Install Docker Engine:
curl -fsSL https://get.docker.com | sudo sh. - Add
n8nadminto docker group:sudo usermod -aG docker n8nadmin(log out/in). - Install Docker Compose v2:
sudo apt install docker-compose-plugin -y. - Verify:
docker compose versionshould show v2.20+.
Deploy n8n with Docker Compose
Create /home/n8nadmin/n8n/docker-compose.yml:
version: '3.8'
services:
n8n:
image: n8nio/n8n:latest
restart: unless-stopped
ports:
- "127.0.0.1:5678:5678"
environment:
- N8N_HOST=${DOMAIN}
- N8N_PORT=5678
- N8N_PROTOCOL=https
- NODE_ENV=production
- WEBHOOK_URL=https://${DOMAIN}/
- GENERIC_TIMEZONE=America/New_York
volumes:
- n8n_data:/home/node/.n8n
volumes:
n8n_data:
Create .env with DOMAIN=yourdomain.com. Run docker compose up -d. n8n now listens only on localhost:5678.
Reverse Proxy, SSL, and Firewall
Configure Nginx Reverse Proxy
- Install Nginx:
sudo apt install nginx -y. - Create
/etc/nginx/sites-available/n8n:
server {
listen 80;
server_name yourdomain.com;
location /.well-known/acme-challenge/ { root /var/www/html; }
location / { return 301 https://$host$request_uri; }
}
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:5678;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
- Enable site:
sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/ && sudo nginx -t && sudo systemctl reload nginx.
Obtain Let's Encrypt Certificates
Let's Encrypt issues free 90-day TLS certificates used by over 700 million sites. Install Certbot: sudo apt install certbot python3-certbot-nginx -y. Run sudo certbot --nginx -d yourdomain.com --non-interactive --agree-tos -m admin@yourdomain.com. Certbot auto-configures HTTPS and sets up a systemd timer for renewal every 60 days.
Lock Down with UFW and Fail2Ban
- Enable UFW:
sudo ufw allow 22/tcp && sudo ufw allow 80/tcp && sudo ufw allow 443/tcp && sudo ufw enable. - Install Fail2Ban:
sudo apt install fail2ban -y. - Create
/etc/fail2ban/jail.local:
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 3
- Restart:
sudo systemctl restart fail2ban. Fail2Ban monitors logs and bans IPs after 3 failed SSH attempts for 1 hour.
Backups, Monitoring, and Maintenance
Automated Daily Backups to S3
- Create IAM policy allowing
s3:PutObjecton a dedicated bucketn8n-backups-prod. - Attach policy to EC2 instance profile (no access keys needed).
- Write backup script
/home/n8nadmin/backup_n8n.sh:
#!/bin/bash
DATE=$(date +%F)
docker exec n8n-n8n-1 tar czf /tmp/n8n_${DATE}.tar.gz -C /home/node/.n8n .
aws s3 cp /tmp/n8n_${DATE}.tar.gz s3://n8n-backups-prod/
rm /tmp/n8n_${DATE}.tar.gz
- Make executable and schedule via cron:
0 2 * * * /home/n8nadmin/backup_n8n.sh >> /home/n8nadmin/backup.log 2>&1.
Monitoring with CloudWatch Agent
- Install CloudWatch Agent:
sudo apt install amazon-cloudwatch-agent -y. - Configure
/opt/aws/amazon-cloudwatch-agent/bin/config.jsonto collect CPU, memory, disk, and custom n8n log metrics. - Start agent:
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json -s. - Create alarms for CPU > 80% for 5 minutes, disk > 85%, and n8n container restarts.
Routine Maintenance Checklist
- Weekly:
docker compose pull && docker compose up -dto update n8n image. - Monthly: Review Fail2Ban logs
sudo fail2ban-client status sshdand adjust bantime. - Quarterly: Rotate Elastic IP if not using Route 53 alias records; test backup restore to a staging EC2.
Comparison: Self-Hosted n8n on EC2 vs. n8n Cloud vs. Zapier
Choosing the right deployment model depends on budget, compliance needs, and engineering bandwidth. The table below compares three popular options for a team running 50,000 workflow executions per month.
Self-hosted EC2 requires DevOps effort but offers lowest marginal cost and full data control. n8n Cloud removes infrastructure burden at a predictable price. Zapier provides the largest integration library but charges per task and lacks self-hosting.
| Factor | Self-Hosted n8n on EC2 (t3.small) | n8n Cloud (Pro Plan) | Zapier (Team Plan) |
|---|---|---|---|
| Monthly Cost (USD) | $15–$25 (EC2 + S3 + data transfer) | $50 (50k executions included) | $299 (50k tasks included) |
| Data Residency | Your VPC, any AWS region | EU (Frankfurt) or US (Virginia) | US only |
| Integrations | 400+ (community nodes unlimited) | 400+ (same as self-hosted) | 6,000+ (mostly SaaS) |
| Custom Code Support | Full Node.js/Python in Code node | Full Node.js/Python in Code node | JavaScript only, limited memory |
| Scaling Model | Vertical + queue mode (Redis/RDS) | Managed horizontal scaling | Automatic, opaque |
| SSO / LDAP | Self-managed (Keycloak, Authelia) | SAML/OIDC included in Enterprise | SAML only on Company plan |
| Maintenance Overhead | High (OS, Docker, Nginx, backups) | Zero | Zero |
Common Mistakes and Pro Tips
Mistake: Opening Port 5678 to the Internet
Why It Hurts: n8n's default port exposes the editor UI and webhook endpoints without authentication if you misconfigure environment variables. Bots scan for port 5678 within hours of instance launch.
Fix: Bind n8n to 127.0.0.1:5678 in docker-compose.yml and terminate TLS at Nginx on port 443 only.
Mistake: Using Default n8n Encryption Key
Why It Hurts: n8n encrypts credentials with N8N_ENCRYPTION_KEY. The default key is public knowledge; anyone with database access can decrypt stored API keys.
Fix: Generate a 32-character key: openssl rand -hex 16. Set it in .env and never rotate without re-entering all credentials.
Mistake: Skipping Automated Certificate Renewal
Why It Hurts: Let's Encrypt certificates expire in 90 days. Expired certs break webhook HTTPS endpoints, causing silent workflow failures.
Fix: Certbot's systemd timer handles renewal. Verify with sudo certbot renew --dry-run and monitor /var/log/letsencrypt/letsencrypt.log.
Mistake: No Backup Verification
Why It Hurts: Corrupt or incomplete backups give false confidence. A 2023 study found 40% of SMBs couldn't restore from backup when needed.
Fix: Add a monthly restore test to a throwaway EC2 instance. Automate with a script that spins up t3.micro, restores, runs n8n --version, then terminates.
Mistake: Ignoring Container Resource Limits
Why It Hurts: A runaway workflow can OOM-kill the n8n container, losing in-memory execution state and crashing the editor.
Fix: Add deploy: resources: limits: cpus: '1.5' memory: 2G to docker-compose.yml. Set N8N_PAYLOAD_SIZE_MAX=16 (MB) to prevent huge payloads.
Pro Tips
- Use AWS Systems Manager Session Manager instead of SSH keys — no open port 22 required.
- Enable n8n's
EXECUTIONS_MODE=queuewith Redis (ElastiCache) and PostgreSQL (RDS) for zero-downtime deployments. - Store
.envin AWS Secrets Manager and inject at container start with a sidecar script. - Add a CloudFront distribution in front of Nginx for WAF protection and global edge caching of static assets.
- Tag all resources with
Project=n8n,Env=prodfor cost allocation reports in AWS Cost Explorer.
FAQ
What is n8n and why self-host it?
n8n is a source-available workflow automation tool with 400+ integrations, launched in 2019 by n8n GmbH. Self-hosting on AWS EC2 gives you full data control, lower marginal cost at scale, and the ability to run custom Node.js or Python code without vendor limits.
How does EC2 hosting compare to n8n Cloud?
EC2 hosting costs ~$15–25/month for a t3.small instance versus $50/month for n8n Cloud Pro (50k executions). You manage OS patches, Docker, Nginx, and backups yourself, but you choose the AWS region, keep data in your VPC, and can scale vertically or add queue mode with Redis/RDS.
How do I secure n8n on EC2 with HTTPS?
Deploy n8n behind an Nginx reverse proxy on the same instance. Use Certbot to obtain Let's Encrypt certificates (valid 90 days, auto-renewed). Bind n8n to localhost:5678 only, allow ports 80/443 in the security group, and enforce HTTPS via Nginx redirect.
Why do my webhooks fail after a few months?
Let's Encrypt certificates expire every 90 days. If Certbot's renewal timer fails (common after OS upgrades), HTTPS breaks and webhook endpoints return certificate errors. Monitor /var/log/letsencrypt/letsencrypt.log and run certbot renew --dry-run monthly.
What's the future of self-hosted n8n on AWS?
n8n's 2025 Series C funding ($180M at $2.5B valuation) signals heavy investment in enterprise features: native SSO, advanced RBAC, and managed queue mode. Expect AWS-focused CloudFormation templates and Graviton3 (ARM) optimized Docker images to reduce EC2 costs by 20–40%.
Conclusion
Hosting n8n on AWS EC2 safely is a series of deliberate choices: isolate the container on localhost, terminate TLS at a hardened Nginx reverse proxy, automate Let's Encrypt renewals, enforce firewall rules with UFW, and ban brute-force attackers with Fail2Ban. Add daily S3 backups verified by monthly restore tests, CloudWatch monitoring, and a maintenance calendar, and you'll run a production-grade automation platform that costs a fraction of SaaS alternatives while keeping sensitive data under your control. Start with a t3.micro, validate your workflows, then scale vertically or add queue mode as execution volume grows.
- Never expose n8n's default port 5678 to the internet — use Nginx on 443 only.
- Generate a unique
N8N_ENCRYPTION_KEYand store it in AWS Secrets Manager. - Automate Let's Encrypt renewal and verify it monthly with a dry-run.
- Test backup restores regularly; untested backups are not backups.
0 comments:
Post a Comment