Running Claude Code on a server is the moment two different questions get tangled together, and answering the wrong one wastes an afternoon.
The first question is how do I log in on a machine with no browser. The second is how do I stop the session dying when my laptop lid closes.
They have different answers, and neither is a tunnel. This walks through both, plus the traps that only appear on a server and never on a laptop.
When a server session is the right call
Be honest about this first, because the cheapest fix is not doing it.
Claude Code on the web runs sessions on Anthropic's cloud infrastructure. Nothing on your machine has to stay awake, there is no tmux, and there is no login-over-SSH problem. If your task is "work on a repo, run its tests, open a PR," that is usually the correct tool.
A session on your own server earns its place when the work needs that specific box:
- The data lives there and is not leaving.
- It sits inside a network your laptop cannot reach.
- It runs the long-lived process you are debugging.
- It has MCP servers, credentials, or toolchains configured locally.
If none of those apply, stop here and use the web.
Step 1: install on the server
The native installer covers macOS, Linux, and WSL:
curl -fsSL https://claude.ai/install.sh | bash
On a machine you would rather not pipe a script into, Anthropic publishes signed apt, dnf, and apk repositories. The apt route on Debian or Ubuntu:
sudo apt install curl gnupg
sudo install -d -m 0755 /etc/apt/keyrings
sudo curl -fsSL https://downloads.claude.ai/keys/claude-code.asc \
-o /etc/apt/keyrings/claude-code.asc
gpg --show-keys /etc/apt/keyrings/claude-code.asc
Confirm the fingerprint reads 31DDDE24DDFAB679F42D7BD2BAA929FF1A7ECACE before you trust it, then register the repository:
echo "deb [signed-by=/etc/apt/keyrings/claude-code.asc] https://downloads.claude.ai/claude-code/apt/stable stable main" \
| sudo tee /etc/apt/sources.list.d/claude-code.list
sudo apt update
sudo apt install claude-code
Two details that matter on a server:
- Package manager installs do not auto-update. Updates arrive through your normal system upgrade workflow, so a box you never patch will drift. The native installer updates itself in the background.
- Node.js is not needed at runtime. Even the npm package (
npm install -g @anthropic-ai/claude-code) just pulls in a per-platform native binary; the installedclaudedoes not invoke Node.
Alpine needs its dependencies spelled out and USE_BUILTIN_RIPGREP set to 0:
apk add bash curl libgcc libstdc++ ripgrep
The USE_BUILTIN_RIPGREP value goes in the env block of your settings.json, not the shell:
{
"env": {
"USE_BUILTIN_RIPGREP": "0"
}
}
Verify with claude --version, then claude doctor for a read-only diagnostic that does not start a session.
Step 2: log in without a browser
This is where most people stall.
Run claude and use /login. Claude Code prints a URL. Open it in a browser on your laptop, sign in, and you will notice it does not redirect back the way it does locally. Instead it shows a login code.
That is expected, and Anthropic documents why: the browser cannot reach Claude Code's local callback server, "which is common in WSL2, SSH sessions, and containers."
Paste the code back into the terminal at the Paste code here if prompted prompt. Done.
Quick Win: If the terminal does not open the browser at all, press
cto copy the login URL to your clipboard.
Where the credential lands
On Linux, in ~/.claude/.credentials.json with file mode 0600.
On macOS, normally the encrypted Keychain, but with a fallback that trips people up: when the Keychain rejects the write, "such as when it's locked in an SSH session," Claude Code writes the same ~/.claude/.credentials.json file instead. If you SSH into a Mac, that is the path your login actually took.
If you set CLAUDE_CONFIG_DIR, the credentials file moves under that directory, and a session with a different CLAUDE_CONFIG_DIR reads a different credential entirely.
The setup-token trap
claude setup-token mints a one-year OAuth token you export as CLAUDE_CODE_OAUTH_TOKEN. On a server, this looks exactly like the right answer: no browser dance, no expiry to babysit.
It is the right answer for CI and scripts. It is the wrong answer for an interactive server session, and the reason is not obvious until you hit it.
That token can only make model requests. It cannot establish a Remote Control session, so you lose the ability to pick the session up from your phone or another machine. The error, when you eventually try, is:
Remote Control requires a full-scope login token
The fix is claude auth login. Decide which of the two you want before you set the variable in a shell profile you will forget about.
Step 3: keep the session alive
Now the real question. You have three options and they are not interchangeable.
Option A: tmux (or screen)
This is the documented answer for a Remote Control session on a remote machine. From the Remote Control docs: "To keep a session running on a remote machine after you disconnect from SSH, start it inside tmux or screen."
The whole recipe:
# on the server
tmux new -s claude # or: tmux attach -t claude
cd /srv/your-project
claude --remote-control "prod debugging"
Detach with Ctrl-b then d. Close the SSH connection, close the laptop, go somewhere. Later:
ssh your-server
tmux attach -t claude
A slightly nicer version that reattaches if the session exists and creates it if it does not, worth putting in your shell profile on the server:
# ~/.bashrc on the server
cc() {
tmux new-session -A -s claude -c "${1:-$PWD}"
}
tmux new-session -A attaches to an existing session named claude or creates it. Run cc /srv/your-project and you land in the same place every time.
Option B: background sessions
Claude Code has its own answer to "keep working with no terminal open," and on a server it is genuinely useful.
claude --bg "run the migration dry-run and report what would change"
It prints a short id and returns immediately. Per the agent view docs, "Background sessions don't need any terminal open to keep working. A separate supervisor process runs them, so you can close agent view, close your shell, or start a new interactive session and your dispatched work keeps going."
The management commands:
claude agents # list every session, grouped by state
claude attach <id> # open one in this terminal
claude logs <id> # print recent output without attaching
claude stop <id> # stop it; the conversation is kept
claude respawn <id> # restart it, resuming its saved conversation
claude rm <id> # remove it from the list
The boundary to keep in mind: sessions are local to that machine. They survive sleep and a closed shell. They do not survive the machine shutting down.
Option C: do not keep it alive at all
Claude Code on the web. No process of yours has to stay up. Covered above; it is the option people skip past because they already started down the SSH path.
Choosing
| You want | Use | Why |
|---|---|---|
| To steer a long task from your phone later | tmux + claude --remote-control | The documented path for Remote Control on a remote machine |
| To fire off work and collect the result | claude --bg | Supervisor process, no terminal needed, claude logs to check in |
| To keep several tasks going in parallel | claude remote-control --spawn worktree | Each on-demand session gets its own git worktree |
| Nothing that needs this box | Claude Code on the web | No process to keep alive at all |
The two are not mutually exclusive. tmux keeps an interactive session and its Remote Control connection alive; --bg keeps dispatched work alive. Use whichever matches what you are actually protecting.
Step 4: reach it from somewhere else
With the session running inside tmux, Remote Control lets you pick it up from a browser or the Claude app instead of SSHing back in.
claude --remote-control
Or, inside a session you already started, /remote-control. It prints a session URL and can show a QR code. Your machine opens no inbound ports; the local process makes outbound HTTPS requests to the Anthropic API and polls for work.
The full mechanism, the security model, and what you can and cannot do from a phone are covered in the Remote Control walkthrough. Two things from it matter specifically on a server:
- Server mode gives up faster. If the machine is awake but cannot reach the network,
claude remote-controlexits after roughly 10 minutes. An interactive session started withclaude --remote-controlretries for as long as the outage lasts. On a flaky VPS, prefer the interactive form inside tmux. - An expired login stops an unattended session cold. Anthropic notes this directly: a background session or a Remote Control session that outlives its login "stops making progress once the credential expires and can't recover until you sign in again." Claude Code warns at startup within three days of expiry, and
/statusshows aLoginrow readingExpired — log in again. On a box you rarely open, that warning is easy to never see.
The server-specific traps
These never bite on a laptop and reliably bite on a server.
Hardening flags silently disable Remote Control
DISABLE_TELEMETRY, DO_NOT_TRACK, CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC, and DISABLE_GROWTHBOOK each disable the feature-flag evaluation that Remote Control availability depends on. Any one of them, set in the shell environment or in a settings file's env block, is enough.
Server base images and hardening playbooks set DO_NOT_TRACK routinely. If Remote Control works on your laptop and not on the box, check this before anything else:
env | grep -E 'DISABLE_TELEMETRY|DO_NOT_TRACK|DISABLE_NONESSENTIAL|DISABLE_GROWTHBOOK'
Gateways and alternative endpoints rule it out entirely
Remote Control needs a direct connection to api.anthropic.com. It is unavailable on Amazon Bedrock, Google Cloud's Agent Platform, and Microsoft Foundry, when ANTHROPIC_BASE_URL points at an LLM gateway or proxy, or when you sign in through an enterprise Claude apps gateway. The error names what routed the session away.
This is common on corporate infrastructure, where routing through a gateway is exactly the reason the server exists. There is no workaround; use Claude Code on the web or work in the terminal.
Workspace trust does not follow you home
Run claude in the project directory once and accept the trust dialog. The startup trust dialog never saves trust for your home directory, so start from a project directory rather than ~.
claude doctor tells you which check failed
Rather than guessing among the above:
claude doctor
It prints install health, settings-file validation errors, and, when Remote Control is off, which individual eligibility check failed.
Permissions on an unattended box
One thing worth settling before you leave a session running somewhere you are not watching.
A server session that stops on every permission prompt is not doing work while you sleep, and the temptation is to reach for --dangerously-skip-permissions. Anthropic is explicit that bypassPermissions should only be used "in isolated environments like containers or VMs where Claude Code can't cause damage," and on Linux and macOS as a non-root user.
A production server is the opposite of that environment. The better shape is an explicit allowlist plus deny rules, which is a topic of its own: how to stop Claude Code asking permission for everything without turning safety off.
If the box genuinely is disposable, --sandbox on a Remote Control server adds filesystem and network isolation, off by default.
Conclusion
The two problems have two answers, and neither of them is a tunnel.
Logging in over SSH is a paste-the-code flow, not a broken browser. Keeping the session alive is tmux for an interactive session you want to steer later, or claude --bg for work you want to collect the result of.
Everything else on this page is the list of things that look like they should work on a server and do not: setup-token quietly costing you Remote Control, and a hardening variable someone set two years ago quietly costing you the same thing.
Working out where an agent belongs in your infrastructure? Book a free consultation with Evalics and we will map it against what you already run.
Related Resources
- How to Use Claude Code on Mobile with Remote Control - the full mechanism and security model behind the
--remote-controlflag used above - How to Stop Claude Code Asking Permission for Everything - what to do instead of
--dangerously-skip-permissionson a server - Introduction to Claude Code: Anthropic's Agentic CLI Tool Explained
- n8n MCP vs Claude Code: Which Automation Approach Wins
Official Sources
- Claude Code: advanced setup
- Claude Code: authentication
- Claude Code: Remote Control
- Claude Code: background sessions and agent view
- Claude Code: permission modes
By Kevin Michael Schindler, AI Automation Expert at Evalics
