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:
- Generate a token:
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
- Set it in
.env:
CODENAVI_AUTH_TOKEN=your-generated-token-here
- Restart the container:
docker compose down && docker compose up -d
- 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.
-
Vendor change reference CN-84. ↩