← Blog

Strategy

Edge-agents overbouwen: de veldgids voor agency-CTO's

Iemand op Hacker News serveert deze week zijn blog vanaf een telefoon die platgeperst in een wc-pot zit. Je CTO heeft de thread in één tab open en een AWS-factuur in de andere.

Jacob Molkenboer· Oprichter · A Brand New Company· 19 jun 2026· 10 min
Messing belletje, mahoniehouten blokjes, koperdraad en jute touwtjes aan een indexkaart, kaartje met groen tabje, lakzegel.

Iemand op Hacker News serveert deze week zijn blog vanaf een telefoon die platgeperst in een wc-pot zit. De thread staat op plek #22 op de front page. Je CTO heeft 'm in één tab open en een AWS-rekening van €4.200 in een andere. Hij staat op het punt je kantoor binnen te lopen met de vraag die we elke keer krijgen als we een overbouwde edge-agent stack auditen: "als een wc-telefoon een webserver kan zijn, waarom hebben we dan net een jaar Vercel Pro, twee regio's Upstash en een Cloudflare Workers Paid-abonnement betaald voor veertien agents die elk minder dan twee requests per seconde afhandelen?"

Een terechte vraag. En een vraag die, als je 'm slecht beantwoordt, eindigt in een rewrite van zes weken vóór de volgende sprint in plaats van een Caddyfile-aanpassing van veertig minuten vanavond.

Hieronder volgt de veldgids die we intern gebruiken als we de agent-stack van een bureau onder de €14M auditen. Vijftien fouten die telkens terugkomen, gesorteerd op exit-kost: acht die je terugdraait in één Caddyfile op één Hetzner CX22, en zeven die je vastzetten in een rewrite zodra je de eerste regel Workers-specifieke code hebt geschreven.

De wc-telefoon als ijkpunt

De reden dat die platgeperste-wc-telefoonpost nuttig is, is niet dat je klantsites vanaf een toilet zou moeten serveren. Het is dat de post je plafond reset. Die telefoon doet misschien één request per minuut. Een Hetzner CX22 van €4,59 per maand (2 vCPU, 4 GB, 40 GB NVMe, Falkenstein of Neurenberg) is ongeveer vier ordes van grootte capabeler. Twaalf klantprojecten, elk met een paar duizend requests per dag, passen op die ene machine met ruimte over voor een Postgres, een pgvector-index en de agent-runtimes zelf.

Als je stack duurder is dan dat en je load in die range zit, betaal je voor één van twee dingen: een echte technische noodzaak, of pattern-matched architectuur die je hebt overgenomen van een HN-post over een bedrijf met 400× jouw traffic. Meestal is het het tweede. En bijna alles in dat tweede is terug te draaien.

De splitsing die telt is niet is dit overengineered — bijna alles is dat — maar kan ik dit terugdraaien zonder de agent-code zelf te herschrijven.

Acht die je met één Caddyfile terugdraait

Dit zijn fouten aan de edge. Ze beïnvloeden hoe traffic je app bereikt. De app zelf weet niet eens dat ze bestaan. Je kunt ze vanavond terugdraaien, op één CX22, met één configuratiebestand en een systemd-unit.

1. Marketingsite op Vercel omdat dat de standaard van het framework is. De marketingteksten van Next.js en de onboarding van Vercel laten het voelen als één beslissing. Het zijn er twee. Een static export geserveerd door Caddy met file_server en automatische Let's Encrypt kost je niets en draait vanaf dezelfde machine als de rest.

2. Cloudflare vóór admin-dashboards die door twaalf mensen worden gebruikt. De CDN doet niets — er is geen edge cache hit op een geauthenticeerde /admin-route. Je betaalt voor de obscuriteit van een Cloudflare-hostname en krijgt er een debug-belasting voor terug. Zet 'm voor het publieke oppervlak; serveer admin rechtstreeks vanaf de origin met tls internal op een privé-subdomein.

3. Lambda@Edge of Workers als TLS-terminatielaag. Caddy termineert TLS, hot-reload't certs, staple't OCSP en vernieuwt zichzelf. Automatic HTTPS is een one-liner. Je hebt hier geen edge runtime voor nodig. Je hebt een TLS-bewuste webserver nodig, en dat is Caddy.

4. Preventief multi-region voor een Nederlandse klantenbasis. Elke klant die je hebt zit binnen 40ms RTT van AMS-IX. Een tweede regio in Singapore koopt je 0% van je klanten en 100% van een extra data plane om over na te denken. Eén regio, één machine, één back-uptarget.

5. Managed cron-services voor jobs die ieder uur draaien. Een systemd-timer plus een one-shot unit is twintig regels en overleeft een reboot. De cron-as-a-service producten bestaan voor fleets, niet voor de vier factuur-chase-jobs die je daadwerkelijk draait.

# /etc/systemd/system/invoice-chaser.service
[Unit]
Description=Chase one batch of overdue invoices

[Service]
Type=oneshot
WorkingDirectory=/opt/agents/invoice-chaser
ExecStart=/usr/bin/node run.js
User=agents

# /etc/systemd/system/invoice-chaser.timer
[Unit]
Description=Hourly invoice chase

[Timer]
OnCalendar=hourly
Persistent=true
Unit=invoice-chaser.service

[Install]
WantedBy=timers.target

Daarna sudo systemctl daemon-reload && sudo systemctl enable --now invoice-chaser.timer en je bent klaar. journalctl -u invoice-chaser -f tail't 'm.

6. Webhooks ingepakt in API Gateway + Lambda. Een webhook is een HTTP POST. Caddy kan 'm routeren naar een long-running Go- of Node-proces dat op een Unix socket luistert. Geen cold start, geen kosten per invocation, geen IAM-policy om vrijdagavond om 21:00 te debuggen.

7. Auth0 Free voor de interne tool met twaalf gebruikers. Je raakt het MAU-plafond aan in de week dat een klant tekent en dan zit je auth te migreren tijdens een launch. Authelia achter Caddy's forward_auth-directive, of basic auth voor een dashboard dat niemand buiten kantoor ziet, is de betere ondergrens.

8. Datadog log-ingestion terwijl journalctl gewoon klaarstaat. Je betaalt per GB om logs te shippen die je één keer per kwartaal leest. journalctl -u agent-foo -f via SSH is gratis. Een Grafana + Loki-paar op dezelfde machine, achter Caddy basic auth, is óók gratis en geeft je een dashboard voor het zeldzame moment dat je er echt eentje nodig hebt.

Hier is de complete edge voor een twaalfprojecten-bureau op één machine:

{
    email ops@agency.nl
}

agency.nl, www.agency.nl {
    root * /var/www/marketing
    file_server
}

app.klant-een.nl {
    reverse_proxy unix//run/agents/klant-een.sock
}

app.klant-twee.nl {
    reverse_proxy unix//run/agents/klant-twee.sock
}

admin.intern.agency.nl {
    forward_auth localhost:9091 {
        uri /api/verify
        copy_headers Remote-User Remote-Groups
    }
    reverse_proxy localhost:8080
}

Dat is de hele edge. Eén block per klantproject, één voor de marketingsite, één voor de interne dashboards. Caddy reload't bij een wijziging, certs vernieuwen zichzelf, en het bestand staat in een git-repo die je CTO naar een tweede machine kan scp'en op de dag dat Falkenstein in brand staat.

Elk van deze is een Caddyfile-diff en een service-restart. Geen ervan raakt je applicatiecode aan. Als je CTO alleen de acht dingen hierboven heeft gedaan, zit je ongeveer twee uur verwijderd van een hostingrekening die in één Hetzner-factuur past in plaats van drie SaaS-dashboards.

Waarschuwing

De grens die je oversteekt is de eerste import { KVNamespace } from "@cloudflare/workers-types". Vóór die regel heb je een portable Node-service. Erná is je storage-laag getrouwd met Cloudflare en betaal je voor de scheiding.

Zeven die een rewrite afdwingen vóór de volgende sprint

Deze fouten veranderen wat voor soort programma je hebt geschreven. De agent zelf is ervan afhankelijk. Je kunt ze niet terugdraaien met een config-bestand; je gaat dieper het platform in, of je herschrijft tegen een portable runtime.

9. Cloudflare KV of Durable Objects als je primaire store. De bindings zijn geen Postgres. Je hebt geschreven tegen een eventually-consistent key-value model met een cap van 25 MiB per value en een regionaal consistency-verhaal. Eraf migreren vraagt om het opnieuw doordenken van je datamodel, niet om het wisselen van een driver. De Workers limits-pagina is verplichte literatuur voordat je je commit.

10. R2 met aannames over de Workers runtime. Als je file-handling de streaming Response-APIs van Workers gebruikt en aanneemt dat er geen Node fs is, dan is porten naar S3 of lokale disk geen one-line driver-swap. Het is een refactor van elk code-pad dat een bestand aanraakt.

11. Vectorize of Workers AI voor embeddings. pgvector in dezelfde Postgres op dezelfde CX22 is strikt een simpelere architectuur voor elke index onder een paar miljoen vectoren. Als je retrieval-laag rond Vectorize's query-API is gebouwd, herbouw je de retrieval-laag, niet de index.

12. Eén agent opsplitsen in acht Workers om binnen de CPU-limiet te blijven. De Workers free tier cap't op 10ms CPU; de paid tier op 50ms. Als je agent 200ms werk deed en je 'm verdeeld hebt over acht Workers plus een Queue om te passen, heb je een gedistribueerd systeem geschreven. Terugdraaien betekent alles weer in één proces samenvoegen — en dat betekent de IPC, de partial-failure handling en de observability die je erbovenop hebt gebouwd om 'm te debuggen, opnieuw schrijven.

13. Custom queues op Workers Queues met bespoke consumer-logica. De semantiek — max batch, retry policy, DLQ-gedrag — mapt niet één-op-één op SQS, RabbitMQ of een Postgres-gebaseerde job-tabel. Migreren betekent dat je je retry- en backoff-invarianten vanaf nul opnieuw afleidt.

14. LLM-calls per request zonder caching-laag. Deze is verraderlijk, omdat het er niet uitziet als vendor lock-in; het ziet eruit als een kostenprobleem. De fix (prompt caching, embedding caching, caching van tussenresultaten) is een echte architecturale laag. Als je agents bij elke turn een model aanroepen zonder cache, heb je geen overdure stack, je hebt een onafgemaakte stack. De prompt-caching-docs van Anthropic zijn het startpunt voor de Claude-kant.

15. Auth vastgelijmd aan Cloudflare Access-policies. Als je agents identiteit checken door de Cf-Access-Jwt-Assertion header te vertrouwen en geen fallback-verifier hebben, betekent weg van Cloudflare dat je een IdP optuigt en het trust-pad door elke service herschrijft. De fix is om op dag één een dunne auth-abstractie vóór de header te zetten — maar als het zes maanden geleden is, kijk je naar serieus werk.

De audit van vijf minuten die je morgen kunt draaien

Open de repo. Grep op deze strings:

git grep -nE '@cloudflare/workers|KVNamespace|DurableObject|R2Bucket|env\.VECTORIZE|Cf-Access-Jwt'

Krijg je nul hits, dan zit je volledig in de Caddyfile-omkeerbare zone. Spin een CX22 op, schrijf de Caddyfile van dertig regels van hierboven, wijs een staging-subdomein erop en migreer deze week één klantproject als pilot.

Krijg je hits, tel dan de bestanden. Onder de vijf: refactor vóór de volgende sprint, zolang het nog klein is. Boven de vijf: accepteer dat je nu een Cloudflare-shop bent en dat de goedkoopste zet is om er dieper in te gaan — Workers Paid, Hyperdrive vóór een managed Postgres, en stop met óók nog Lambda en Vercel ernaast te willen houden.

De fout onder alle vijftien is dezelfde fout. Je hebt een thread gelezen over Discord dat vijftien miljoen gelijktijdige gebruikers serveert en stilletjes aangenomen dat dat op jou van toepassing was. Dat is het niet. De wc-telefoonpost is geen meme. Het is hetzelfde punt vanuit de andere kant: het plafond ligt veel lager dan de architectuur-astronautenposts suggereren, en de vloer ligt veel, veel lager dan de AWS-factuur.

Toen we deze audit voor het laatst deden bij een Amersfoorts bureau dat twaalf klantprojecten op een serverless mesh draaide, was het ding waar we tegenaan liepen de auth-laag — zes maanden Cloudflare Access-lijm die eruit moest voordat er iets anders kon bewegen. Uiteindelijk hebben we het opgelost door alle auth door één Authelia-container achter Caddy forward_auth te routeren, waarna we de overige services één voor één in drie weken konden migreren. De hele stack draait nu op een CX32, met hostingkosten een orde van grootte lager dan waar we begonnen. Wil je meer lezen over hoe we AI-agents op deze schaal aanpakken, dan dekt de servicepagina de rest.

Het kleinste ding voor vanavond: draai die git grep hierboven. Het aantal hits vertelt je in welke helft van deze gids je zit.

Kern

Audit je stack met één git grep; komt @cloudflare/workers nergens voor, dan zit je een avondje Caddyfile-werk verwijderd van een normale rekening.

FAQ

Is één Hetzner CX22 echt genoeg voor twaalf klantprojecten?

Voor de meeste Nederlandse agency-workloads — een paar duizend requests per dag per project, lage concurrency, geen media-transcoding — ja. Het knelpunt waar je het eerst tegenaan loopt is meestal het aantal Postgres-connecties, niet CPU of RAM.

Wanneer is Cloudflare Workers wél zinvol voor een agency-stack?

Als je traffic globaal is, latency-gevoelig aan de request-edge, en je code in het runtime-model past. Voor een Nederlandse klantenbasis die vanuit Falkenstein wordt geserveerd, is daar bijna niets van waar.

Wat is de snelste manier om een Vercel-deployment terug te draaien?

Static-export je Next.js-app, rsync 'm naar /var/www op een CX22, wijs Caddy erop met file_server en update DNS. Voor een marketingsite kost de omschakeling minder dan een uur.

Hoe weet ik of ik de Workers-rewrite-grens al ben overgestoken?

Grep je repo op @cloudflare/workers, KVNamespace, DurableObject, R2Bucket en Cf-Access-Jwt. Verschijnen die in meer dan vijf bestanden, dan zit je in rewrite-gebied.

strategyarchitectureai agentstoolingoperations

Iets bouwen?

Start een project