Migrating from Zapier to n8n: Docker Setup and Zap Mapping
A practical Zapier-to-n8n migration path: what to audit first, the Docker Compose settings n8n documents for self-hosting, the localhost trap inside containers, and which n8n trigger and action nodes replace common Zaps.
Moving from Zapier to self-hosted n8n is mostly two jobs: running n8n reliably on a server, and rebuilding each Zap as an n8n workflow. This guide covers both. The server settings come from n8n's own self-hosting documentation, and the node mapping only names nodes that have a page in the n8n integration docs.
Step 1: audit the Zaps before rebuilding anything#
Open the Zap list and sort every Zap into one of three groups:
- Still useful: it fires regularly and someone depends on its output.
- Running but unused: it fires, but nobody reads the result (digests nobody opens, duplicates, integrations with tools you have stopped using).
- Broken: expired credentials or a changed API, and it has failed for a while.
Delete the second and third groups in Zapier first. Only the first group needs to move, and a shorter list makes it easier to run both systems side by side during the switch.
For each Zap that stays, write down its trigger app and event, every action, any filter or path logic, and which credentials it uses. That list becomes the build plan in n8n.
Step 2: run n8n with Docker Compose#
n8n's Docker Compose guide runs two containers: n8n, and Traefik as the proxy that obtains TLS certificates. The n8n service in that file sets, among others:
services:
n8n:
image: n8nio/n8n
restart: always
ports:
- "127.0.0.1:5678:5678"
environment:
- N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}
- N8N_PORT=5678
- N8N_PROTOCOL=https
- NODE_ENV=production
- N8N_WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN_NAME}/
- GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
- TZ=${GENERIC_TIMEZONE}
volumes:
- n8n_data:/home/node/.n8n
volumes:
n8n_data:This is an excerpt; copy the full file, including the Traefik service, its labels and the .env values, from the guide. A few points are worth understanding rather than copying blindly:
n8n_datamust be a persistent volume. The guide notes that n8n saves its SQLite database file and encryption key in/home/node/.n8n. Lose the volume and you lose workflows and the key that decrypts stored credentials.GENERIC_TIMEZONEdrives schedules. The Docker install page explains thatTZsets the system timezone whileGENERIC_TIMEZONEsets the timezone for schedule-oriented nodes such as the Schedule Trigger. Set both, for example toEurope/London.- No
N8N_BASIC_AUTH_*variables. Many older Compose files still set them. The v1.0 migration guide states that support for basic auth and JWT authentication was removed in n8n 1.0 and that user management is mandatory. Create the owner account in the UI on first launch. - No
version:key. The official file starts directly atservices:.
Webhook URLs behind a reverse proxy#
Many Zaps start from a webhook, so the URL n8n registers with external services has to be the public one. n8n's page on configuring webhook URLs with a reverse proxy explains why: n8n builds the URL from N8N_PROTOCOL, N8N_HOST and N8N_PORT, but behind a proxy n8n listens on 5678 while the public port is 443. The fix it documents:
export N8N_WEBHOOK_URL=https://n8n.example.com/
export N8N_PROXY_HOPS=1and the last proxy on the request path must pass X-Forwarded-For, X-Forwarded-Host and X-Forwarded-Proto. The Compose guide notes that N8N_WEBHOOK_URL is available from n8n 2.30.0 and that earlier versions use WEBHOOK_URL; the reverse-proxy page adds that WEBHOOK_URL is deprecated from 2.35.0 and logs a warning.
The localhost trap inside Docker#
If a workflow calls a service running on the host itself (a local model server, a database, an internal API), localhost will not reach it from inside the n8n container. n8n's Ollama Chat Model common issues page spells out why: each container has its own localhost. For a service on the host, use host.docker.internal as the address. Docker Desktop configures that name automatically; on Linux, the page shows the docker run flag that maps it:
docker run -it --rm --add-host host.docker.internal:host-gateway \
--name n8n -p 5678:5678 -v n8n_data:/home/node/.n8n n8nio/n8nIf both services run in separate containers, use the other container's name as the host instead.
Step 3: map each Zap to n8n nodes#
n8n workflows follow the same shape as Zaps: one trigger node, then action nodes. The table maps common Zap patterns to nodes that exist in n8n's integration docs.
| Zap pattern | n8n trigger | n8n actions |
|---|---|---|
| New form response → CRM + welcome email | Typeform Trigger or Webhook | Notion, Gmail |
| Payment received → update project + receipt | Stripe Trigger | Notion, Gmail |
| New RSS item → chat notification | RSS Feed Trigger | Slack (Message → Send) |
| New booking → calendar block + confirmation | Calendly Trigger | Google Calendar, Gmail |
| Labelled email → task | Gmail Trigger with the Label Names or IDs filter | Notion |
| Repository event → spreadsheet row | GitHub Trigger | Google Sheets |
| Every Monday → email an agenda | Schedule Trigger | Google Calendar, Gmail |
Filters and paths#
Zapier filters and paths become an If node, which splits items on String, Number, Date & Time, Boolean, Array or Object comparisons and combines conditions with AND or OR. For more than two outputs, the If node documentation points to the Switch node.
Apps without an n8n node#
When an app has no n8n node, the HTTP Request node calls its REST API directly. Its documentation describes importing a curl command from the service's API docs so n8n fills in the method, URL, headers and body. If n8n already has a credential type for the service, choose Predefined Credential Type; otherwise use a generic credential such as Basic auth or Header auth.
Email bodies built in code#
If a Zap assembles an HTML email, build the HTML in a Code node, then set the Gmail node's Email Type to HTML and map the string into Message. The Gmail message operations list Email Type with Text or HTML for sending.
Step 4: test, run in parallel, then switch off Zapier#
- Use test URLs while building. Webhook-based triggers have a Test URL and a Production URL. The Webhook node documentation explains that n8n registers the production webhook when you publish the workflow, and that production runs are not shown live in the editor; you inspect them in the workflow's Executions tab.
- Read executions, not just the final output. Understand executions describes the workflow-level and instance-wide execution lists, and how to copy data from a past execution back into the editor to debug it.
- Run both for a while. Keep the Zap on while the n8n workflow runs in production, compare their outputs, then turn the Zap off. Start with a simple Zap, then move the one that would hurt most if it broke, and leave the rest for later.
- Remove duplicate side effects. While both run, both may send the same email or create the same record. Point one of them at a test destination during the overlap.
Step 5: keep the instance updated#
Self-hosting moves maintenance to you. n8n's update guidance recommends updating frequently, at least once a month, checking the release notes for breaking changes, and testing the update on a separate environment first. For a Compose install, the Docker page gives the sequence:
cd /path/to/your/compose/directory
docker compose pull
docker compose down
docker compose up -dBack up the n8n_data volume before major version jumps, since it holds the database and the encryption key.
Further reading: n8n Lead Capture to Notion: Webhooks, Scoring, Slack Alerts, n8n Beginner Guide 2026: Build Your First Automation, n8n Client Reporting Workflow: ClickUp, Toggl and Gmail.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
One email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
Continue Reading
n8n Client Reporting Workflow: ClickUp, Toggl and Gmail
A step-by-step n8n workflow that reads active clients from Notion, pulls completed ClickUp tasks and Toggl time entries, builds an HTML summary and leaves a Gmail draft per client for review before sending.
n8n Lead Capture to Notion: Webhooks, Scoring, Slack Alerts
A tutorial for a lead pipeline in n8n: capture leads from a form webhook, Gmail and an n8n Form, classify emails with a local model, score each lead, store it in Notion and get a Slack reminder when a lead goes unanswered.
n8n requested webhook is not registered fix
This n8n webhook error is usually not about your payload. It is almost always a test-vs-production URL mixup or an inactive workflow.


