How to host n8n on aws

Nowadays, many individuals and businesses are leveraging n8n to create diverse automation tools and systems. In this article, we will explore about n8n and how to host n8n for personal projects, providing you with the knowledge to take full control of your automation needs and enjoy unlimited executions.

What is n8n

N8n is an open-source automation tool that allows users to connect various applications and services to automate workflows. It provides a flexible and user-friendly platform for creating complex workflows without the need for extensive coding knowledge. With n8n, users can streamline processes, enhance productivity, and integrate different systems to work together seamlessly.

You can visit n8n github for open sourced version of N8N.

Why to host n8n locally

  1. N8n only provides 14 days of free trial of pro plans of n8n cloud SaaS. After which you are redirected to upgrade to a paid account. Failing to do so can lead to your data being deleted after warnings.

  2. Even the lowest paid plans of n8n costs around 20 euros a month (starter pack paid yearly) whereas we can do better in even lesser price.

  3. So choose n8n hosted locally if you want to use it for your personal projects, lower budget, unlimited executions, better data privacy (resides in your local machine) and to learn something new (how to host a local n8n).

Minimum requirements

Althrough we can run it on lower ends but for the proper and smooth functionality of the program, minimum requirements to run n8n for personal projects would be 2GBs of RAM 2 vCPUs and 20 GB SSD.

Why use lightsail and not ec2?

Since you are configuring it for your personal projects and use cases, lightsail offers several benefits over ec2 instance like:

  1. Fixed pricing with no surprise - Unlike ec2, it is fixed and pre calculated as it is not automatically scalable, perfect for our use case.

  2. Pre-configured networking and firewall settings - Unlike ec2 all firewalls are preconfigured like port 22 and 80.

  3. More simplified - Unlike ec2 it is more rigid and provides less configurable parts and more preconfigured parts. So it is faster to setup than ec2 and all it takes is to start the instance.

  4. FIrst 90 days free for our case - Unlike ec2, lightsail provides with basic requirements in the free tier to run the n8n locally. Whereas ec2 provides t2.mirco for free 12 months, it is not sufficient to run n8n freely.

Setup dockerized container with N8N application

  1. Create a lightsail with linux, os only and ubuntu (most used configuration). Select 2 GBs RAM, 2 vCPUs ane 60 GB SSD (free for 90 days).

  2. Go to networking tab and attach a static IP to the instance. (Otherwise the IP would be changed everytime the instance is restarted).

  3. Connect to the instance using either browser or your own SSH client.

  4. Install docker and docker compose in the system and create a folder for n8n

     # Update system packages
     sudo apt update && sudo apt upgrade -y
    
     # Install Docker using the official script (includes docker compose plugin)
     curl -fsSL https://get.docker.com -o get-docker.sh
     sudo sh get-docker.sh
    
     # Optional: Add your user to the docker group to avoid using 'sudo'
     sudo usermod -aG docker $USER
     newgrp docker  # or log out and log back in
    
    
     # Test Docker Compose (new CLI plugin)
     docker compose version
    
     # Create a folder for n8n
     mkdir -p ~/n8n-docker
    
     # move into the newly created folder
     cd ~/n8n-docker
    
     mkdir n8n-data postgres-data
    
     sudo chown -R 1000:1000 ./n8n-data
     sudo chown -R 999:999 ./postgres-data
    
  5. Either you can directly run docker command to create a container out of the latest n8n image online, or you can use docker-compose method to run a series of containers (recommended). Below is the docker compose method. Inside of your newly created folder n8n-docker and create a file called docker-compose.yml and save the given content there.

     version: '3.8'
     services:
       nginx:
         image: nginx:alpine
         restart: unless-stopped
         ports:
           - "80:80"
         volumes:
           - ./nginx.conf:/etc/nginx/nginx.conf
         depends_on:
           - n8n
       postgres:
         image: postgres:13
         restart: unless-stopped
         environment:
           POSTGRES_DB: ${POSTGRES_DB}
           POSTGRES_USER: ${POSTGRES_USER}
           POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
         volumes:
           - ./postgres-data:/var/lib/postgresql/data
         healthcheck:
           test: ['CMD-SHELL', 'pg_isready -h localhost -U ${POSTGRES_USER} -d ${POSTGRES_DB}']
           interval: 5s
           timeout: 5s
           retries: 10
       n8n:
         image: n8nio/n8n
         restart: unless-stopped
         extra_hosts:
           - "host.docker.internal:host-gateway"
         environment:
           - DB_TYPE=postgresdb
           - DB_POSTGRESDB_HOST=postgres
           - DB_POSTGRESDB_PORT=5432
           - DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
           - DB_POSTGRESDB_USER=${POSTGRES_USER}
           - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
           - N8N_HOST=${LIGHTSAIL_IP}
           - WEBHOOK_URL=http://${LIGHTSAIL_IP}
           - N8N_BASIC_AUTH_ACTIVE=${N8N_BASIC_AUTH_ACTIVE}
           - N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER}
           - N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD}
           - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
           - N8N_RUNNERS_ENABLED=${N8N_RUNNERS_ENABLED}
           - N8N_PROXY_HOPS=1
           - N8N_SECURE_COOKIE=false # This is only for HTTP requests
         volumes:
           - ./n8n-data:/home/node/.n8n
         depends_on:
           postgres:
             condition: service_healthy
    

    Now create two folders for volumes as mentioned in the yml file: postgres-data and n8n-data.

    This docker-compose file creates containers for postgres, n8n and nginx (as reverse proxy).

  6. Create a .env file with something like this (add proper values there):

     # PostgreSQL Configuration
     POSTGRES_USER=your_postgres_user
     POSTGRES_PASSWORD=your_postgres_password
     POSTGRES_DB=n8n
    
     # n8n Configuration
     LIGHTSAIL_IP=your_lightsail_public_ipv4_address  #For example 123.45.67.890
     N8N_BASIC_AUTH_ACTIVE=true
     N8N_BASIC_AUTH_USER=your_n8n_user
     N8N_BASIC_AUTH_PASSWORD=your_n8n_password
     N8N_RUNNERS_ENABLED=true
    
     # General Settings
     GENERIC_TIMEZONE=Asia/Kolkata
    
  7. Create a nginx.conf file in the same location as docker-compose.yml to look like this:

     events {
         worker_connections 1024;
     }
    
     http {
         upstream n8n {
             server n8n:5678;
         }
    
         server {
             listen 80;
             server_name _;
    
             client_max_body_size 50M;
    
             location / {
                 proxy_pass http://n8n;
                 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;
    
                 # to support websockets connections required for n8n
                 proxy_http_version 1.1;
                 proxy_set_header Upgrade $http_upgrade;
                 proxy_set_header Connection "upgrade";
             }
         }
     }
    
  8. Run the docker compose

     docker compose up -d
    

You can now access it from your browser by going to http://your-lightsail-ip and you would see something like this:

Potential risks of HTTP

This instance that we just started is only advisable for development environment and personal use. You should always consider upgrading to HTTPS over HTTP.

Advantages of HTTPS over HTTP:

  • Https encrypts all the communication between client and server, which also include your API keys used in the n8n workflows. Using unencrypted keys in HTTP may lead to security leaks.

  • HTTPS uses SSL certificate that are issued by a trusted certificate authority.

  • Many browsers block or warn against accessing HTTP sites.

How to set up HTTPS in the existing setup?

Prerequisite:

You need to buy a domain name in order to setup https request because SSL/TLS certificates are issued for domain names.

Steps required:

  • Buy a domain name if you don’t have one already.

  • Create a dns record to point to your lightsail public ip-address.

  • Update the .env file to add DOMAIN_NAME variable

      # remove this line:
      LIGHTSAIL_IP=your_lightsail_public_ipv4_address
    
      # add this line instead:
      DOMAIN_NAME=subdomain.domain.com     # domain name you registed in your dns record
    
  • Update docker-compose.yml to change the nginx configuration

      # Replace the nginx configuration with this.
      nginx:
        image: nginx:alpine
        restart: unless-stopped
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - ./nginx.conf:/etc/nginx/nginx.conf
          - ./ssl:/etc/nginx/ssl
        depends_on:
          - n8n
    

    Also update n8n environment variable

      # Replace these lines in n8n service:
      - N8N_HOST=${LIGHTSAIL_IP}
      - WEBHOOK_URL=http://${LIGHTSAIL_IP}
      - N8N_SECURE_COOKIE=false # This is only for HTTP requests
    
      # With these:
      - N8N_HOST=${DOMAIN_NAME}
      - WEBHOOK_URL=https://${DOMAIN_NAME}
      - N8N_SECURE_COOKIE=true
    

    Here is the updated docker-compose.yml file:

      version: '3.8'
      services:
        nginx:
          image: nginx:alpine
          restart: unless-stopped
          ports:
            - "80:80"
            - "443:443"
          volumes:
            - ./nginx.conf:/etc/nginx/nginx.conf
            - ./ssl:/etc/nginx/ssl
          depends_on:
            - n8n
        postgres:
          image: postgres:13
          restart: unless-stopped
          environment:
            POSTGRES_DB: ${POSTGRES_DB}
            POSTGRES_USER: ${POSTGRES_USER}
            POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
          volumes:
            - ./postgres-data:/var/lib/postgresql/data
          healthcheck:
            test: ['CMD-SHELL', 'pg_isready -h localhost -U ${POSTGRES_USER} -d ${POSTGRES_DB}']
            interval: 5s
            timeout: 5s
            retries: 10
        n8n:
          image: n8nio/n8n
          restart: unless-stopped
          extra_hosts:
            - "host.docker.internal:host-gateway"
          environment:
            - DB_TYPE=postgresdb
            - DB_POSTGRESDB_HOST=postgres
            - DB_POSTGRESDB_PORT=5432
            - DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
            - DB_POSTGRESDB_USER=${POSTGRES_USER}
            - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
            - N8N_HOST=${DOMAIN_NAME}
            - WEBHOOK_URL=http://${DOMAIN_NAME}
            - N8N_BASIC_AUTH_ACTIVE=${N8N_BASIC_AUTH_ACTIVE}
            - N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER}
            - N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD}
            - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
            - N8N_RUNNERS_ENABLED=${N8N_RUNNERS_ENABLED}
            - N8N_PROXY_HOPS=1
            - N8N_SECURE_COOKIE=true
          volumes:
            - ./n8n-data:/home/node/.n8n
          depends_on:
            postgres:
              condition: service_healthy
    
  • Replace the whole nginx.conf with this new nginx.conf:

      events {
          worker_connections 1024;
      }
    
      http {
          upstream n8n {
              server n8n:5678;
          }
    
          # Redirect HTTP to HTTPS
          server {
              listen 80;
              server_name exp.tilakr.dev;
              return 301 https://$server_name$request_uri;
          }
    
          # HTTPS server
          server {
              listen 443 ssl;
              server_name exp.tilakr.dev;
    
              ssl_certificate /etc/nginx/ssl/fullchain.pem;
              ssl_certificate_key /etc/nginx/ssl/privkey.pem;
    
              ssl_protocols TLSv1.2 TLSv1.3;
              ssl_ciphers HIGH:!aNULL:!MD5;
    
              client_max_body_size 50M;
    
              location / {
                  proxy_pass http://n8n;
                  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;
    
                  # To support websockets connection required for n8n
                  proxy_http_version 1.1;
                  proxy_set_header Upgrade $http_upgrade;
                  proxy_set_header Connection "upgrade";
              }
          }
      }
    
  • Install certbot and get SSL certificate:

      # Stop the containers first
      docker compose down
    
      # Install Certbot
      sudo apt update
      sudo apt install certbot -y
    
      # Create SSL directory
      mkdir -p ~/n8n-docker/ssl
    
      # Get SSL certificate (replace with your email)
      sudo certbot certonly --standalone \
        --email your-email@example.com \
        --agree-tos \
        --no-eff-email \
        -d exp.tilakr.dev
    
      # Copy certificates to your project directory
      sudo cp /etc/letsencrypt/live/exp.tilakr.dev/fullchain.pem ~/n8n-docker/ssl/
      sudo cp /etc/letsencrypt/live/exp.tilakr.dev/privkey.pem ~/n8n-docker/ssl/
      sudo chown $USER:$USER ~/n8n-docker/ssl/*
    
      # Start the containers
      cd ~/n8n-docker
      docker compose up -d
    
  • Setup automatic certificate renewal:

      # Edit crontab
      crontab -e
    
      # Add this line to renew certificates automatically:
      0 3 * * * sudo certbot renew --quiet && sudo cp /etc/letsencrypt/live/exp.tilakr.dev/*.pem ~/n8n-docker/ssl/ && sudo chown $USER:$USER ~/n8n-docker/ssl/* && cd ~/n8n-docker && docker compose restart nginx
    

Important:

Remember to edit the IPV4 firewall for your lightsail instance and add a new rule for port 443 (https), else you won't be able to access through HTTPS.

You can now visit https://DOMAIN_NAME (DOMAIN_NAME is the one you registered in your DNS to point to the IP of the instance).

Congratulations 🎉, you just setup a remote n8n in aws which you can access over HTTPs.

Cloudflare extra security (Optional)

You can also use cloudflare as an extra layer of added security. You can follow the steps below to setup cloudflare:

  1. Add your domain to cloudflare

    - Sign up / Log in into cloudflare account.

    - Click “Add a site“

    - Enter your domain and select free plan.

  2. DNS record import

    - Cloudflare will automatically import your dns records

    - Important : Check if your your A record pointing to your lightsail ip is there or not with proxy enabled (orange cloud)

  3. Update nameservers

    - Update the nameservers in your domain manager with the nameservers provided by the cloudflare.

    - The propagation could take upto 48 hours

  4. Security optimizations

    - In cloudflare dashboard → SSL/TLS → Overview, set encryption mode to Full(Strict)

    - Go to security section → set Security Level: Medium, Bot Fight Mode: On

You have just added cloudflare as an extra layer of security for your setup.

Firewall considerations (Optional)

You can add/modify firewall settings for further better security.

For example ssh is open for all IPs by default. Althrough it requires ssh keys to connect to the instance, you can further restrict the ssh by setting port 22 to only be accessible to a specific IP or a range of IPs.

Important :

Idle static IPs are subject to charge. Until a static IP is connected to an instance, it is free but as soon as you delete the instance or by any means detach the static IP and it becomes idle it will be charged. So it is better to just delete any idle static IPs to avoid any surprise charge!!

So you have just setup your n8n application which you could access through HTTPs connection. You can have unlimited executions and your data is also secured. Enjoy creating some amazing automations 🤖🤖 .

2
Subscribe to my newsletter

Read articles from Tilak raj Choubey directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Tilak raj Choubey
Tilak raj Choubey