Self-host on a server
Run a single-tenant NavFlow instance on a server: the daemon, the MCP server, and a reverse proxy
(Caddy) that terminates TLS and serves one hostname. DuckDB is single-writer, so this is exactly one
navflowd and one volume.
Provision a host
Any Linux host with Docker. A 1 GB VM is sufficient — it pulls a prebuilt image, it does not build.
curl -fsSL https://get.docker.com | sh # if Docker isn't installedPoint DNS
Create an A record for your hostname (e.g. navflow.example.com) pointing at the host’s IP. Caddy
needs this resolving before it can obtain a TLS certificate.
Open the firewall
Allow SSH and HTTP/HTTPS:
ufw allow 22 && ufw allow 80 && ufw allow 443 && ufw --force enableAdd the compose and config
Create the docker-compose.yml and Caddyfile from
Deployment → Self-hosted (compose) on the host. Then set the
secrets and domain:
cat > .env <<EOF
NAVFLOW_AUTH_TOKEN=$(openssl rand -hex 24)
NAVFLOW_DOMAIN=navflow.example.com
EOFNAVFLOW_AUTH_TOKEN is the bearer token for the console and agents. Keep it.
Pull and start
docker compose pull
docker compose up -d
docker compose logs -f caddy # wait for the certificate to be obtainedVerify
curl -s https://navflow.example.com/health
# {"status":"ok","auth_required":true,...}Open https://navflow.example.com and log in with NAVFLOW_AUTH_TOKEN.
Connect a remote agent
The MCP endpoint is served at /mcp on the same hostname. From a workstation:
claude mcp add --transport http navflow https://navflow.example.com/mcp \
--header "Authorization: Bearer <NAVFLOW_AUTH_TOKEN>"Operate
- Upgrade — pin a version with
NAVFLOW_VERSIONin.env, thendocker compose pull && docker compose up -d. - Back up — snapshot the host, or copy the data volume’s
navflow.duckdb. - Auth — the console, API, and MCP require the token. For per-user SSO, front the console with a proxy (oauth2-proxy, Tailscale); ingest and MCP keep their bearer tokens. See Deployment → Authentication.