Search docs

Search the Beamd documentation

Production

Run the edge under Docker or systemd, where it can and can't be hosted, binding :443, and what to monitor.

The Setup walkthrough gets you a working edge. This page covers running it for real.

Where it can run

Beamd terminates its own TLS and ALPN-demuxes public HTTPS from client control on a single :443, so it needs a raw TCP :443 on a public IP. That's the whole story of platform fit:

TargetFits?Why
Any VM — DigitalOcean, Hetzner, Linode, Vultr, EC2, GCEYou're the host; raw :443 + public IP.
Fly.ioRaw-TCP passthrough + a dedicated IP.
Render, Railway, Heroku, Cloud Run, DO App PlatformThey terminate TLS in front of your container.
Cloudflare Workers / PagesRequest-scoped; no raw :443 + custom TLS/ALPN.

Cloudflare is a DNS provider here, not a host — you can't run the edge on Cloudflare compute.

The bundled example/docker-compose.yml is the production-ready shape:

services:
  beamd:
    image: ghcr.io/dynamismlabs/beamd:latest
    container_name: beamd
    restart: unless-stopped
    user: "0:0"                # root: bind :443, read tokens.json, write cert cache
    dns: ["1.1.1.1", "8.8.8.8"] # pin resolvers (see below)
    ports: ["443:443"]          # the only public port (ALPN-demuxed)
    volumes:
      - /etc/beamd:/etc/beamd       # rw: add-developer updates tokens.json
      - /var/lib/beamd:/var/lib/beamd # cert cache + ACME state survive restarts
    environment:
      - BEAMD_DNS_PROVIDER_CREDS=${BEAMD_DNS_PROVIDER_CREDS}
cd /etc/beamd && sudo docker compose up -d
sudo docker compose logs -f beamd

Pin DNS resolvers. certmagic finds the DNS-01 zone via an SOA lookup, and some hosts' default resolvers intermittently SERVFAIL, which breaks ACME issuance. The compose file pins 1.1.1.1 / 8.8.8.8 to avoid it.

systemd (binary install)

If you run the static binary instead of Docker, grant the :443 capability and run it as a unit:

sudo cp bin/beamd /usr/local/bin/
sudo setcap cap_net_bind_service=+ep /usr/local/bin/beamd
 
sudo tee /etc/systemd/system/beamd.service >/dev/null <<'EOF'
[Unit]
Description=Beamd edge server
After=network.target
 
[Service]
Type=simple
User=root
Environment=BEAMD_DNS_PROVIDER_CREDS=YOUR_CF_TOKEN
ExecStart=/usr/local/bin/beamd serve --config /etc/beamd/beamd.yaml
Restart=on-failure
RestartSec=2s
 
[Install]
WantedBy=multi-user.target
EOF
 
sudo systemctl enable --now beamd
journalctl -u beamd -f

:443 needs root or CAP_NET_BIND_SERVICE — the setcap line covers the non-root binary case.

Running the client agent as a service

On a machine that should keep tunnels up unattended (a build box, an embedded host app), run the background agent as a service instead of relying on beamd open -d to spawn it. See Agent local API and Embed in your app.

Monitoring

  • Health: GET /healthz{"status":"ok","version":"…"}.
  • Metrics: the edge exposes /metrics (Prometheus format) with per-slug bandwidth and active-tunnel counts — scrape it for dashboards and alerts.
  • Certs: certmagic renews automatically before expiry; wire /metrics into alerting if you want to be paged on failure.

Known limits

A single edge is a single point of failure — no built-in HA or anycast; if the VM dies, tunnels drop until it's back (fine for personal/team use, run a second region if you need more). Body size is capped but there's no per-IP rate limit — put a fronting WAF in front if you're exposed to abuse. See Limits & quotas.