If Jean Web Access works in a browser but the native Jean app, phone, or another tailnet device cannot connect, check whether Jean is being reached directly over HTTP or through Tailscale Serve.
Recommended setup
Use Tailscale Serve as the tailnet entrypoint and bind jean-server to localhost:
# /etc/jean-server.env
JEAN_HOST=127.0.0.1
JEAN_PORT=3456
JEAN_TOKEN=<long-random-token>
JEAN_ALLOWED_ORIGINS=*Restart Jean and publish it through Tailscale Serve:
sudo systemctl restart jean-server.service
sudo tailscale serve --https=443 off
sudo tailscale serve --bg http://127.0.0.1:3456
tailscale serve statusUse the HTTPS Tailscale Serve URL everywhere, including phones and the native Jean desktop app:
https://<machine-name>.<tailnet-name>.ts.net/?token=<JEAN_TOKEN><machine-name> is the device name in Tailscale. You can choose any name you want in Tailscale (for example, jean-server, build-box, or home-lab) and use that name in the URL.
For example, if you named the device jean-server in Tailscale:
https://jean-server.tail71152.ts.net/?token=<JEAN_TOKEN>Why the direct Tailscale IP may stop working
When JEAN_HOST=127.0.0.1, Jean only listens on the server itself. That is intentional for the recommended Tailscale Serve setup. Other tailnet devices cannot connect directly to:
http://100.x.y.z:3456They must use the Tailscale Serve HTTPS URL instead. Tailscale Serve receives the tailnet HTTPS request and proxies it locally to http://127.0.0.1:3456 on the server.
Quick checks
From any tailnet device, these should return 200 OK:
curl -i https://<machine-name>.<tailnet-name>.ts.net/readyz
curl -i 'https://<machine-name>.<tailnet-name>.ts.net/api/auth?token=<JEAN_TOKEN>'Expected /readyz body:
{"http":true,"ok":true,"websocket_broadcaster":true}If the HTTPS URL returns a proxy error, confirm jean-server is listening on 127.0.0.1:3456 and restart Tailscale Serve.
Is this a Jean issue?
This is mostly a deployment/configuration gotcha for Jean servers behind a tailnet, not a core Jean server bug. The confusing part is that there are two valid modes:
Tailscale Serve mode (recommended): JEAN_HOST=127.0.0.1, connect with https://...ts.net/?token=....
Direct tailnet HTTP mode: JEAN_HOST=100.x.y.z or 0.0.0.0, connect with http://100.x.y.z:3456/?token=....
The modes are easy to mix up. If Jean binds to localhost, direct Tailscale IP access will fail. If Jean binds to the Tailscale IP, Tailscale Serve must proxy to that IP instead of 127.0.0.1, or it will fail.
Related
Deploy a Seed Site From Your Own Fork — the author's other self-hosting guide: running your own Seed site from a fork with custom GHCR images
2026-03-19: Tech Sync — where Jean is discussed as the Claude Code GUI in the Seed team's agent-tooling sync
This developer docs are amazing and we should copy this patterns — how the Seed team uses Jean in its workflow and what it admires about Jean's developer docs
Do you like what you are reading? Subscribe to receive updates.
Unsubscribe anytime