usher can add an Open in editor action to each session. Configure it with an
URL template containing {cwd}:
usher serve --editor-url 'https://code.example.com/?folder={cwd}'usher replaces {cwd} with the session's working directory. The editor, not
usher, is responsible for interpreting that value and enforcing access.
For a local desktop editor, a protocol URL also works:
usher serve --editor-url 'vscode://file{cwd}'Keep code-server separate from usher. Route each service to its own hostname so they retain separate authentication boundaries:
cloudflared tunnel route dns devbox usher.example.com
cloudflared tunnel route dns devbox code.example.comtunnel: devbox
credentials-file: /home/you/.cloudflared/<TUNNEL-UUID>.json
ingress:
- hostname: usher.example.com
service: http://localhost:7777
- hostname: code.example.com
service: http://localhost:8080
- service: http_status:404Then run the three processes:
usher serve --editor-url 'https://code.example.com/?folder={cwd}'
code-server --bind-addr 127.0.0.1:8080
cloudflared tunnel run devboxAn exposed editor is effectively shell access. Apply a Cloudflare Access policy
to code.example.com as well, or at minimum keep code-server's built-in
password authentication enabled.
Use a separate HTTPS port for code-server while keeping both services bound to loopback:
usher serve --editor-url 'https://<machine>.<tailnet>.ts.net:8443/?folder={cwd}'
tailscale serve --bg 7777
code-server --bind-addr 127.0.0.1:8080
tailscale serve --bg --https=8443 8080This produces:
https://<machine>.<tailnet>.ts.netfor usher.https://<machine>.<tailnet>.ts.net:8443for code-server.
Avoid mounting either application below a URL subpath. Tailscale Serve's proxy mode forwards the full request path without stripping the mount prefix, while both usher and code-server expect to own the URL root.
See Access usher remotely for tunnel setup and authentication guidance.