Skip to content

Network & authentication

Out of the box CodeNavi listens on 127.0.0.1:8765 on the host — the MCP endpoint (/mcp), the web UI (/ui), the connect wizard (/connect) and /health all share that port. Prometheus metrics are on 9091. Nothing is reachable from another machine until you say so, and the auth token is what you turn on first when you do.

Variable Default Notes
Port CODENAVI_PORT 8765 MCP + web UI
Metrics port CODENAVI_METRICS_PORT 9091 Prometheus text format; also bearer-gated at GET /metrics on the API port
Host interface CODENAVI_HOST 127.0.0.1 The host-side interface Docker publishes the port on. 0.0.0.0 for LAN access.
Container bind CODENAVI_BIND 0.0.0.0 The in-container bind — not the same thing as CODENAVI_HOST; leave it.1
Auth token CODENAVI_AUTH_TOKEN (empty) Bearer token. Empty = no auth, fine only on 127.0.0.1.
Public URL CODENAVI_PUBLIC_URL http://localhost:<port> The origin clients reach the server at from outside (scheme + host + optional port, no path). Set it when a reverse proxy or tunnel fronts CodeNavi — see HTTPS in front of CodeNavi.

Authentication (bearer token)

Authentication is opt-in. When CODENAVI_AUTH_TOKEN is not set, the server accepts all requests (suitable for local development where the port is bound to 127.0.0.1).

To enable authentication:

  1. Generate a token:
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
  1. Set it in .env:
CODENAVI_AUTH_TOKEN=your-generated-token-here
  1. Restart the container:
docker compose down && docker compose up -d
  1. Configure your MCP client to send the token. In Claude Code's .mcp.json:
{
  "mcpServers": {
    "codenavi": {
      "type": "http",
      "url": "http://localhost:8765/mcp",
      "headers": {
        "Authorization": "Bearer your-generated-token-here"
      }
    }
  }
}

The /health endpoint is always unauthenticated, so monitoring tools work without tokens.

The server implements RFC 9728 OAuth Protected Resource metadata. MCP clients that support OAuth discovery will automatically detect whether auth is required by querying /.well-known/oauth-protected-resource.

Packaged and trial installs always issue a token — the installer prints it, and the connect wizard fills it into the client config for you.

Beyond localhost

Every recipe starts with the token above. Then, by shape:

You want Recipe
A second machine on the same LAN (another dev box, a Windows IDE talking to a Linux server) Remote access → Same LAN — CODENAVI_HOST=0.0.0.0 + token, plain HTTP
HTTPS from anywhere — phones, Claude Desktop Connectors, off-site Remote access → Tailscale Funnel / Cloudflare Tunnel / your own proxy
One shared server for the whole team, index following the repo Team server
Windows IDE ↔ CodeNavi in Docker Desktop or WSL2 on the same PC Windows — no proxy on the Docker Desktop path; netsh port proxy only for a self-managed WSL2 install
A CI runner calling the server CI review bots

Health and monitoring endpoints

GET /health is always unauthenticated but minimal without a token (status, version, auth_required — no codebase names, counts or models), so monitors work and an unauthenticated caller cannot inventory the deployment. The full diagnostic body needs the bearer token — see Setup guide → Health check. Metrics: Observability.

Outbound connections

With the shipped defaults the server makes no outbound connection at all after install: the embedder is in the image, the reranker is cached on first run (TRANSFORMERS_OFFLINE=1 afterwards), and search runs entirely on the box. The only outbound paths, each opt-in and visible: a cloud LLM provider for chat (Providers), the web crawler when you enable it (with an SSRF guard that refuses private and cloud-metadata addresses — Configuration), event hooks you configure (Webhooks), and the connected-install update check (Updating). An air-gapped install has none of them.


  1. Vendor change reference CN-84. ↩