← Back to Blog
n8n · AWS · DevOps

How to Self-Host n8n on AWS EC2 (Step-by-Step 2025 Guide)

✍️ Hamza Bilal 📅 February 2025 ⏱ 12 min read
n8nAWSDockerDevOpsSelf-Hosted

I've set up self-hosted n8n on AWS EC2 for multiple clients. This guide covers the exact setup I use in production — Docker Compose, Nginx with SSL, PostgreSQL persistence, and auto-restart on reboot. Total cost: under $10/month on a t3.small instance.

Prerequisites: AWS account, a domain name (or subdomain), basic terminal comfort. This guide assumes Ubuntu 22.04 LTS.

Step 1 — Launch EC2 Instance

  1. Go to EC2 → Launch Instance
  2. Select Ubuntu Server 22.04 LTS
  3. Choose t3.small (2 vCPU, 2 GB RAM) — minimum for stable n8n
  4. Storage: set to 20 GB gp3
  5. Security Group: open ports 22 (SSH), 80 (HTTP), 443 (HTTPS)
  6. Create a key pair and download the .pem file

SSH into your instance:

ssh -i your-key.pem ubuntu@YOUR_EC2_PUBLIC_IP

Step 2 — Install Docker & Docker Compose

sudo apt update && sudo apt upgrade -y
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker ubuntu
newgrp docker
sudo apt install docker-compose-plugin -y
docker --version  # confirm it works

Step 3 — Create the Docker Compose File

Create a working directory and the compose file:

mkdir ~/n8n && cd ~/n8n
nano docker-compose.yml

Paste this — replace the values in angle brackets:

version: "3.8"

services:
  postgres:
    image: postgres:15
    restart: always
    environment:
      POSTGRES_USER: n8n
      POSTGRES_PASSWORD: <STRONG_PASSWORD>
      POSTGRES_DB: n8n
    volumes:
      - postgres_data:/var/lib/postgresql/data

  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: always
    ports:
      - "5678:5678"
    environment:
      - N8N_HOST=<YOUR_DOMAIN>
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://<YOUR_DOMAIN>/
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=<STRONG_PASSWORD>
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=<ADMIN_PASSWORD>
      - EXECUTIONS_PROCESS=main
      - GENERIC_TIMEZONE=UTC
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      - postgres

volumes:
  postgres_data:
  n8n_data:

Step 4 — Install Nginx & Certbot

sudo apt install nginx certbot python3-certbot-nginx -y

Create an Nginx config for your domain:

sudo nano /etc/nginx/sites-available/n8n
server {
    listen 80;
    server_name <YOUR_DOMAIN>;

    location / {
        proxy_pass http://localhost:5678;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_read_timeout 86400;
    }
}
sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Step 5 — SSL with Let's Encrypt

Point your domain's A record to the EC2 public IP first, then:

sudo certbot --nginx -d <YOUR_DOMAIN>

Certbot will automatically update your Nginx config to redirect HTTP to HTTPS and add SSL certificates. Auto-renewal is configured by default.

Step 6 — Start n8n

cd ~/n8n
docker compose up -d
docker compose logs -f  # watch for errors

Visit https://YOUR_DOMAIN — you should see the n8n login screen. Log in with the basic auth credentials you set in the compose file.

Step 7 — Production Hardening

Auto-restart on reboot

The restart: always in the compose file handles this for Docker. But also enable Docker to start on boot:

sudo systemctl enable docker

Monitoring with a simple health check

Add a cron job that pings n8n and alerts you via email if it's down:

crontab -e
# Add this line:
*/5 * * * * curl -sf https://<YOUR_DOMAIN>/healthz || echo "n8n DOWN" | mail -s "n8n Alert" you@email.com

Backup PostgreSQL daily

crontab -e
# Add:
0 2 * * * docker exec n8n-postgres-1 pg_dump -U n8n n8n | gzip > ~/backups/n8n-$(date +\%Y\%m\%d).sql.gz

Cost breakdown: t3.small = ~$0.0208/hr × 730 hrs = ~$15/month. Use a t3.micro if you have low workflow volume — drops to ~$7.50/month (or free tier eligible for new accounts).

Common Issues I've Hit

That's the full setup. I've run this stack in production for 6+ months without downtime. If you want me to set this up for you or migrate your existing Zapier workflows to n8n, get in touch.

Hire Me For This

I set up self-hosted n8n on AWS EC2 and build production workflows — fixed price, includes SSL, PostgreSQL, Nginx, and full documentation.