Ports & Networking
Change the frontend and backend ports, understand NEXT_PUBLIC_API_PORT, and what happens when a port is already in use.
TokenTelemetry runs two services:
- Frontend (Next.js) — default port 13000
- Backend (FastAPI) — default port 18000
Both ports are configurable. The defaults sit away from 3000 and 8000, which most dev servers use, so TokenTelemetry can run next to your own projects. They match the Docker setup. Versions before September 2026 used 3000 and 8000; ./start.sh --port 3000 --api-port 8000 brings those back.
Changing ports
Use the --port / -p flag for the frontend and --api-port / -a flag for the backend:
# Custom frontend port only (backend stays 18000):
./start.sh --port 4000
./start.sh -p 4000
# Custom backend port only (frontend stays 13000):
./start.sh --api-port 9000
./start.sh -a 9000
# Both:
./start.sh --port 4000 --api-port 9000Valid port range: 1–65535.
How the frontend finds the backend
The frontend derives the backend URL from window.location at runtime:
- It takes the hostname from the browser URL (e.g.
localhost,192.168.1.42,box.tailnet.ts.net). - It substitutes the API port from
NEXT_PUBLIC_API_PORT(which the launcher sets automatically to match--api-port).
This means that if you open the dashboard from a remote address (because you used --host), the frontend automatically talks to the backend at that same remote address on the API port. You don't need to configure anything extra.
NEXT_PUBLIC_API_PORT
NEXT_PUBLIC_API_PORT is set by the launcher to match the --api-port value. You can override it manually if you're running the frontend separately from the backend (e.g. in development):
NEXT_PUBLIC_API_PORT=9000 npm run devNEXT_PUBLIC_API_BASE (explicit override)
NEXT_PUBLIC_API_BASE lets you pin the full backend URL, overriding the auto-derived value. This is useful for SSH-tunnel setups where the frontend and backend are on different hosts from the browser's perspective:
NEXT_PUBLIC_API_BASE=http://localhost:18000 ./start.shSee Remote Access for the SSH-tunnel pattern where this is needed.
Port-in-use behaviour
The launcher checks both ports before starting. If either port is already occupied, it prints an error and exits:
ERROR: required port(s) already in use: 13000
Stop whatever is listening on those ports and try again.
Tip: `lsof -iTCP:13000 -sTCP:LISTEN` shows the culprit.On Windows:
Tip: `netstat -ano | findstr :13000` shows the culprit PID.This fail-fast behavior prevents the common problem where Next.js silently bumps to port 3001 and the auto-opened browser lands on the wrong URL.
To free a port:
# macOS / Linux — find the process:
lsof -iTCP:13000 -sTCP:LISTEN
# Kill it:
kill <PID>Or just pick a different port with --port.
Loopback-only by default
Both services bind to 127.0.0.1 by default. They are not reachable from other devices on your network without explicitly using --host. See Remote Access for instructions on exposing the dashboard to other devices.