Use code for 20% launch discount. Lifetime licenses include complete source code.Copy code

Architecture guide

Drop Hookdeck and Svix queues for SQLite on your own disk

Cloud webhook queues are an HTTPS listener, a JSON blob, and a retry table. SQLite WAL on a VPS you already run does that job under 50MB RAM.

Local SQLite webhook routing

Hookdeck, Svix, and similar products persist events in a vendor queue you never see. Webhook Router writes the same rows to app.db next to Compose. Signing secrets stay in an env file. Retries are SQL, not a dashboard you rent.

Path of one event

  1. 01

    Ingest

    TLS at Caddy. POST /hooks/{source}. Body never leaves the box.

  2. 02

    Verify

    Stripe or HMAC. Failed signatures return 400 with no INSERT.

  3. 03

    Enqueue

    One SQLite transaction: events row plus N deliveries in WAL.

  4. 04

    Deliver

    Workers claim rows, retry on next_at, dead-letter on disk.

Production Docker Compose

mem_limit 50m matches the RSS budget. WAL files live on the bind mount so a restart does not drop the queue.

services:
  webhook-router:
    image: webhook-router:latest
    restart: unless-stopped
    mem_limit: 50m
    memswap_limit: 50m
    cpus: "0.50"
    ports:
      - "127.0.0.1:8090:8090"
    environment:
      TZ: Europe/Madrid
      NEXUS_TELEMETRY: "off"
      SQLITE_JOURNAL: WAL
      SQLITE_BUSY_TIMEOUT_MS: "5000"
      SQLITE_CACHE_KB: "8192"
      MAX_RSS_MB: "48"
      STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET}
    volumes:
      - ./data/webhooks:/var/lib/webhook-router
      - ./routes.json:/app/routes.json:ro
      - ./router.env:/run/secrets/env:ro
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8090/health"]
      interval: 15s
      timeout: 3s
      retries: 5

SQLite schema

Three tables. No broker. Back up ./data/webhooks with the rest of the host.

-- /var/lib/webhook-router/app.db  (WAL)
CREATE TABLE events (
  id TEXT PRIMARY KEY,
  source TEXT NOT NULL,
  received_at INTEGER NOT NULL,
  payload BLOB NOT NULL,
  verified INTEGER NOT NULL DEFAULT 1
);
CREATE TABLE deliveries (
  id INTEGER PRIMARY KEY,
  event_id TEXT NOT NULL,
  dest TEXT NOT NULL,
  attempt INTEGER NOT NULL,
  status TEXT NOT NULL, -- queued | retrying | ok | dead
  next_at INTEGER,
  last_error TEXT
);
CREATE TABLE dead_letter (
  id INTEGER PRIMARY KEY,
  event_id TEXT NOT NULL,
  dest TEXT NOT NULL,
  failed_at INTEGER NOT NULL,
  last_error TEXT
);

Resource usage (under 50MB RAM)

Measured on a 1 vCPU / 1 GB VPS with WAL on SSD after 10k Stripe-sized events.

# RSS after 10k Stripe-sized events, WAL on SSD
# webhook-router   38–46 MB RSS
# sqlite WAL       ~2 MB mapped
# idle CPU         <1% of 1 vCPU
# p95 ingest       4–9 ms local
# p95 fan-out      destination-bound

Related: Replace cloud webhook services and self-hosted webhook router setup.

Get the source

Webhook Router ships in both bundles. Checkout stays on Whop.

Complete Dev Suite

Own the queue

$149.99one-time

  • Webhook Router with SQLite WAL queue
  • Production Docker Compose (50MB cap)
  • NexusCron and NexusPipeline
  • Retries and dead-letter on disk
Buy Complete Dev Suite

Checkout stays on Whop. You get the source after payment.

Questions people ask before they switch

Why SQLite instead of Redis or Postgres for the queue?

Webhook volume is bursty writes of small JSON blobs plus a few retries. WAL SQLite on local SSD handles that under 50MB RAM. Redis and Postgres add another process you have to patch and back up.

Does WAL survive a container restart?

Yes if ./data/webhooks is a bind mount. The WAL and SHM files live next to app.db. Restart the container; inflight rows stay queued.

What happens when a destination is down?

The row stays in deliveries with status retrying. After max attempts it moves to dead_letter. Replay with POST /api/dlq/{id}/retry. Nothing sits in a vendor inbox.

Is 50MB RAM a hard cap?

Idle plus a few concurrent POSTs stays under 50MB RSS on a 1 vCPU VPS in our production Compose. Burst fan-out uses disk, not a bigger heap.

Keep reading

Guide

Self-hosted cron alternative

Stop paying a monthly bill to fire HTTP on a timer. NexusCron is a self-hosted cron alternative you deploy with Docker on machines you already own.

Guide

EasyCron and cron-job.org alternative

Compare EasyCron, cron-job.org, and other hosted cron products with NexusCron. Same job, no subscription, logs and secrets stay on your disk.

Guide

Migrate off EasyCron to a self-hosted runner

Step-by-step migration from EasyCron to a self-hosted cron runner. Export jobs, map cron expressions, Docker Compose, HTTP pings, and cutover without downtime.

Guide

Migrate cron jobs off cloud providers to self-hosted

Technical guide for migrating cron jobs off cloud providers to self-hosted NexusCron. Architecture, Docker Compose, job mapping, and cutover without missed pings.

Guide

Replace cloud cron services with self-hosted NexusCron

Architecture, Docker Compose, production env vars, and cutover for replacing hosted cron with NexusCron on a VPS you already run. One lifetime payment.

Guide

Migrate EasyCron jobs to self-hosted NexusCron

Architecture, Docker Compose, and cost math for replacing $20–$50/month hosted cron with NexusCron on a VPS you already run. One lifetime payment.

Guide

Self-hosted webhook router

A self-hosted webhook router that receives, transforms, and forwards events on your infrastructure. One payment. No Zapier tax for simple routing.

Guide

Replace cloud webhook services with self-hosted Webhook Router

Architecture, Docker Compose, and config mapping to replace Hookdeck, Svix, Zapier, and Make with NexusCore Webhook Router on your VPS. One lifetime payment.

Guide

Self-hosted pipeline setup

NexusPipeline is a FastAPI Docker execution engine. Clone it, compose up, and keep job state on disk you control. One payment. No worker SaaS.

Guide

Self-hosted admin dashboard setup

NexusAdmin is the self-hosted dashboard that sits next to NexusPipeline. One payment, Docker Compose, no SaaS admin tenant.

Guide

Self-hosted log stream setup

LogStream is a single-binary Node.js collector. HTTP and UDP ingest, SQLite, live dashboard, webhook alerts. One payment. No observability SaaS.

Guide

Self-hosted env sync setup

EnvSync Agent syncs .env values across VPS hosts, laptops, and microservices. Encrypted key-value store. One payment. No secrets tenant.

Guide

Self-hosted API proxy setup

API Proxy Service sits between your code and upstream APIs. Retries, rate limits, fallbacks, circuit breakers. One payment. No gateway SaaS.