🏠 Home ← Docs Index
Open Beta 📖 Interactive Reader Raw .md llms.txt

GoClaw Ingress Configuration Guide

Ingress is the public entry point for webhooks and channel callbacks. It lets platforms such as Microsoft Teams, Facebook, GitLab, Graylog, and custom webhook senders reach a GoClaw process that is running on a local or private port.

Request Flow

flowchart TD
    EXT["<b>External Platform</b><br/>Teams, Facebook, GitLab, Graylog, custom webhook"] --> ING["<b>Ingress Layer</b><br/>ngrok, nginx, Caddy, HAProxy, or another reverse proxy"]
    ING --> GW["<b>GoClaw Gateway or Dedicated Webhook Listener</b><br/>• /hook/msteams, /hook/facebook, /hook/telegram<br/>• /hook/&lt;slug&gt;/msteams, /hook/&lt;slug&gt;/facebook, /hook/&lt;slug&gt;/telegram<br/>• /goclaw/hook/&lt;type&gt;[/&lt;key&gt;]<br/>• /api/webhook"]

Config Fields

gateway:
  ingress:
    type: ""               # "ngrok", "proxy", "nginx", or "" (no tunnel; see Ingress Types)
    url: ""                # The address outside systems reach this gateway at
    authtoken: ""          # Ngrok auth token, only used with type: "ngrok"
    allow_preset: ""       # "microsoft-teams", "none", or empty
    allow_ips: []          # CIDR/IP allowlist; when set, it replaces the preset
    port: ""               # Optional dedicated webhook port
    bind: ""               # Webhook port's interface: "loopback" (default), "lan", or an explicit IP
    trust_proxy: false     # Trust X-Forwarded-For / X-Real-IP from a known proxy

If gateway.ingress.port is empty, webhook routes share the main gateway port. If it is set, GoClaw starts a separate webhook server for ingress traffic. This is useful when the WebUI and admin API should stay private while public webhooks are exposed. That server listens on gateway.ingress.bind, which defaults to loopback: set bind: "lan" (or an IP) when the sender reaches it directly rather than through a proxy on the same host.

With a dedicated port, the webhook routes (/hook/* and /goclaw/hook/*) leave the Web UI port: they are served only on gateway.ingress.port, and a hook URL that points at server.port gets 404. Health probes and /api/webhook are served on both ports; /api/webhook needs the gateway token on either. The Web UI, /gateway and the rest of /api/* stay on server.port only.

url is the gateway's address as the sender sees it, including a proxy's path prefix if it has one. Features that give this address to another system read it whatever type is: the Webhooks page, the agent's graylog_alert tool (Graylog calls <url>/goclaw/hook/graylog/<key>) and the goclaw gitlab hook wizard. On a LAN with no proxy it can be the gateway's own address, for example http://192.0.2.10:8080; the GitLab wizard, though, accepts only an https:// address.

Ingress Types

Type Behavior
empty No tunnel is started. url, when set, is still the address the Webhooks page, graylog_alert and the GitLab wizard give senders; without it the Webhooks page builds hook URLs from the address you opened it at. This does not limit who can reach the gateway: that is wherever gateway.bind (or gateway.ingress.bind, with a dedicated port) listens, subject to allow_ips / allow_preset
ngrok GoClaw starts or uses an ngrok tunnel for webhook traffic
proxy An external reverse proxy forwards traffic to GoClaw
nginx Alias-style value for reverse proxy deployments

Common Routes

Route Purpose
/hook/msteams Microsoft Teams channel webhook
/hook/facebook Facebook channel webhook
/hook/telegram Telegram channel webhook (only with channels.telegram.mode: webhook)
/hook/<slug>/msteams, /hook/<slug>/facebook, /hook/<slug>/telegram The same webhooks when gateway.webhook_secret_slug is set: the plain /hook/<channel> path is then not served
/goclaw/hook/<type>[/<key>] Generic webhook router
/api/webhook Inbound message API: the agent answers a text as if it came from the named channel (goclaw message uses it)
/api/send Outbound message API for local scripts: main gateway port only, loopback callers only, with the gateway token. Not a route to expose
/gateway Web chat WebSocket when the main gateway is exposed

Ngrok For Testing

gateway:
  ingress:
    type: "ngrok"
    authtoken: "${NGROK_AUTHTOKEN}"
    url: "https://my-agent.ngrok.app"
    port: "8001"
    allow_preset: "microsoft-teams"

The built-in tunnel delivers requests to GoClaw from the local machine (loopback), which the allowlist always lets through, so with trust_proxy: false (the default) allow_preset does not filter ngrok traffic. The Teams webhook is still protected by its Bot Framework token check (see Microsoft Teams). The allowlist filters callers that connect directly or through a reverse proxy.

Use a stable ngrok domain when the external platform stores a fixed callback URL. For Microsoft Teams, set the Azure Bot messaging endpoint to:

https://my-agent.ngrok.app/hook/msteams

or, with a secret slug:

https://my-agent.ngrok.app/hook/<slug>/msteams

Reverse Proxy With Path Prefixes

One domain can serve multiple agents by prefix. The proxy must strip the prefix before forwarding to GoClaw.

https://agents.example.com/finance/    -> 127.0.0.1:8001
https://agents.example.com/analyst/   -> 127.0.0.1:8002

Agent config:

gateway:
  bind: "loopback"
  ingress:
    type: "nginx"
    url: "https://agents.example.com/finance"
    port: "8001"
    bind: "loopback"
    allow_preset: "microsoft-teams"
    trust_proxy: true

Nginx example:

location /finance/ {
    proxy_pass http://127.0.0.1:8001/;
    proxy_http_version 1.1;

    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;

    proxy_read_timeout 300s;
    proxy_send_timeout 300s;
    proxy_buffering off;
}

location = /finance {
    return 301 $scheme://$host/finance/;
}

The trailing slash in proxy_pass http://127.0.0.1:8001/; is important. It strips /finance/ before forwarding, so /finance/health reaches GoClaw as /health.

Reverse Proxy With Subdomains

Use a subdomain per agent when DNS and TLS automation are already in place.

server {
    server_name finance.agents.example.com;

    location / {
        proxy_pass http://127.0.0.1:8001/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_read_timeout 300s;
        proxy_buffering off;
    }
}
gateway:
  ingress:
    type: "nginx"
    url: "https://finance.agents.example.com"
    port: "8001"
    bind: "loopback"
    trust_proxy: true

Allowlist And Proxy Trust

allow_preset: "microsoft-teams" admits the Microsoft 365 address ranges Teams calls from. GoClaw downloads them from endpoints.office.com at start-up; if the download fails, the gateway does not start (Ingress failed: …), so the host needs outbound HTTPS to that address.

allow_ips is a list of IPs and CIDR ranges. When it has any entry, it replaces the preset: the Teams ranges are not loaded, and only the listed addresses get in. To admit Teams and your own addresses, use one of these:

gateway:
  ingress:
    allow_ips:                # no allow_preset: these are the only addresses let in
      - "10.0.1.5"            # the reverse proxy
      - "203.0.113.10/32"     # a test machine

The allowlist covers every request on the listener it guards. With gateway.ingress.port set, that is the dedicated webhook listener. Without it, webhooks share the main port, and the allowlist covers the Web UI and the API there too: a browser on an address that is not listed gets 403.

Set trust_proxy: true only when the immediate upstream is a proxy you control, and have that proxy set or append X-Forwarded-For with the client address it saw (proxy_set_header X-Forwarded-For $remote_addr; in nginx, as the examples above do; $proxy_add_x_forwarded_for works too). GoClaw takes the last entry, the one your proxy wrote: anything before it is what the caller sent. Otherwise, GoClaw uses the TCP remote address and ignores spoofable forwarding headers.

Loopback callers are always allowed for local health checks and reverse proxy deployments.

Troubleshooting

Symptom Likely cause Fix
Prefix URL returns 404 The reverse proxy did not strip the prefix Use a trailing slash in proxy_pass
WebSocket does not connect Upgrade and Connection headers are missing Forward WebSocket headers
Teams endpoint validation fails Wrong path or method filtering in proxy Forward all methods to GoClaw; let GoClaw validate
Requests are denied by allowlist GoClaw sees the proxy IP, not the external IP Enable trust_proxy for a trusted proxy, or add the proxy IP to allow_ips (which replaces allow_preset)
Gateway exits at start-up with Ingress failed allow_preset: microsoft-teams could not download the Microsoft 365 ranges Allow outbound HTTPS to endpoints.office.com, or list the ranges in allow_ips
Hook URL returns 404 gateway.ingress.port is set and the URL points at server.port Point the sender (or the proxy) at the webhook port
WebUI is public unintentionally Webhook and WebUI share the same public listener Use gateway.ingress.port and expose only that port

Implementation Files