Webhook not triggered from Firecrawl → n8n (self-hosted, pm2, reverse proxy)

Hey everyone,
I’m currently running into a weird issue with my self-hosted stack and could use some help.
Setup:

  • Firecrawl v2 API self-hosted on Ubuntu VPS (Hetzner, Ubuntu 24.04)
  • Running via docker compose (api, redis, postgres, playwright-service)
  • n8n (v1.111.0) installed globally with pm2 (not via Docker)
  • Reverse proxy with Caddy (domain: https://n8napp.alphamindhub.com)
    Problem:
  • When I start a crawl via Firecrawl (POST /v2/crawl), I pass a webhook like:
    "webhook": {
      "url": "https://n8napp.alphamindhub.com/webhook/fc-completed",
      "events": ["completed","failed"],
      "headers": { "x-source": "firecrawl" },
      "metadata": { "site": "https://www.physyo.de" }
    }
    

Firecrawl logs show:
debug [queue-worker:processJob]: Calling webhook with success…
But n8n never receives the request. In the Executions tab I only see test requests (e.g. when I manually POST via PowerShell or curl).
Logs:
Firecrawl side: no errors, just “Calling webhook with success…”.
n8n side (pm2 logs):
pgsql
Code kopieren
Received request for unknown webhook: The requested webhook “POST firecrawl-completed” is not registered.
Also recurring error:
pgsql
Code kopieren
ValidationError: The ‘X-Forwarded-For’ header is set but the Express ‘trust proxy’ setting is false (default).
code: ‘ERR_ERL_UNEXPECTED_X_FORWARDED_FOR’
My workflow is active and production URL is correct. Manually hitting the webhook with Invoke-WebRequest or curl works fine (execution is triggered). It just seems Firecrawl → n8n communication breaks.
Questions:
Is this related to trust proxy / reverse proxy config? (Caddy is handling SSL/TLS).
Does n8n drop/ignore requests if the proxy headers are misconfigured?
Could Firecrawl require a different webhook format (headers, body)?
Any known pitfalls when combining Firecrawl → n8n webhook?
Any pointers would be really appreciated – I’m stuck between the two systems. Firecrawl says “Calling webhook with success…”, but n8n doesn’t register it.
Thanks a lot!

Please share your workflow

Share the output returned by the last node

19 items
success
true
id
a1220a3a-235a-4097-826d-c4dee5f76a87
url
http://91.99.172.36:3002/v2/crawl/a1220a3a-235a-4097-826d-c4dee5f76a87

Update / What I’ve tried since posting

Stack recap

  • Firecrawl v2 API self-hosted (docker compose: api + redis + postgres + playwright)

  • n8n 1.111.0 installed via pm2 (not Docker)

  • Reverse proxy: Caddy on https://n8napp.alphamindhub.com

  • Firecrawl webhook set to production n8n URL:

    https://n8napp.alphamindhub.com/webhook/fc-completed
    
    

1) n8n: Webhook + payload normalization

  • I switched my workflow to use the Production webhook URL only (no “Listen once”, just active workflow).

  • I removed my Code node that was returning an array with a non-object json (which caused
    A 'json' property isn't an object [item 0]).

  • Replaced it with Edit Fields → mapping out a clean item:

    ok       = {{ $json.body.id ? true : false }}
    crawl_id = {{ $json.body.id }}
    url      = {{ $json.body.url || `https://crawl.alphamindhub.com/v2/crawl/${$json.body.id}` }}
    raw      = {{ $json }}
    
    
  • Guard IF: {{$json.ok}} is true AND {{$json.crawl_id || $json.url}} is not empty.

This fixed the n8n validation error and gives me a single, well-formed item downstream.


2) Firecrawl API: status/results endpoint

From POST /v2/crawl I get:

{
  "success": true,
  "id": "d95dbe2f-20dd-4710-808a-ed1a6d0ce48a",
  "url": "https://crawl.alphamindhub.com/v2/crawl/d95dbe2f-20dd-4710-808a-ed1a6d0ce48a"
}

When I try GET /v2/crawl/<id>/results I get 404 (Cannot GET /v2/crawl/<id>/results).
So it looks like there is no /results sub-route. (If anyone can confirm that the correct endpoint is simply GET /v2/crawl/<id> for status + data, that would help.)


3) Reverse proxy / trust proxy

In pm2 logs I was seeing:

ValidationError: The ‘X-Forwarded-For’ header is set but Express ‘trust proxy’ is false.
code: ‘ERR_ERL_UNEXPECTED_X_FORWARDED_FOR’

I addressed this by setting trusted proxies for n8n and HTTPS hints (pm2 env):

N8N_TRUSTED_PROXIES=*,loopback,uniquelocal,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
N8N_PROTOCOL=https
N8N_HOST=n8napp.alphamindhub.com
WEBHOOK_URL=https://n8napp.alphamindhub.com/

(After restart the X-Forwarded-For warning no longer appears.)

For Caddy, I’m just running a plain reverse_proxy to the pm2 n8n port; no special header surgery.


4) Sanity checks

  • Manual POST to https://n8napp.alphamindhub.com/webhook/fc-completed (PowerShell Invoke-WebRequest or curl) correctly triggers the workflow.

  • curl -I (HEAD/GET) to the same URL returns 404 — which is expected for n8n production webhooks (they accept POST, not GET/HEAD).


5) Current behavior / suspected root cause

  • Firecrawl job creation works (200 + id).

  • Firecrawl logs say: Calling webhook with success...

  • But n8n receives no production execution from Firecrawl (only my manual test posts arrive).

So I’m trying to understand:

  1. Does Firecrawl send POST (not GET/HEAD) to the webhook? n8n will 404 on GET/HEAD.

  2. Is there any retry behavior / status code expectation on the Firecrawl side (e.g., requires 2xx within X seconds)?

  3. Can anyone confirm the correct status/results GET endpoint for v2 (is it GET /v2/crawl/<id> and not /results)?

If helpful, here’s a minimal payload I’m sending in POST /v2/crawl (works via shell):

{
  "url": "https://www.physyo.de",
  "maxDiscoveryDepth": 0,
  "limit": 10,
  "ignoreQueryParameters": true,
  "sitemap": "include",
  "crawlEntireDomain": false,
  "allowExternalLinks": false,
  "allowSubdomains": false,
  "scrapeOptions": {
    "formats": ["markdown"],
    "onlyMainContent": true
  },
  "webhook": {
    "url": "https://n8napp.alphamindhub.com/webhook/fc-completed",
    "events": ["completed","failed"],
    "headers": { "x-source": "firecrawl" },
    "metadata": { "site": "https://www.physyo.de" }
  }
}

Any pointers on the webhook call semantics from Firecrawl (method, headers, timing) and the correct GET endpoint for results in v2 would be awesome. Thanks! :folded_hands: