If you’ve been running n8n on your laptop, that’s exactly how you start. But at some point you need this thing running 24/7. Webhooks don’t work if your laptop is closed. Batch jobs don’t run if you’re not online. And once you start hitting the limits on the free cloud plan, or you just want your data on your own server — that’s when n8n self hosting makes sense.
This post walks through how to get n8n running on AWS the right way, for about $15 a month — and set up so it comes back up on its own if the server ever restarts.
📺 Prefer to watch? Full walkthrough on YouTube
Why Self-Host n8n on AWS?
n8n cloud starts at $20 a month. Once your workflows get serious — webhooks, batch jobs, MCP servers — you need something running 24/7, not just when your laptop lid is open. With n8n docker AWS self hosting you get:
- A server that’s always on — webhooks fire, batch jobs run, MCP servers stay alive
- Full data privacy — your workflows live on your own infrastructure
- Around $15 a month on a t3.small — already less than n8n cloud’s entry plan
- No execution limits
What We’re Covering
- Setting up IAM — root account vs IAM user, and why it matters
- Launching and configuring an EC2 instance for n8n
- Connecting to the server without SSH keys using EC2 Instance Connect
- Installing Docker and running n8n with a single command
- Fixing the secure cookie error you’ll hit on first load
Prerequisites
You’ll need an AWS account. If you don’t have one yet, sign up for the AWS free tier — it takes about 2 minutes and you won’t be charged just for signing up.
Step 1: IAM Setup — Do This Before Anything Else
Before touching EC2, get IAM right. This is the security step most n8n self hosting tutorials skip entirely.
Root vs IAM User
When you create your AWS account you get a root account. Think of it as the master key — you use it once to set up, then you put it away. Your IAM user is what you use day to day.
Here’s why this matters: most self-hosting tutorials tell you to create an access key from root and paste it directly into your server as an environment variable. That works — but if that server is ever breached, the attacker now has root-level access to your entire AWS account. Creating an IAM user instead is a small step that makes a big difference.
If your IAM user gets compromised, you can revoke it from root. If root gets compromised — that’s a much bigger problem with no clean recovery.
Create Your IAM User
- Go to AWS Console → IAM → Users → Create User
- Give it a name — something like
admin-user - Attach the
AdministratorAccesspolicy directly - Enable console access and set a password
- Download the credentials CSV
Once done, log out of root and log back in as your IAM user. Do this explicitly — it’s the habit that protects you long term.
Step 2: Launch Your EC2 Instance
EC2 is AWS’s virtual server service. Think of it the same way you’d think about the laptop you were running n8n on locally — except this one runs 24/7 in Amazon’s data center.
Go to AWS Console → EC2 → Launch Instance and configure the following:
| Setting | Value |
|---|---|
| Name | n8n-server |
| AMI | Ubuntu 22.04 LTS |
| Instance type | t3.small |
| Key pair | Proceed without key pair |
Why t3.small and Not Free Tier?
n8n technically runs on a t2.micro but you’ll hit memory pressure fast once you’re running real workflows with multiple nodes. t3.small is around $15 a month — which is already less than n8n cloud’s cheapest plan. That’s kind of the whole point.
Security Group
Create a new security group named n8n-sg with these inbound rules:
| Type | Port | Source |
|---|---|---|
| SSH | 22 | Anywhere 0.0.0.0/0 |
| HTTP | 80 | Anywhere 0.0.0.0/0 |
| Custom TCP | 5678 | Anywhere 0.0.0.0/0 |
Port 22 is required — even though we’re connecting through the browser with EC2 Instance Connect, it still uses SSH under the hood. If port 22 isn’t open you’ll get a Failed to connect error when trying to connect.
Port 5678 is n8n’s default port — that’s how you’ll reach the UI. Port 80 is there for when we add a domain and HTTPS in the next post.
Launch
Click Launch Instance and wait for the status to show Running before moving on.
Step 3: A Note on Elastic IP
Once your instance is running you’ll see a public IP address. That address changes every time the server restarts. For just browsing the UI that’s annoying — but for webhooks it’s a real problem. Whatever service is pointing at that URL won’t know the address changed, and everything breaks.
The fix is Elastic IP — a fixed address that stays attached to your instance across restarts. I’ve written a full walkthrough on setting that up, link is in the description. It’s worth doing before you start pointing real workflows at this server.
Step 4: Connect via EC2 Instance Connect
We’re skipping SSH key files entirely. AWS gives us a cleaner option — EC2 Instance Connect — a browser-based terminal that handles everything automatically.
- Select your instance → click Connect
- Choose the EC2 Instance Connect tab
- Click Connect
A terminal opens right inside your browser. No PuTTY, no .pem files, no local terminal setup needed.
Step 5: Install Docker
Once you’re connected, run:
sudo apt update && sudo apt upgrade -y
sudo apt install docker.io -y
After installation, check the status:
sudo systemctl status docker
On recent Ubuntu installs, Docker enables and starts automatically after install. You should see it as active (running).
Then verify it’s set to come back up on reboot:
sudo systemctl is-enabled docker
This should return enabled. If it doesn’t:
sudo systemctl enable docker
This matters because of how the auto-restart chain works. When the server reboots, systemctl enable brings Docker back up first — and then Docker reads its restart policy and brings n8n back up with it. Both pieces need to be in place:
Server reboots
↓
systemctl enable → Docker starts automatically
↓
--restart unless-stopped → n8n container starts automatically
Step 6: Run n8n with Docker
This is the core of the n8n docker self host setup. One command does everything:
sudo docker run -d \
--name n8n \
--restart unless-stopped \
-p 5678:5678 \
-v n8n_data:/home/node/.n8n \
n8nio/n8n
Here’s what each flag does:
| Flag | What it does |
|---|---|
-d | Runs in background — detached mode |
--name n8n | Names the container for easy reference |
--restart unless-stopped | Auto-restarts n8n if it crashes or the server reboots |
-p 5678:5678 | Maps port 5678 on the server to port 5678 inside the container |
-v n8n_data:/home/node/.n8n | Persists your workflows and credentials to the server’s disk |
The Two Flags You Cannot Skip
--restart unless-stopped is what makes this hands-off. If n8n crashes on its own, Docker sees it went down and brings it straight back up. If the whole server reboots, Docker starts automatically with the server and picks n8n back up from there. Either way you don’t touch anything.
-v n8n_data:/home/node/.n8n is what keeps your data safe. Without this volume mount, every time the container restarts you start from a blank n8n — no workflows, no credentials, nothing. Don’t skip this.
Verify It’s Running
sudo docker ps
You should see the n8n container listed with a status of Up.
Step 7: Fix the Secure Cookie Error
Open your browser and visit:
http://<your-ec2-public-ip>:5678
You’ll likely hit this on first load:
Your n8n server is configured to use a secure cookie, however you are either visiting this via an insecure URL, or using Safari.
n8n defaults to expecting HTTPS — which is correct for production. Since we’re on plain HTTP for now, we need to tell it to relax that temporarily. Stop and remove the current container, then rerun it with N8N_SECURE_COOKIE set to false:
# stop and remove the current container
sudo docker stop n8n
sudo docker rm n8n
# rerun with secure cookie disabled
sudo docker run -d \
--name n8n \
--restart unless-stopped \
-p 5678:5678 \
-e N8N_SECURE_COOKIE=false \
-v n8n_data:/home/node/.n8n \
n8nio/n8n
Your data is safe — removing and recreating the container doesn’t touch the n8n_data volume.
Visit http://<your-ec2-public-ip>:5678 again and the n8n setup screen should load.
Create your owner account and log in.
Step 8: Test Your Instance
Build a quick workflow to confirm everything is wired up — a manual trigger into a Set node is enough. Run it and confirm the execution shows up in the history.
That’s your own n8n. On your own server. Your data, your workflows, nobody else’s cloud. About $15 a month.
What’s Not Production Ready Yet
This setup works — but be honest about what it isn’t:
No fixed IP. That public IP changes every time the server restarts. Set up Elastic IP before pointing real workflows here — full walkthrough linked in the description.
No HTTPS. You’re on plain HTTP. Services like Stripe, GitHub, and Slack will refuse to send webhooks to an unencrypted endpoint — n8n is already telling you that with the cookie error we just fixed. This gets sorted in the next post.
SQLite as the database. n8n uses SQLite internally by default. Fine for personal use and light workflows, but not built for heavy concurrent load. Swapping to Postgres with Docker Compose is covered later in the series.
No backups. If this EC2 instance gets terminated, your workflows go with it. EC2 snapshots and workflow exports are coming in the series.
Updating n8n Later
When a new version drops, updating is two commands:
sudo docker pull n8nio/n8n
sudo docker restart n8n
That’s one of the main reasons the n8n docker AWS approach beats a raw npm install — updates are clean and fast with no dependency mess left behind.
What’s Next
This post is part of a series on self-hosting n8n properly on AWS:
| Post | Topic |
|---|---|
| #1 — This post | EC2 + Docker + n8n running |
| #2 | Domain name + HTTPS + webhooks working |
| #3 | Swap SQLite for Postgres with Docker Compose |
| #4 | Backups — EC2 snapshots and workflow exports |
| #5 | Connect n8n to S3 for file handling in workflows |
If you’re using n8n for anything that talks to external services, post #2 is not optional — HTTPS is required for webhooks to work, and n8n is already telling you that with the error we just fixed.
Questions? Drop them in the comments.