Claude Code

    How to Run Claude Code on a Remote Server and Keep It Alive

    Claude Code on a VPS dies the moment your SSH session drops. Here is how to log in on a headless box, keep the session running, and reach it again later.

    12 min read
    How to Run Claude Code on a Remote Server and Keep It Alive

    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 installed claude does 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 c to 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 wantUseWhy
    To steer a long task from your phone latertmux + claude --remote-controlThe documented path for Remote Control on a remote machine
    To fire off work and collect the resultclaude --bgSupervisor process, no terminal needed, claude logs to check in
    To keep several tasks going in parallelclaude remote-control --spawn worktreeEach on-demand session gets its own git worktree
    Nothing that needs this boxClaude Code on the webNo 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-control exits after roughly 10 minutes. An interactive session started with claude --remote-control retries 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 /status shows a Login row reading Expired — 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.

    Official Sources

    By Kevin Michael Schindler, AI Automation Expert at Evalics

    Ready to automate your business?

    Book a free consultation and discover how AI automation can save you hours every week.

    Frequently Asked Questions