# 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. ## Start from the default `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: 1. **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. 2. **Prefer keeping the loopback bind** and putting an authenticated tunnel in front of it, over binding wide and relying on a password alone. ## Pick an approach | 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. | ## Tailscale (recommended) 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: ```bash install.sh tailscale ``` By hand: ```bash tailscale serve --bg 3000 tailscale serve status ``` Then open `https://..ts.net` from any device on your tailnet. Notes: - Keep the loopback bind. `tailscale serve` connects to `127.0.0.1:3000` locally, so binding wider adds exposure and buys nothing. - Your tailnet is the authentication boundary. Setting `CODEMAN_PASSWORD` as 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 `serve` mappings other than the one pointing at Codeman's port, so unrelated serve configuration is left alone. ## Cloudflare tunnel A free [quick tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/do-more-with-tunnels/trycloudflare/) 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`](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/) installed, and `CODEMAN_PASSWORD` set. ```bash ./scripts/tunnel.sh start # starts the tunnel, prints the public URL ./scripts/tunnel.sh url ./scripts/tunnel.sh status ./scripts/tunnel.sh stop ``` The 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: ```bash systemctl --user enable codeman-tunnel loginctl enable-linger $USER ``` There 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. ## LAN plus password ```bash export CODEMAN_PASSWORD='something long' codeman web -H 0.0.0.0 --https ``` Every 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. ## SSH port forward No configuration at all, if you already have SSH access: ```bash ssh -L 3000:localhost:3000 you@your-box ``` Then 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. ## Logging in from a phone 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, `Referer` headers, 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`](https://github.com/Ark0N/Codeman/blob/master/docs/qr-auth-plan.md). ## Behind a reverse proxy 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: ```bash 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. ## Session cookies and rate limits 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. ## Terminal alternatives You do not have to use a browser. `sc` is a thumb-friendly session chooser for SSH clients like Termius or Blink: ```bash sc # interactive chooser sc 2 # attach to session 2 sc -l # list ``` Detach with `Ctrl+A D`. The sessions are the same ones the dashboard shows. ## Common problems | 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. | ## Read next - [Security](Security) - the whole model, and the hardening checklist. - [Mobile Guide](Mobile-Guide) - once you can reach it from the phone. - [Running As A Service](Running-As-A-Service) - keeping server and tunnel up across reboots. - [`docs/security-architecture.md`](https://github.com/Ark0N/Codeman/blob/master/docs/security-architecture.md) - the full model.