Jean logoJean

Web Access and Headless

Expose Jean over its built-in HTTP server or run it without the desktop window.

Jean includes an embedded HTTP server for browser access.

This is useful when you want to keep the app running on another machine, open it from a browser, or use the headless mode as a long-lived workspace host.

What web access provides

The HTTP server serves the frontend and keeps the app state connected over WebSocket.

In practice, that means you can:

  • open Jean in a browser
  • keep using the same projects, worktrees, and sessions
  • copy a tokenized URL for quick access

Default behavior

The safe baseline is:

  • HTTP server disabled
  • localhost-only binding
  • token required

That is the right place to start unless you have a clear reason to expose Jean more broadly.

What you can configure

From Preferences, you can control:

  • whether the server is running
  • port
  • bind host
  • auto-start behavior
  • whether a token is required
  • token regeneration

Jean can also list likely bind host options for the machine so you do not have to guess the address manually.

Headless mode

To run Jean without the desktop window:

jean --headless --host 127.0.0.1 --port 3456

Swap the host if you need network access, but keep token protection enabled unless you have a stronger access layer in front of it.

When headless mode starts, Jean prints the browser URL. If token auth is enabled, the URL includes the token as a query parameter.

Options and environment variables

CLI optionEnvironment variableDefault
--headlessJEAN_HEADLESS=1off
--host <addr>JEAN_HOSTsaved preference, usually 127.0.0.1
--port <port>JEAN_PORT3456
--token <token>JEAN_TOKENsaved or generated token
--no-tokenJEAN_NO_TOKEN=1off
--allow-unsafe-no-tokenJEAN_ALLOW_UNSAFE_NO_TOKEN=1off
n/aJEAN_ALLOWED_ORIGINSsame-origin only

Jean refuses --no-token with --host 0.0.0.0 or --host :: unless you also pass --allow-unsafe-no-token. Prefer leaving token auth on.

jean-server

Packaged server deployments can use the jean-server entrypoint. It is the same Jean backend, started with headless mode enabled by default:

jean-server --host 127.0.0.1 --port 3456

On Linux, Jean still needs a display backend because the Tauri/GTK runtime initializes even without a visible window. If you run the raw binary on a server without DISPLAY, start it with xvfb-run or provide an X/Wayland display:

xvfb-run -a jean-server --host 0.0.0.0 --port 3456 --token "$JEAN_TOKEN"

Docker image

Jean publishes a server image from the server release workflow:

ghcr.io/coollabsio/jean-server:<tag>

The container starts Xvfb automatically before launching jean-server. Bind to 0.0.0.0 inside the container, keep token auth enabled, and mount Jean's app-data directory so projects, preferences, and sessions persist.

docker run --rm \
  -e JEAN_HEADLESS=1 \
  -e JEAN_HOST=0.0.0.0 \
  -e JEAN_PORT=3456 \
  -e JEAN_TOKEN=change-me-long-random-token \
  -p 127.0.0.1:3456:3456 \
  -v jean-data:/home/jean/.local/share/com.jean.desktop \
  ghcr.io/coollabsio/jean-server:latest

Keep the host-side port bind on 127.0.0.1 when you are putting Caddy, Nginx, Tailscale, or an SSH tunnel in front of Jean.

Health checks

Use these endpoints for process checks and deployment probes:

  • GET /healthz — process is alive
  • GET /readyz — HTTP server and WebSocket broadcaster are initialized

Authenticated API endpoints accept either ?token=... or an HTTP bearer token:

curl -H "Authorization: Bearer $JEAN_TOKEN" http://127.0.0.1:3456/api/auth
curl "http://127.0.0.1:3456/api/init?token=$JEAN_TOKEN"

A simple remote setup

  1. Start Jean in headless mode, with jean-server, or with the Docker image.
  2. Keep it on a loopback bind if you only need local browser access.
  3. If you need remote access, bind intentionally and keep the token on.
  4. Put TLS and access control in front of Jean for internet-facing deployments.
  5. Copy the generated URL with the token appended when needed.

Reverse proxy and Tailscale

Reverse proxies do not need to rewrite paths. The browser UI uses /api/init, /api/auth, and /ws from the same origin.

A minimal Caddy route looks like this:

jean.example.com {
  encode zstd gzip
  reverse_proxy 127.0.0.1:3456
}

For Tailscale-only access, bind directly to your Tailscale IP and keep token auth enabled:

jean --headless --host 100.x.y.z --port 3456 --token "$JEAN_TOKEN"

Use this when

Web access and headless mode make sense when:

  • Jean runs on a dedicated development machine
  • you want browser access to long-running work
  • you need to check session state without opening the desktop app

Next reads

On this page