-
Notifications
You must be signed in to change notification settings - Fork 98
Remote Access
Reaching your Codeman from a phone, a laptop on the other side of the house, or a hotel network. This is the page to read carefully, because Codeman's dashboard is a remote-code-execution surface by design: it starts agents with permission prompts skipped, so whoever can reach it can run code on your machine.
codeman web binds 127.0.0.1. It is reachable from the machine running it and nothing
else, which is why the no-password default is safe out of the box. Every option below is a
deliberate step away from that.
Two rules that make the rest of this page simple:
-
Never expose Codeman on a network without
CODEMAN_PASSWORD. Binding a non-loopback host without one starts, but prints a loud warning with the fixes. - Prefer keeping the loopback bind and putting an authenticated tunnel in front of it, over binding wide and relying on a password alone.
| Approach | Good for | Cost |
|---|---|---|
| Tailscale | Phone access, permanently. The recommended setup. | Install Tailscale on both devices. |
| Cloudflare tunnel | A public URL, quickly, from anywhere. | Public URL, so a password is mandatory. |
| LAN + password | Home network only, no extra software. | Every device on your LAN can reach the login page. |
| SSH port forward | You already SSH to the box. | Manual, per session, terminal-bound. |
Your devices join a private network, and Codeman stays bound to loopback. Nothing is published to the internet, and you get real HTTPS with a real certificate.
The installer sets this up for you, including installing Tailscale, logging in, enabling tailnet HTTPS, and verifying the result end to end. To retrofit it onto an existing install:
install.sh tailscaleBy hand:
tailscale serve --bg 3000
tailscale serve statusThen open https://<machine>.<tailnet>.ts.net from any device on your tailnet.
Notes:
- Keep the loopback bind.
tailscale serveconnects to127.0.0.1:3000locally, so binding wider adds exposure and buys nothing. - Your tailnet is the authentication boundary. Setting
CODEMAN_PASSWORDas well is reasonable defence in depth, especially if other people have devices on your tailnet. - Codeman's Host-header allowlist already accepts
.ts.net, so no extra configuration is needed. - The installer never resets or rewrites
servemappings other than the one pointing at Codeman's port, so unrelated serve configuration is left alone.
A free quick tunnel gives you a public HTTPS URL with no port forwarding, no DNS, and no static IP:
Browser → Cloudflare edge (HTTPS) → cloudflared → localhost:3000
Prerequisites: cloudflared
installed, and CODEMAN_PASSWORD set.
./scripts/tunnel.sh start # starts the tunnel, prints the public URL
./scripts/tunnel.sh url
./scripts/tunnel.sh status
./scripts/tunnel.sh stopThe quick-tunnel URL is a random *.trycloudflare.com address that changes every time the
tunnel restarts. For a stable hostname, ./scripts/tunnel.sh named setup walks through a
named tunnel.
To survive reboots:
systemctl --user enable codeman-tunnel
loginctl enable-linger $USERThere is also a toggle in App Settings → System → Remote access.
The tunnel refuses to start without a password. That is on purpose: a public URL with no authentication is a terminal on your machine handed to the internet. Acknowledging the risk explicitly is possible from the UI toggle, and only from there; the API will not do it for you.
export CODEMAN_PASSWORD='something long'
codeman web -H 0.0.0.0 --httpsEvery device on your local network can now reach the login page. --https generates a
self-signed certificate into ~/.codeman/certs/, which your browser will warn about once.
CODEMAN_USERNAME defaults to admin.
The installer offers this path and prompts for the password. On re-runs it preserves whichever binding you already chose.
No configuration at all, if you already have SSH access:
ssh -L 3000:localhost:3000 you@your-boxThen open http://localhost:3000 on the local machine. Codeman keeps its loopback bind and
sees a local connection. Good for occasional access, awkward as a permanent arrangement
because it dies with the SSH session.
Typing a long password on a phone keyboard is miserable, so Codeman issues single-use QR tokens. The desktop dashboard shows a QR code; scan it and the phone is authenticated.
How it behaves:
- The code rotates every 60 seconds, with a 90 second grace window so scanning during a rotation still works.
- Each token is single use. The moment a phone consumes it, a new one is generated.
- The URL contains a 6-character lookup code, not the secret, so it does not leak through
browser history,
Refererheaders, or the tunnel provider's logs. - The desktop shows a toast naming the device and browser that just authenticated, with a one-click revoke.
- QR attempts are rate limited separately from password attempts, so a mistyped password cannot lock out your QR login and vice versa.
Someone holding only the tunnel URL still meets the normal password prompt. The QR is the fast path, not a bypass.
Design detail and the threat analysis it is built against:
docs/qr-auth-plan.md.
Codeman enforces a Host-header allowlist on every request to block DNS rebinding, and the
same allowlist gates the cross-site Origin check. It accepts localhost, IP literals, the
bind host, .ts.net, .trycloudflare.com, .cfargotunnel.com, and the active managed
tunnel.
Your own domain is not on that list. Add it:
CODEMAN_ALLOWED_HOSTS='codeman.example.com,.internal.example.com'A bare entry matches that exact host; a leading dot matches subdomains. Without this, a
correctly configured proxy still gets 403 host not allowed, which reads like a proxy bug
and is not one.
Also make sure the proxy forwards WebSocket upgrades. The terminal is a WebSocket, and the
upgrade runs the same Host and Origin checks, closing with code 4003 on failure.
The first request prompts for HTTP Basic credentials. On success the server issues an opaque
codeman_session cookie (24 hour lifetime, extended on activity, validated server-side so
it cannot be forged offline). Ten failed attempts from one IP produce a 429 with a 15
minute decay.
A valid cookie or a correct password recovers immediately even while an attacker is hammering the same IP, which matters because all tunnel traffic arrives from one loopback address.
You do not have to use a browser. sc is a thumb-friendly session chooser for SSH clients
like Termius or Blink:
sc # interactive chooser
sc 2 # attach to session 2
sc -l # listDetach with Ctrl+A D. The sessions are the same ones the dashboard shows.
| Symptom | Cause and fix |
|---|---|
403 host not allowed |
Your domain is not in the allowlist. Set CODEMAN_ALLOWED_HOSTS. |
| Phone shows the login page but the terminal never connects | The proxy is not forwarding WebSocket upgrades. |
| Browser warns about the certificate | Expected with --https and its self-signed certificate. Tailscale gives you a real one instead. |
| LAN IP does not respond, but a tunnel to the same box works | The server is bound to loopback. That is the default. A tunnel reaches it; a LAN browser cannot. |
| Hooks stopped working after switching to HTTPS | Hook callbacks need -k for the self-signed certificate. Recent versions self-heal existing cases; if yours predates that, recreate the case's hooks. |
| Everything is slow over the tunnel | Quick tunnels route through Cloudflare's edge. Tailscale is usually a direct connection and much faster. |
- Security - the whole model, and the hardening checklist.
- Mobile Guide - once you can reach it from the phone.
- Running As A Service - keeping server and tunnel up across reboots.
-
docs/security-architecture.md- the full model.
Documents Codeman 1.20.x. Something wrong or missing on this page? These pages are
generated from docs/wiki/ in
the main repository, so browser edits here are overwritten on the next sync. Send a pull
request against that directory instead, or open a
Discussion.
Getting started
Using it
- The Dashboard
- Agent CLIs
- Working With Files
- Input And Voice
- Mobile Guide
- Keyboard Shortcuts
- Settings Reference
Keeping agents running
Where it runs
Access & security
Automation
Operating it