Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.noxus.ai/llms.txt

Use this file to discover all available pages before exploring further.

Inbound traffic falls into two groups with very different exposure needs:
  1. Your users — browsers and API clients. Can stay entirely on a private network/VPN.
  2. External SaaS webhooks — third-party services pushing events to you. Require a publicly reachable endpoint.

Services and ports

Self-hosted Noxus puts a reverse proxy (nginx on VM, an ingress controller on Kubernetes) in front of three HTTP services. Only the proxy needs to be exposed.
ServiceInternal portPublic hostname (typical)Who connects
Frontend (Next.js)8080 (3000 on VM)app.example.comUsers’ browsers
Backend API (FastAPI)8080 (8100 on VM)api.example.comBrowsers, API clients, SSE
Relays (FastAPI)8080 (5003 on VM)relay.example.comExternal SaaS webhooks
Workers8080 (internal)Never exposed
Plugin server / sandbox8500 / 8080 (internal)Never exposed
On Kubernetes these are three ingress hosts (main, api., relay.) all routing to internal port 8080. On the VM, nginx terminates TLS on 80/443 and proxies to the per-service ports. Only 443 (and 80 for redirect) needs to be open at the edge.

Inbound from your users (UI, API, streaming)

These power the product itself and are always required, but they only need to be reachable by your users — a LAN or VPN address is fine.
  • Frontend + Backend API over HTTPS.
  • Server-Sent Events (SSE) — long-lived GET/POST responses with text/event-stream, used for live run progress (/v1/runs/{run_id}/events) and agent replies (/v1/conversations/{conversation_id}/stream and /events). Make sure your proxy does not buffer these responses and allows long-lived connections (disable response buffering; set a generous read timeout — streams can run for minutes).
  • WebSockets — used by optional interactive features (sandbox shell, playbook recording). If your proxy needs explicit WebSocket upgrade rules, add them; these features simply won’t work without them, but core usage is unaffected.
A common self-hosting bug is an idle-timeout or buffering proxy that cuts SSE streams. If runs “hang” in the UI but complete server-side, check your proxy’s buffering and timeout settings on the API host first.

Inbound from external SaaS (channel webhooks)

Agent and trigger channels differ in whether the external service pushes events to you (needs public inbound) or whether Noxus pulls them (outbound only). This is the single biggest restricted-networking consideration.
ChannelMechanismNeeds public inbound?Notes
WhatsApp (Cloud API)Meta POSTs to your webhookYesNo polling alternative — webhook is mandatory
Microsoft TeamsTeams POSTs change notificationsYesNo polling fallback
TelegramsetWebhook registers your URL; Telegram POSTs updatesYesA getUpdates polling fallback is not implemented
Generic webhook triggerExternal system POSTs to /webhook/{group_id}/{trigger_id}YesThe whole point is to receive external calls
Google ChatWebhook or Pub/SubOnly in webhook modeSwitch to Pub/Sub mode to make it outbound-only
SlackSocket Mode (outbound WS) or Events webhookNo, with Socket ModeSocket Mode opens an outbound WebSocket to Slack, so no inbound is needed
GmailRelay polls the Gmail APINoOutbound polling loop
Outlook / emailRelay polls the providerNoOutbound polling loop
Knowledge base syncWorker polls the sourceNoPeriodic outbound polling
In a private/VPN-only deployment you can still use Slack (Socket Mode), Gmail/Outlook, Google Chat in Pub/Sub mode, and KB sync — they never need an inbound path. The push channels (WhatsApp, Teams, Telegram, generic webhooks) require exposing the relay host to the internet; expose only relay.example.com and keep the app itself private if you want to minimise surface area.

Securing the relay endpoint

If you must expose the relay for push channels, restrict it: each provider signs or carries a secret on its webhook (Slack signing secret, Telegram secret token, WhatsApp/Meta app secret, per-trigger tokens for generic webhooks). Keep the relay host on its own subdomain so you can apply WAF/rate-limit rules independently of the app.

OAuth callbacks

When a user connects an integration (Google, Microsoft, Slack, GitHub…), the provider sends the user’s browser back to:
{BACKEND_URL}/integrations/oauth/callback
This is a 302 redirect in the user’s browser, not a server-to-server call from the provider. So the callback URL only needs to be reachable by your users’ browsers — the same audience as the rest of the app. The subsequent token exchange (backend → the provider’s token endpoint) is outbound (see Outbound). Implications:
  • If your users reach the app over a VPN, an internal BACKEND_URL works for OAuth — no public inbound required.
  • BACKEND_URL must exactly match the redirect URI registered in each OAuth app, and the frontend redirect_uri must share the configured FRONTEND_URL origin (the backend validates this).
  • If you can’t expose an OAuth callback at all, fall back to manual credential entry (static API tokens) for providers that support it.