Back · Hosting

flyio

Fly.io runs your n8n Docker image on lightweight Firecracker VMs close to your users, with a simple fly.toml config and an attachable Postgres app.

Difficulty
Monthly cost from: ~$5–20/mo

Fly.io runs your n8n Docker image on lightweight Firecracker VMs close to your users, with a simple fly.toml config and an attachable Postgres app.

Prerequisites

  • A Fly.io account
  • flyctl CLI installed
  • A credit card for anything beyond the free allowance

Step-by-step guide

  1. Step 1

    Install flyctl & log in

    Install the CLI and authenticate.

    curl -L https://fly.io/install.sh | sh
    flyctl auth login
  2. Step 2

    Launch a Postgres app

    Create a managed Fly Postgres cluster to attach later.

    flyctl postgres create --name n8n-db
  3. Step 3

    Create fly.toml for n8n

    Point the app at the n8nio/n8n image, expose port 5678, add a persistent volume mount.

    flyctl launch --image n8nio/n8n:latest --name my-n8n
    flyctl volumes create n8n_data --size 3
    flyctl postgres attach n8n-db
  4. Step 4

    Deploy & set secrets

    Set N8N_HOST, WEBHOOK_URL, N8N_ENCRYPTION_KEY as Fly secrets, then deploy.

    flyctl secrets set N8N_HOST=my-n8n.fly.dev N8N_ENCRYPTION_KEY=changeme
    flyctl deploy

Scaling & queue mode

Scale vertically with `flyctl scale vm` (more CPU/RAM) or run multiple Fly Machines across regions for redundancy. For queue mode, deploy a second Fly app running `n8n worker` connected to the same Postgres/Redis.

Backup & upgrade

Fly Postgres supports snapshot-based backups via `flyctl postgres backup`; upgrade n8n by updating the image tag in fly.toml and running `flyctl deploy` again.

Security checklist

  • Always run behind HTTPS (Caddy/Traefik/Nginx + Let's Encrypt) — never expose port 5678 directly.
  • Set a strong, permanent N8N_ENCRYPTION_KEY and back it up (losing it breaks stored credentials).
  • Use Postgres, not the default SQLite, for anything beyond local testing.
  • Enable N8N_BASIC_AUTH or an SSO/proxy layer if the instance is reachable from the internet.
  • Restrict inbound firewall rules to 80/443 (and SSH from your IP only).
  • Keep the n8n image pinned and update on a schedule instead of always using :latest in production.

Cost breakdown

  • shared-cpu-1x VM~$2–5/mo
  • Fly Postgres (single node)~$5–10/mo

Troubleshooting & FAQ

+Can I use SQLite instead of Postgres?

n8n defaults to SQLite, which works for testing but isn't recommended for production: no concurrent writers, harder backups, and risk of corruption under load. Use Postgres for anything real.

+My webhooks return 404 / don't trigger — why?

WEBHOOK_URL must match the public HTTPS URL exactly (including trailing slash), and the workflow must be activated (not just saved) for production webhook URLs to work.

+How do I move from Fly.io to another host later?

Export workflows/credentials with the n8n CLI (`n8n export:workflow --all` / `export:credentials --all`) or the REST API, restore the Postgres dump on the new host, then import.

+Do I lose data if the container restarts?

No, as long as n8n_data and the Postgres volume are mounted as named Docker volumes (not ephemeral container storage), your data persists across restarts and image updates.