Networking

Networking

Cronable binds to 127.0.0.1. That is deliberate: the daemon runs commands on your behalf, so exposing it would be the worst possible hole. But a webhook from Stripe or GitHub has to reach you somehow.

There are two ways, and you choose in Settings → Networking.

Cronable relayYour own endpoint
Ports to opennoneone, plus HTTPS in front
Works behind NAT / at homeyesno — needs a public address
Changing IP addressfineneeds stable DNS
Payloads pass through Cronableyesno
Setupone switcha DNS record (Cronable can run the proxy)
Per-user installyesno — needs a sudo install

If you are not sure, use the relay. It is the right answer for a laptop, a home server, or anything behind NAT. Choose your own endpoint when payloads must not leave your infrastructure.

The Cronable relay

Your machine opens an outbound connection to hooks.cronable.ai, and events are pushed back down it. Nothing listens for incoming connections.

Stripe ──POST──▶ hooks.cronable.ai ═══outbound WS═══ your machine ──▶ job runs
                                    (opened by you)

Turn on Cronable relay and each webhook job gets a public address of the form https://hooks.cronable.ai/h/<hookId>, shown when you open the job. Callers still need that webhook’s token, so this does not open your jobs to anonymous requests.

Full architecture and security model: Webhook relay.

Your own endpoint

Webhooks arrive directly at your machine, so payloads never touch Cronable’s servers. You need:

  • a public address — a domain pointed at the machine (recommended) or a public IP;
  • a port open in your firewall or cloud security group;
  • HTTPS in front — Caddy, nginx, or a Cloudflare Tunnel.

Then set Public URL to that address, for example https://cron.example.com, and Cronable builds each job’s inbound URL from it.

Let Cronable handle HTTPS

Choose Cronable handles it and give it a domain. It installs Caddy, points it at Cronable, and lets it obtain and renew the certificate — you never touch a certificate file.

Two things must be true before you save:

  1. The domain’s DNS points at this machine.
  2. Ports 80 and 443 are reachable from the internet — check your cloud firewall or security group, not just the machine’s own firewall.

The certificate cannot be issued until both hold; that is a requirement of how ACME works, not a Cronable one.

You can do the same at install time, which is the shortest path on a fresh server:

sudo ./install.sh --public-access cron.example.com

Managed HTTPS needs the system install (sudo). A per-user install never has root, so it cannot install or configure a proxy.

What Cronable writes, and what it leaves alone. It appends one import line to your /etc/caddy/Caddyfile and then only ever rewrites its own snippet in Cronable’s state directory. Your Caddyfile is never overwritten, so any other sites you serve are untouched. Uninstalling removes that one line and Cronable’s own units — never Caddy itself, and never your certificates.

Serving the dashboard too

By default only webhooks are served on the domain. You can also serve this dashboard there — but that is a full-access surface reachable from the internet, so it requires two-factor authentication on your account, the same as remote access.

Point your proxy at the webhook port, not at the dashboard port

Turning this on arms a second listener that serves the inbound webhook route and nothing else — by default 127.0.0.1:8789 (CRONABLE_HOOK_PORT). Every other path returns 404 there, including Cronable’s own token-rotation endpoint.

Point your proxy at that port:

cron.example.com {
  reverse_proxy /h/* 127.0.0.1:8789
  reverse_proxy /api/hooks/* 127.0.0.1:8789
}

The second line keeps older /api/hooks/<hookId> URLs working, so if you already had a proxy forwarding that path, your existing registrations survive the move.

That matters more than it looks. The obvious alternative — proxying to the main API on :8787 and forwarding “only /api/hooks/” — puts the burden on your proxy config being exactly right forever. A misconfigured rule there exposes jobs, secrets and settings. Aimed at 8789, a proxy that forwards everything still reaches only the hook route, because nothing else exists on that port.

The listener is not opened until you enable Public access, so an install that never uses this never opens a port.

Test connection

The Test connection button checks, in order: the listener is running, a request routes through it, your DNS resolves to this machine, and the full HTTPS path reaches Cronable.

These checks run from your machine. They will catch a wrong address, an expired certificate, or a stopped listener. They cannot tell you whether a cloud firewall is blocking the outside world — most providers let a machine reach its own public address even when nobody else can. Treat a pass as “nothing is obviously broken”, not as proof that Stripe can reach you.

Can I use both at once?

Yes, and you should while switching. The two switches are independent, not a single mode. Turn on your own endpoint, confirm it works, and only then turn the relay off. Nothing stops firing in between.

Connectors that register their own webhook with the vendor — Calendly, Asana, Typeform and others — are re-pointed for you. Cronable records the address each subscription was registered against and re-registers it when that address changes, so switching cannot leave a service quietly posting to an address that no longer answers.

When both are on, new registrations use your own endpoint.

Why can’t I turn this on?

The tab disables Your own endpoint and tells you why. The two common reasons:

  • “This copy of Cronable was installed for your user only.” A per-user install (always the case on macOS, and on Linux when you run the installer without sudo) cannot open a privileged port or manage a system proxy. Install on a server with sudo ./install.sh — or use the relay.
  • “This machine has no public IP address.” Every address on the machine is private, so an external service cannot reach it directly however you configure it. Use the relay.

Is my endpoint open to anyone?

No. The inbound route authenticates every request with a per-webhook token, compared in constant time against a stored hash. An unknown webhook, a disabled one, and a wrong token all return the same generic 401, so a caller cannot probe which webhooks exist. Bodies are capped at 256 KB, each webhook is rate-limited (300 requests/minute by default), and a repeated delivery ID within ~10 minutes is acknowledged without running the job twice.

The token travels either as the X-Webhook-Token header or as ?token= in the address — which is why Cronable requires HTTPS for any public address and refuses to save a plain http:// one.

What about the dashboard?

Turn on Serve the dashboard on this domain too under managed HTTPS. It requires two-factor authentication on your account, because the dashboard is a full-access surface.

If you terminate TLS yourself, point your proxy at the dashboard port (8788 by default) — see Operations.