10 min leestijdIntegraties

Zelfgehoste n8n-linkautomatisering: van Docker tot webhooks

Draai zelfgehoste n8n-linkautomatisering met Elido-webhooks, Docker Compose en wachtrijmodus, met workflowdata op eigen infrastructuur in de EU.

Marius Voß
DevRel · edge infra

Zelfgehoste n8n-automatisering voor links betekent drie dingen op servers die je zelf beheert: een n8n-instantie in Docker, een openbaar HTTPS-endpoint dat Elido-webhookevents ontvangt en uitgaande aanroepen naar de Elido-API met een token met beperkt bereik. Link- en domeinevents komen ondertekend binnen en events per klik staan op de roadmap. Je workflows bepalen wat er daarna gebeurt en de uitvoeringslogs verlaten je infrastructuur nooit.

Dat is de hele architectuur. De rest van dit artikel is het deel dat de quickstarts overslaan: hoe je webhooks door een reverse proxy krijgt, hoe je de handtekening controleert zodat een vreemde je workflows niet kan starten, wat de wachtrijmodus verandert en wanneer n8n Cloud eerlijk gezegd de betere keuze is. Ik draai deze opzet op één kleine VM en de bewegende delen passen op één scherm.

Wil je ook de links zelf op je eigen hardware, dan is dat een aparte en veel grotere klus. Het draaiboek voor Elido zelf hosten op k3s behandelt dat. Hier blijft Elido beheerd en verhuist alleen de automatiseringslaag naar je eigen huis.

Waarom n8n zelf hosten voor linkautomatisering

De gebruikelijke reden is data. Een workflow met een zelfgehoste n8n en een URL-verkorter ziet elke payload die hij verwerkt: de bestemmings-URL, tags, soms een campagnenaam die meer zegt dan je zou willen, en land, apparaat en referrer als je klik-analytics erin haalt. Bij n8n Cloud staan die uitvoeringen op andermans servers onder andermans standaard bewaartermijnen. Zelfgehost staan ze in je eigen Postgres, in de regio die jij koos.

Onder artikel 28 van de AVG heeft elke verwerker die persoonsgegevens aanraakt een contract nodig en een plek in je registers. Minder verwerkers, minder papierwerk. Moet je marketingdata al in de EU blijven, dan legt de gids voor dataresidentie in de EU uit waarom de automatiseringslaag net zo zwaar telt als de verkorter.

De tweede reden is de kostenvorm. n8n Cloud rekent per uitvoering en een drukke webhooktrigger of een frequente analytics-poll verbruikt uitvoeringen snel. Zelfgehost is een uitvoering een rij in een tabel en een paar milliseconden CPU.

De derde is bereik. Een zelfgehoste instantie staat op hetzelfde netwerk als je CRM-database of interne ticketingtool, dus een linkevent kan terechtkomen in een systeem dat nooit voor internet bedoeld was.

De Docker Compose-stack

Een minimale stack voor n8n-linkautomatisering met Docker heeft vier services nodig. De eigen Docker Compose-gids van n8n is de referentie; dit is de versie waar ik voor linkwerk mee zou beginnen, met de wachtrijmodus al aan zodat je later niet hoeft te migreren.

services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_USER: n8n
      POSTGRES_PASSWORD: ${PG_PASSWORD}
      POSTGRES_DB: n8n
    volumes: [pgdata:/var/lib/postgresql/data]

  redis:
    image: redis:7

  n8n:
    image: docker.n8n.io/n8nio/n8n
    env_file: .env.n8n
    ports: ["127.0.0.1:5678:5678"]
    depends_on: [postgres, redis]

  n8n-worker:
    image: docker.n8n.io/n8nio/n8n
    command: worker
    env_file: .env.n8n
    depends_on: [n8n]

volumes:
  pgdata:

En het gedeelde omgevingsbestand:

DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=postgres
DB_POSTGRESDB_USER=n8n
DB_POSTGRESDB_PASSWORD=change-me
EXECUTIONS_MODE=queue
QUEUE_BULL_REDIS_HOST=redis
N8N_ENCRYPTION_KEY=generate-a-long-random-string
N8N_WEBHOOK_URL=https://n8n.example.com/
N8N_PROXY_HOPS=1

Twee regels tellen zwaarder dan ze lijken. De versleutelingssleutel moet op het hoofdproces en elke worker identiek zijn, anders kunnen workers de Elido-credential niet ontsleutelen en mislukt elke uitvoering met een verwarrende authenticatiefout. En poort 5678 is alleen aan localhost gebonden, omdat de reverse proxy het enige is dat naar internet mag kijken.

Architectuur van zelfgehost n8n voor linkautomatisering: Elido stuurt ondertekende webhooks via HTTPS naar een reverse proxy, die doorstuurt naar het n8n-hoofdproces, dat uitvoeringen in Redis in de wachtrij zet voor workers met Postgres als opslag, terwijl de workers de Elido API uitgaand aanroepen met een token met beperkte rechten

De Elido-API aanroepen vanuit zelfgehoste n8n

Uitgaande aanroepen hebben niets nodig buiten wat n8n meelevert. Maak een Header Auth-credential met de naam Authorization en als waarde Bearer gevolgd door een API-sleutel uit het Elido-dashboard en gebruik die vanuit de ingebouwde HTTP Request-node. n8n versleutelt hem in rust met de sleutel uit het omgevingsbestand, een reden te meer dat die sleutel overal moet overeenkomen.

Elke linkroute is gebonden aan een werkruimte. Om een URL te verkorten, doe je een POST naar https://api.elido.app/v1/workspaces/{workspace_id}/links met een JSON-body:

{
  "domain_id": 12,
  "destination_url": "{{ $json.url }}",
  "title": "Spring launch",
  "tags": ["n8n", "spring"]
}

Laat slug weg en Elido genereert er een. De domain_id is het korte domein waarop de link leeft; een GET naar /v1/workspaces/{workspace_id}/domains toont die van jou en ik zou de ID in de workflow vastzetten in plaats van hem bij elke run op te zoeken. Een GET op dezelfde linkroute toont links en met PATCH /v1/workspaces/{workspace_id}/links/{link_id} wijzig je achteraf een bestemming of tags.

Zet een Idempotency-Key-header op de POST, opgebouwd uit iets stabiels in het triggerende item, zoals een rij-ID. Probeert n8n de node na een timeout opnieuw, dan speelt de API het eerste antwoord opnieuw af in plaats van een tweede link aan te maken. De quickstart voor API en SDK's behandelt de rest van het oppervlak en de pagina over API en SDK's is er als je later liever een stap naar code verplaatst.

Er is ook een verpakte community node, n8n-nodes-elido, bedoeld om deze aanroepen in een vriendelijker vorm te verpakken. Hij staat op npm (versie 0.2.0) maar is nog optioneel, en omdat het geen geverifieerde node is, installeert hij alleen op zelfgehoste n8n, wat de opzet is die dit artikel toch al aanneemt. Houd de HTTP Request-versie als basis. Installeer je toch community-pakketten in wachtrijmodus, bedenk dan dat de GUI alleen in de hoofdcontainer installeert; workers zien hem nooit. Vanaf n8n 2.21 lost de route via installatie met omgevingsvariabelen dat op door bij het opstarten elke container af te stemmen, al verwijdert die bij de eerste keer alles wat niet op de lijst staat.

Elido-webhooks door je reverse proxy krijgen

Events stromen de andere kant op. Elido stuurt link.created, link.updated en domain.verified (onder andere) naar een endpoint dat je registreert onder Settings, Webhooks, en op zelfgehoste n8n is dat endpoint de productie-URL van een Webhook-node. Een event per klik, click.created, staat op de roadmap maar is nog niet opgeleverd, dus klikdata komt voorlopig uit een geplande pull van de analytics-API. De volledige eventlijst en payloadvormen staan in de referentie webhooks voor linkevents.

Achter een proxy bouwt n8n zijn webhook-URL op uit zijn eigen protocol, host en poort, wat betekent dat hij graag http://localhost:5678/webhook/... bekendmaakt aan wie erom vraagt. De pagina over de reverse-proxyconfiguratie is kort en het waard om helemaal te lezen: zet N8N_WEBHOOK_URL op je openbare adres, zet N8N_PROXY_HOPS=1 en laat de laatste proxy X-Forwarded-For, X-Forwarded-Host en X-Forwarded-Proto doorsturen. Oudere gidsen zeggen WEBHOOK_URL; huidige releases lezen die nog wel maar loggen een waarschuwing over verouderd gebruik.

Nginx, Traefik, wat je al draait is prima. Wat telt is TLS aan de openbare kant en dat het pad /webhook/* ongemoeid bij n8n aankomt.

Eén timingdetail kostte mij tijd. Elido wacht tien seconden op een antwoord voordat hij een bezorging als mislukt telt. Een workflow die naar een trage spreadsheet-API schrijft en dan antwoordt, kan daar doorheen schieten, opnieuw worden geprobeerd en dezelfde rij twee keer schrijven. Zet de Webhook-node op direct antwoorden en doe het werk daarna.

Bouw je dit voor een klant en wil je dat de webhookkant voor je wordt geregeld, dan toont de functiepagina over webhooks waarop je je kunt abonneren voordat je iets bouwt.

De handtekening controleren voordat er iets draait

Een openbare webhook-URL is een openbare URL. Wie hem vindt, kan een nep-event POSTen en je workflow starten, dus de eerste node na de trigger moet een handtekeningcontrole zijn.

Elke bezorging van Elido draagt X-Webhook-Signature (waarde v1= plus een hex-digest), X-Webhook-Timestamp in Unix-seconden, X-Webhook-Event en X-Webhook-Delivery. De digest is HMAC-SHA256 over de timestamp, een punt en de ruwe requestbody, met als sleutel het whsec_-geheim dat eenmalig wordt getoond wanneer je het endpoint aanmaakte.

Zet eerst Raw Body aan op de Webhook-node. Dat is de stap die mensen overslaan. Hash je JSON.stringify($json.body) in plaats van de exacte bytes die Elido stuurde, dan verschillen sleutelvolgorde of witruimte en mislukt elke handtekening, en je brengt een avond door in de overtuiging dat het geheim fout is. Dan een Code-node:

const crypto = require("crypto");
const item = $input.first();
const h = item.json.headers;
const raw = (await this.helpers.getBinaryDataBuffer(0, "data")).toString(
  "utf8",
);

const ts = Number(h["x-webhook-timestamp"]);
if (Math.abs(Date.now() / 1000 - ts) > 300) throw new Error("stale delivery");

const expected =
  "v1=" +
  crypto
    .createHmac("sha256", $env.ELIDO_WEBHOOK_SECRET)
    .update(`${ts}.${raw}`)
    .digest("hex");
const got = h["x-webhook-signature"] || "";
if (
  got.length !== expected.length ||
  !crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected))
) {
  throw new Error("bad signature");
}
return [{ json: JSON.parse(raw) }];

De crypto-module is standaard beschikbaar in de Code-node, dus daar is geen extra configuratie nodig. Het venster van vijf minuten blokkeert het opnieuw afspelen van een onderschept verzoek. Wanneer je het geheim vervangt, stuurt Elido tijdens de overgangsperiode ook X-Elido-Signature-Previous, zodat je beide sleutels kunt accepteren terwijl je de variabele bijwerkt. De gids voor het controleren van webhookhandtekeningen heeft een versie van deze node die beide headers controleert, plus dezelfde controle in Node, Python en Go.

Controle van de webhookhandtekening in zelfgehost n8n: lees de tijdstempel en de ruwe body, weiger leveringen ouder dan 300 seconden, bereken HMAC-SHA256 opnieuw over tijdstempel, punt en ruwe body met het endpointgeheim, vergelijk in constante tijd en voer dan de workflow uit of stop de uitvoering

Wachtrijmodus en nieuwe pogingen

Met de handtekeningcontrole op zijn plek is de resterende vraag wat er gebeurt onder belasting of als iets uitvalt. Er spelen twee systemen voor nieuwe pogingen, en ze dekken verschillende storingen.

In de wachtrijmodus van n8n ontvangt het hoofdproces de webhook, maakt een uitvoering aan en geeft de ID aan Redis; workers pakken hem op. Een piek aan events hoopt zich op in de wachtrij in plaats van het HTTP-antwoord te laten haperen. Voor meer inkomend volume kun je aparte webhookprocessors achter een load balancer zetten, al is voor de meeste linkworkloads één hoofdproces en twee workers ruim voldoende.

De kant van Elido vangt op dat n8n onbereikbaar is. Elk niet-2xx-antwoord of elke timeout wordt na 1, 5 en 15 minuten opnieuw geprobeerd; na drie pogingen wordt de bezorging als mislukt gemarkeerd en kun je hem vanuit het dashboard opnieuw inplannen. Dat dekt een herstart van een container of een snelle deploy. Het dekt geen storing van een weekend, en daarom zou ik webhooks koppelen aan een nachtelijke afstemming die links via de API oplijst, zoals het artikel webhooks versus pollen bepleit.

Gebruik X-Webhook-Delivery als idempotentiesleutel. Nieuwe pogingen hergebruiken hem.

Zelfgehoste n8n versus n8n Cloud: eerlijke afwegingen

Ik geef de voorkeur aan zelf hosten hiervoor, maar ik heb teams er spijt van zien krijgen. Hier is de vergelijking zonder verkooppraatje van beide kanten.

AandachtspuntZelfgehoste n8nn8n Cloud
Waar uitvoeringsdata staatJe eigen servers, je eigen regio, je eigen bewaartermijnDe infrastructuur en standaarden van n8n
Interne systemen bereikenZelfde netwerk als je CRM en databasesAlleen wat je openbaar maakt
Openbare webhook-URL en TLSJij draait de proxy en de certificatenMeegeleverd
Upgrades, back-ups, patchenJouw taak, elke maandGeregeld
Kosten bij hoog eventvolumeVaste serverkostenSchaalt met uitvoeringen

De laatste rij snijdt aan twee kanten. Een kleine VM is goedkoop, maar een uur van een engineer aan een mislukte upgrade niet, en n8n brengt vaak releases uit. Heeft niemand in het team de machine in beheer, dan is Cloud met de HTTP Request-node en de REST-API van Elido de verstandiger keuze, en de recepten voor Make en IFTTT of de Zapier-gids laten zien hoe dat beheerde pad op andere platformen eruitziet.

Wat ik je niet kan zeggen, is of je functionaris voor gegevensbescherming een zelfgehoste machine eenvoudiger zal vinden dan een verwerkersovereenkomst met een leverancier. Naar mijn ervaring wel, maar dat hangt af van hoe goed de machine wordt beheerd. Hoe het contract aan de kant van de verkorter werkt, vind je het best in de AVG-gids voor URL-verkorters. En ben je klaar om de eerste workflow aan te sluiten, pak dan een API-token in een werkruimte en laat een Webhook-node ernaar wijzen.

Verwant op de blog

Veelgestelde vragen

Kan ik een URL-verkorter gebruiken met zelfgehoste n8n?

Ja. Zelfgehoste n8n kan elke verkorter met een REST-API aanroepen via de ingebouwde HTTP Request-node. Voor Elido betekent dat een Header Auth-credential met je API-sleutel en een POST naar de links-route van de werkruimte. Binnenkomende events zoals link.created komen binnen via de ingebouwde Webhook-node van n8n, die een openbare HTTPS-URL nodig heeft. Een event per klik, click.created, staat gepland maar is nog niet beschikbaar.

Hoe installeer ik community nodes op zelfgehoste n8n?

Gebruik op één instantie Settings, dan Community Nodes, en plak de npm-pakketnaam. In wachtrijmodus bereikt de GUI-installatie je workers niet, dus installeer het pakket in elke container of vermeld het vanaf n8n 2.21 in N8N_COMMUNITY_PACKAGES met N8N_COMMUNITY_PACKAGES_MANAGED_BY_ENV op true. Voor Elido heb je er geen nodig: de HTTP Request-node dekt de API.

Wat is WEBHOOK_URL in n8n?

Het vertelt n8n welk openbaar adres hij in de editor moet tonen en bij externe diensten moet registreren, omdat n8n dat achter een reverse proxy niet uit zijn eigen host en poort kan afleiden. Huidige n8n-versies lezen N8N_WEBHOOK_URL en loggen een waarschuwing over verouderd gebruik voor de oudere WEBHOOK_URL. Combineer het met N8N_PROXY_HOPS=1 en doorgestuurde headers op de proxy.

Hoe controleer ik een webhookhandtekening in n8n?

Zet de optie Raw Body in de Webhook-node aan en voeg dan een Code-node toe die HMAC-SHA256 opnieuw berekent over de timestamp-header, een punt en de ruwe body, met het geheim van je endpoint. Vergelijk het in constante tijd met de handtekeningheader en weiger alles wat ouder is dan vijf minuten. Controleer tegen de ruwe bytes, nooit tegen opnieuw geserialiseerde JSON.

Heeft de wachtrijmodus van n8n Redis nodig?

Ja. In wachtrijmodus zetten de hoofdinstantie en eventuele webhookprocessors binnenkomende triggers om in uitvoerings-ID's en duwen die naar een wachtrij op Redis, waaruit workers ze ophalen. n8n raadt wachtrijmodus met SQLite ook af, dus plan voor Postgres. Elk proces moet dezelfde versleutelingssleutel delen, anders kunnen workers opgeslagen credentials niet lezen.

Is zelfgehoste n8n beter voor de AVG dan n8n Cloud?

Dat kan, omdat jij kiest waar workflowdata, uitvoeringslogs en credentials fysiek staan en wie ze beheert. Het is niet automatisch conform: je wordt zelf verantwoordelijk voor patches, toegangsbeheer, back-ups en bewaartermijnen. Bij linkautomatisering die klikdata verwerkt, haalt zelfhosten in een EU-regio één verwerker uit je registers, wat de administratie eenvoudiger maakt.

Probeer Elido

Plak een URL, krijg een werkende korte link

Geen aanmelding nodig. Link blijft 30 dagen actief. Meld je aan om hem voor altijd te bewaren.

Geen account nodig. Meld je gratis aan voor 50 links per maand.

Probeer Elido

In de EU gehoste URL-shortener met aangepaste domeinen, uitgebreide analyses en een open API. Gratis abonnement - geen creditcard nodig.

Tags
self-hosted n8n automation links
n8n self hosted url shortener
n8n docker link automation
n8n webhook signature verification
n8n queue mode
n8n http request node api

Verder lezen