Skip to content

derek-palmer/aws-n8n-docker-tf

Repository files navigation

n8n AWS Infra Template

A low-cost, n8n on AWS stack using modern AWS and Terraform best practices:

It is designed as a template and a solid starting point for real deployments.


Features

  • Environment‑aware Terraform layout

    • infra/terraform/modules for reusable components and infra/terraform/envs/* for env stacks, matching AWS/HashiCorp guidance.
  • Networking and ingress

    • Single‑AZ VPC and public subnet.
    • Production ingress is Route 53 -> Elastic IP -> Caddy -> n8n.
    • Public HTTPS stays on the custom production domain without exposing n8n on port 5678.
    • The active deployment path is one always-on production host; version validation happens locally before prod deploys.
  • Compute

    • EC2 instance running Docker and docker-compose stack (n8n + Postgres).
    • Caddy runs on the host as the public reverse proxy and manages TLS directly on the instance.
    • No SSH exposure. Administration is handled via AWS SSM Session Manager.
  • Config / secrets (per env)

    • AWS SSM Parameter Store hierarchy:
      • /n8n/<env>/app/...
      • /n8n/<env>/db/postgres/...
      • /n8n/<env>/network/allowed-ips-admin
    • App is env‑agnostic; config is injected via environment variables at runtime, mirroring 12-Factor App methodology.
  • Management & patching

    • SSM Patch Manager association for regular OS patching.
    • SSM State Manager association to ensure Docker and the n8n stack stay in the desired state.
  • CI/CD (skeleton)

    • CodeBuild project to build and push Docker images to ECR.
    • CodeDeploy deployment group targeting the n8n EC2 instance.
    • CodePipeline wiring Source → Build → Deploy stages.

Repository structure

n8n-aws-infra-template/
  Makefile
  README.md
  .gitignore
  docker-compose.yml
  docker-compose.local.yml
  docker-compose.aws.yml
  Caddyfile

  scripts/
    fetch_ssm_env.sh       # Pulls /n8n/<env>/... params into .env.<env>
    deploy.sh              # Used by CodeDeploy to restart docker stack on EC2

  infra/
    terraform/
      modules/
        vpc/
        ec2_n8n/
        route53/
        ssm_params/
        iam/
        codebuild/
        codedeploy/
        codepipeline/
        ssm_automation/

      envs/
        test/
          # historical reference only
          backend.tf
          main.tf
          variables.tf
          outputs.tf
        prod/
          backend.tf
          main.tf
          variables.tf
          outputs.tf

You extend the modules as your needs grow.


Getting started

AWS Authentication

Add a login alias to your ~/.zshrc (or ~/.bashrc) so credentials and profile are set in one step:

awslogin() { export AWS_PROFILE=<your-profile>; aws sso login; }

Then just run awslogin before any AWS work. All make and aws commands will pick up the profile automatically.

Tip

For multiple accounts, create one alias per profile:

awslogin-dev()  { export AWS_PROFILE=my-dev;  aws sso login; }
awslogin-prod() { export AWS_PROFILE=my-prod; aws sso login; }

Or, without an alias:

aws sso login --profile <your-profile>
export AWS_PROFILE=<your-profile>

Bootstrap

After cloning this template, run make bootstrap env=prod once. It handles every one-time AWS setup step automatically:

awslogin
make bootstrap env=prod

make bootstrap will:

  1. Check that aws CLI and docker are available and your credentials work.
  2. Create an S3 bucket + DynamoDB table for Terraform remote state (versioned, encrypted).
  3. Create an ECR repository for the n8n Docker image (scan-on-push enabled).
  4. Create all required SSM Parameter Store entries — auto-generates the n8n encryption key and Postgres password for you, prompts only for your domain.
  5. Enable the S3 backend block in infra/terraform/envs/<env>/main.tf.
  6. Write a complete terraform.tfvars for the environment.

Important

One step cannot be automated via CLI: the GitHub CodeStar Connection. The script will pause and give you the direct console link. Takes ~60 seconds to complete in your browser.

After bootstrap, deploy production with:

make tf-init env=prod
make tf-plan env=prod
make tf-apply env=prod ARGS=-auto-approve

Prerequisites

Local tools required to run the bootstrap script and Makefile:

  • AWS account with:

  • Local tools:

  • IAM permissions to manage VPC, EC2, Elastic IPs, Route 53, SSM, IAM, CodeBuild, CodeDeploy, CodePipeline.


Config: SSM Parameter Store hierarchy

Use AWS SSM Parameter Store per env. For local, create parameters like:

/n8n/local/N8N_ENCRYPTION_KEY   (SecureString)
/n8n/local/N8N_HOST             (String)   # localhost
/n8n/local/N8N_PROTOCOL         (String)   # http
/n8n/local/N8N_PORT             (String)   # 5678
/n8n/local/POSTGRES_USER        (SecureString)
/n8n/local/POSTGRES_PASSWORD    (SecureString)
/n8n/local/POSTGRES_DB          (String)

Repeat the pattern for test and prod (with appropriate values — https, real domain, etc.). The leaf segment of each path becomes the env var name injected into the container.

For production, also create:

/n8n/prod/TLS_CONTACT_EMAIL    (String)   # email used by Caddy for ACME registration

Local development

Local dev runs via Docker Compose, but loads config from SSM so it mirrors AWS. Note: Terraform commands run inside Docker; credentials come from your configured AWS SSO profile via the ~/.aws mount.

  1. Log in (see AWS Authentication above):
awslogin
  1. Create /n8n/local/... SSM parameters:
make setup-local

This runs SSM setup and starts the stack in one step. Or run them separately:

make setup-ssm env=local   # just SSM params
make up-local              # just start the stack

This assumes .env.local already exists from make setup-local, then starts docker compose with the local overrides.

To validate an n8n upgrade locally before touching production:

make up-local-version N8N_UPSTREAM_REF=n8nio/n8n:<candidate-version>

To tear down:

make down-local

Terraform environments

make bootstrap env=prod handles the active setup automatically. To deploy manually or understand what's happening under the hood:

# 1. Bootstrap once (creates state bucket, ECR, SSM params, writes tfvars)
make bootstrap env=prod

# 2. Initialize the Terraform workspace
make tf-init env=prod

# 3. Review the plan
make tf-plan env=prod

# 4. Apply
make tf-apply env=prod ARGS=-auto-approve

Terraform will create networking, the Elastic IP-backed production DNS record, EC2, IAM, SSM, and the full CI/CD pipeline.

The test Terraform environment remains in the repo only as historical reference. It is not part of the active documented deployment path.

To update SSM parameters at any time without re-running the full bootstrap:

make setup-ssm env=prod

EC2 access (Session Manager, no SSH)

No SSH port is exposed. Use AWS Systems Manager Session Manager instead.

CLI example:

aws ssm start-session --target <instance-id>

CI/CD (skeleton)

The template includes modules and scripts for:

  • CodeBuild: Build and push Docker images to ECR (you add the buildspec).
  • CodeDeploy: Deployment group for EC2 instance (tagged role=n8n), running scripts/deploy.sh to restart Docker Compose.
  • CodePipeline: Source → Build → Deploy stages wired together (you configure repo, branches, and ECR).

You provide:

  • GitHub/CodeCommit repo details.
  • ECR repo name.
  • Your buildspec.yml and CodeDeploy appspec.yml if you want fully automated deployments.

Security and best practices

This template is intentionally opinionated to show strong defaults:

  • No plaintext secrets in repo: use SSM SecureString.
  • Environment‑specific paths: /n8n/<env>/... per environment.
  • Least privilege IAM:
    • EC2 role can read only its env’s parameters.
    • SSM/logs permissions are limited to what Session Manager and CloudWatch need.
  • No inbound SSH: Session Manager only.
  • Automated patching: SSM Patch Manager keeps OS patched.
  • Modern Terraform: 1.14.x and AWS provider 6.x pinned.

About

Deploy N8N in AWS with Terraform and Docker

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors