Why self-host your automation engine
No-code/low-code automation platforms like Zapier or Make bill per execution and impose quotas that quickly balloon. By self-hosting n8n or Node-RED on a VPS, you remove these limits: unlimited number of executions, data that never leaves your server, and full access to community nodes. n8n is oriented toward application integrations (CRM, databases, AI, webhooks) with a visual workflow logic close to Make. Node-RED, from IBM, manipulates JSON messages via an event-flow system, perfect for wiring up MQTT sensors, transforming payloads or orchestrating hardware. Both run in a container and are driven from a browser.
What you gain by self-hosting
- Unlimited executions with no per-task billing, unlike automation SaaS.
- Data and secrets (API tokens, credentials) stored exclusively on your VPS.
- Access to community nodes/integrations not available in restricted cloud offerings.
- The ability to run custom code (JavaScript, Python) with no sandbox restriction.
- Direct integration with your internal services via the private Docker network.
- Full control of versions and updates, with no imposed price change.
Scroll the table
| Criterion | n8n | Node-RED |
|---|---|---|
| Main use case | SaaS API integration, business workflows | IoT, MQTT, real-time stream processing |
| Execution model | Triggered workflow (cron, webhook, trigger) | Message-oriented event flow |
| Integration catalog | 400+ ready-to-use application nodes | Node library via the community palette |
| Custom code | Built-in Code nodes (JS/Python) | Function nodes in JavaScript |
| Database | SQLite by default, PostgreSQL recommended | JSON files on disk |
| Recommended RAM | 1 to 2 GB | 512 MB to 1 GB |
| License | Sustainable Use License (fair-code) | Apache 2.0 |
| Learning curve | Accessible, geared toward non-developers | Flow logic, more technical |
Prerequisites depending on the tool chosen
For n8n, plan for a VPS with 2 vCPU and 2 GB of RAM, and above all PostgreSQL rather than SQLite as soon as you exceed a few active workflows: SQLite locks the database under concurrent load. Count on 5 GB of disk for the database and the execution binaries. Node-RED is more frugal: 1 vCPU and 1 GB of RAM are enough, its flows being stored in simple JSON files. In both cases: Docker Compose v2, a dedicated subdomain (n8n.mydomain.com or flows.mydomain.com) and an HTTPS reverse proxy are indispensable, because these interfaces expose secrets and must never run over plain HTTP.
Deploy n8n (or Node-RED) on your VPS
Provision Docker and the network
On the VPS, create a dedicated Docker network:
docker network create automation. It will isolate n8n/Node-RED from the database and the reverse proxy.Start PostgreSQL for n8n
In the docker-compose, add a
postgres:16service with a persistent volume and credentials as environment variables. For Node-RED, this step is unnecessary: adata:/datavolume is enough.Configure the application container
For n8n, use the
docker.n8n.io/n8nio/n8nimage withN8N_HOST,WEBHOOK_URL=https://n8n.mydomain.com/andDB_TYPE=postgresdb. For Node-RED, thenodered/node-red:latestimage exposed on port1880is enough.Start and verify
Run
docker compose up -d. n8n listens on5678, Node-RED on1880. Check the logs withdocker compose logs -fand confirm that the database is properly connected for n8n.Secure behind a reverse proxy
Route the traffic through Caddy or Traefik with an automatic Let's Encrypt certificate. Enable authentication:
N8N_BASIC_AUTH_ACTIVE=truefor n8n, and theadminAuthdirective insettings.jsfor Node-RED. Without this, the editor is publicly accessible.Set up backups
Schedule a daily
pg_dumpfor the n8n database, or a simple snapshot of the/datavolume for Node-RED, deposited on external storage viacron.
For n8n in production, enable queue mode with Redis and separate worker containers: the main process then only orchestrates, while the workers execute the nodes in parallel. You thus absorb webhook spikes without blocking the editor. On the Node-RED side, isolate the Function nodes in a VM context with a restricted functionGlobalContext to prevent a poorly written flow from crashing the whole runtime.