Skip to Content
GuidesSelf-host on a server

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 installed

Point 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 enable

Add 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 EOF

NAVFLOW_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 obtained

Verify

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_VERSION in .env, then docker 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.
Last updated on