DEV Community

Cover image for Claude Code on VPS: systemd Setup That Survives Reboots
Aoba Works
Aoba Works

Posted on Originally published at en.aobaworks.com

Claude Code on VPS: systemd Setup That Survives Reboots

Originally published at Unattended.

Yes, Claude Code runs well on a VPS. Install it with Anthropic's native Linux installer, sign in once over SSH, and run your jobs headless with claude -p from a systemd timer. Your agent keeps working with the laptop closed and comes back by itself after a reboot. The parts that usually break are persistence (keeping it alive after reboots), auth tokens stored on the server, and security (SSH and firewall), so most of this guide covers those three.

Which option is right for you?

The right setup depends on how comfortable you are with Linux and whether the work needs files that live on your server.

Your situation What to pick first First page to open
Beginner, never managed a Linux server Hostinger's "Ubuntu 24.04 with Claude Code" template on a 4 GB+ plan, because Claude Code comes preinstalled Hostinger: How to use the Claude Code VPS template
You already have an Ubuntu or Debian VPS Native installer plus a systemd timer, because it auto-updates and survives reboots Claude Code advanced setup
Daily recurring work on GitHub repos, no server wanted Anthropic's cloud scheduled tasks, because no server is needed Automate work with scheduled tasks
Tight budget Smallest 4 GB KVM plan plus Claude Pro, because 4 GB is the documented minimum Claude pricing
Interactive coding from your phone tmux on the VPS plus Remote Control, because the session stays open between visits Remote Control docs
You're building a product others will use A Claude Console API key, because Anthropic's terms require it for that use Legal and compliance

Can Claude Code run on a VPS?

Yes. Claude Code is a terminal program, so it runs on any supported Linux VPS over SSH, and claude -p runs it with no interactive terminal.

Anthropic lists the system requirements as Ubuntu 20.04+, Debian 10+ or Alpine Linux 3.19+, "4 GB+ RAM", an x64 or ARM64 processor, and an internet connection (as of October 2026). The model runs on Anthropic's servers, so the VPS only needs room for the Claude Code process, your repository and your test tooling. It doesn't need a GPU or a desktop environment.

Headless mode is what makes unattended work possible. According to the headless docs, adding -p (or --print) to any claude command runs it non-interactively. Claude Code exits with code 0 on success and a non-zero code on failure, so systemd and cron can tell whether a run worked. For example:

claude -p "Run the test suite and summarize failures" --allowedTools "Bash,Read"
Enter fullscreen mode Exit fullscreen mode

Before you put a subscription on a server, read the usage rules. Anthropic's legal and compliance page says "Advertised usage limits for Pro and Max plans assume ordinary, individual usage of Claude Code and the Agent SDK." Your own agent working on your own repos fits that description. Running a service for other users on your Pro or Max login does not. Those users need their own credentials, and Anthropic says products should use Console API keys. The flag reference is in Claude Code Headless Mode: Flags, Auth and Cost (2026).

How do you install Claude Code on a VPS?

Run Anthropic's native installer as a non-root user, then confirm with claude --version.

The command is curl -fsSL https://claude.ai/install.sh | bash, the recommended method in the official setup page. One thing changed from older guides: you no longer need Node.js. Most articles from 2025 tell you to install Node 18 and use npm. According to the setup page, the npm package now requires Node.js 22 or later, and even then it just downloads the same native binary.

  1. SSH into the server: ssh you@203.0.113.10 (example IP).
  2. Create a dedicated user for the agent so it doesn't run as root: sudo adduser --disabled-password --gecos "" agent.
  3. Switch to that user: sudo -iu agent.
  4. Install: curl -fsSL https://claude.ai/install.sh | bash.
  5. Open a new shell (or run exec bash), then check the install: claude --version. A working install prints something like 2.1.211 (Claude Code).
  6. Run claude doctor. It checks the install and your settings without starting a session.
  7. Sign in (see the auth section below).

The native installer puts a launcher at ~/.local/bin/claude and updates itself in the background. On a server you won't watch, consider the stable channel, which runs about a week behind and skips releases with major regressions. Install it with curl -fsSL https://claude.ai/install.sh | bash -s stable, or put "autoUpdatesChannel": "stable" in ~/.claude/settings.json.

Common mistakes:

  • claude: command not found: ~/.local/bin isn't on your PATH. Hostinger's install guide fixes this with echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.profile.
  • Installed as root, running as another user: each user has their own ~/.local/bin and ~/.claude. Install as the user that will run the jobs.
  • Free plan: the setup docs say Claude Code needs a Pro, Max, Team, Enterprise or Console account. The free claude.ai plan doesn't include it.

How do you install Claude Code on an Ubuntu VPS?

On Ubuntu 20.04 or newer, use the native installer. If you'd rather update through apt, use Anthropic's signed apt repository instead. Use npm only if your tooling needs it.

Method Command Auto-updates Pick it if
Native installer `curl -fsSL https://claude.ai/install.sh \ bash` Yes, in the background
apt repository sudo apt install claude-code (after adding the repo) No, you update with apt upgrade You want version changes only when you run apt
npm npm install -g @anthropic-ai/claude-code Only if the npm global folder is writable Your existing tooling already manages Node

All three are documented on the Claude Code setup page (as of October 2026).

apt route, step by step (from the official page):

  1. sudo apt install curl gnupg
  2. sudo install -d -m 0755 /etc/apt/keyrings
  3. sudo curl -fsSL https://downloads.claude.ai/keys/claude-code.asc -o /etc/apt/keyrings/claude-code.asc
  4. Check the key: gpg --show-keys /etc/apt/keyrings/claude-code.asc. The fingerprint should be 31DDDE24DDFAB679F42D7BD2BAA929FF1A7ECACE.
  5. Add the stable repo: 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
  6. sudo apt update && sudo apt install claude-code

Ubuntu pitfalls and fixes:

  • sudo npm install -g: the setup docs warn against this because it "can lead to permission issues and security risks." If you use npm, install Node 22+ for your own user (nvm works) and install without sudo.
  • EBADENGINE warning on old Node: according to the setup docs, on Node versions below 22 npm prints a warning, but the install still completes and claude runs. Upgrading Node makes the warning go away.
  • NO_PUBKEY BAA929FF1A7ECACE from apt update: the key download failed. Check that the server can reach downloads.claude.ai, then run step 3 again.
  • Works over SSH, fails from systemd: systemd doesn't read ~/.bashrc or ~/.profile. Set PATH in the unit file (shown later).
  • Out-of-memory kills on a 1–2 GB VPS: the documented minimum is 4 GB. A cheap plan below that can fail during npm install or test runs, even if Claude Code itself starts.

How do you install Claude Code on a Hostinger VPS?

On Hostinger, the easiest route is to pick the "Ubuntu 24.04 with Claude Code" template, which comes with Claude Code installed. Then sign in over SSH or with the browser terminal.

Hostinger's template guide says you can reach the server with ssh root@[your-vps-ip] or from the Web Console in the Hostinger dashboard, then sign in with claude /login. If you'd rather start from plain Ubuntu, follow the Ubuntu steps above. Nothing about Hostinger changes them.

Plans (from Hostinger's Claude Code hosting page, as of October 2026; check the official page for current prices):

Plan vCPU / RAM Intro price Renews at
KVM 1 1 / 4 GB $6.49/mo (24-month term) $11.99/mo
KVM 2 2 / 8 GB $8.79/mo (24-month term) $14.99/mo
KVM 4 4 / 16 GB $12.99/mo (24-month term) $28.99/mo

Hostinger's hosting page notes that "All plans are paid upfront", so the monthly figure is the total price divided across the term. KVM 1 meets Anthropic's 4 GB minimum exactly. KVM 2 leaves room for builds and test runners. Hostinger suits beginners who want a preinstalled template and a browser terminal. If you need month-to-month billing at the advertised price, or a data center close to a particular region, compare other providers first.

Steps after the server is ready:

  1. Connect with SSH or the dashboard's Web Console.
  2. The template logs you in as root. Create the agent user (adduser --disabled-password --gecos "" agent) and copy your SSH key into /home/agent/.ssh/authorized_keys.
  3. Run sudo -iu agent, then claude --version. If the command isn't found for this user, run the native installer as agent. The template's copy may only be on root's PATH.
  4. Sign in as agent, not as root.

Hostinger firewall pitfall: the managed firewall lives under Security → Firewall. Click Add Firewall, name it, click Create, then the ⋯ button → Edit, and add rules with Add rule. Hostinger's firewall article warns that "An empty ruleset will block all traffic when applied to a server." Add an accept rule for SSH before you activate the group, or you'll lock yourself out. Hostinger says changes take effect in two minutes or less.

How do you set up Claude Code to run unattended on a VPS?

Use a systemd timer that triggers a service running claude -p.

Keep the auth token in a root-only environment file. This setup survives SSH disconnects (systemd owns the process, not your shell) and reboots (the timer is enabled at boot, and Persistent=true catches up on missed runs). tmux is good for interactive sessions you check on later, but a tmux session doesn't come back after a reboot.

Step 1: Create a long-lived token

On any machine with a browser (your laptop is easiest), run:

claude setup-token
Enter fullscreen mode Exit fullscreen mode

The authentication docs describe this as the method "For CI pipelines, scripts, or other environments where interactive browser login isn't available." The token lasts one year. It prints to the terminal once and isn't saved anywhere, so copy it right away. It requires Pro, Max, Team or Enterprise, and it can only make model requests. It can't start Remote Control sessions.

Alternatives: a Console ANTHROPIC_API_KEY (billed per token through the API). Or run claude interactively on the VPS. Over SSH, the browser can't reach the local callback, so paste the code at the Paste code here if prompted prompt. That login is saved to ~/.claude/.credentials.json with file mode 0600.

Step 2: Store it in a root-only environment file

sudo install -m 600 -o root -g root /dev/null /etc/claude-agent.env
sudo nano /etc/claude-agent.env
Enter fullscreen mode Exit fullscreen mode

Contents (example):

CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-REPLACE_ME
Enter fullscreen mode Exit fullscreen mode

systemd reads EnvironmentFile= before it switches to the agent user. So the agent's processes get the token, but the file stays unreadable to that user's shell and to anything Claude runs as a file read.

Two documented traps:

  • --bare ignores this token. The authentication docs say bare mode "does not read CLAUDE_CODE_OAUTH_TOKEN". If you add --bare, use ANTHROPIC_API_KEY instead.
  • A stray ANTHROPIC_API_KEY wins. In -p mode, the precedence rules say an API key "is always used when present." It ranks above the OAuth token, so a leftover key in the environment silently switches you to per-token API billing.

Step 3: Write the job script

/home/agent/jobs/nightly.sh (example; adjust the paths, prompt and tools):

#!/usr/bin/env bash
set -euo pipefail
cd /home/agent/repos/myapp
git pull --ff-only
claude -p "$(cat /home/agent/jobs/nightly-prompt.md)" \
  --permission-mode acceptEdits \
  --allowedTools "Read,Edit,Bash(npm test *),Bash(git diff *)" \
  --permission-prompts none \
  --max-budget-usd 3 \
  --output-format json > "/home/agent/logs/nightly-$(date +%F).json"
Enter fullscreen mode Exit fullscreen mode

Make it executable with chmod +x. According to the CLI reference, --permission-prompts none needs v2.1.259 or later. It denies anything that would otherwise wait for a person, so the run never hangs on a prompt. The JSON output includes total_cost_usd, which the headless docs describe as a client-side estimate. For safe allow-lists, see Claude Code Permissions Best Practices: Headless Template.

Step 4: Create the service and timer

/etc/systemd/system/claude-nightly.service:

[Unit]
Description=Nightly Claude Code job
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
User=agent
WorkingDirectory=/home/agent/repos/myapp
EnvironmentFile=/etc/claude-agent.env
Environment=PATH=/home/agent/.local/bin:/usr/local/bin:/usr/bin:/bin
ExecStart=/home/agent/jobs/nightly.sh
TimeoutStartSec=45min
Enter fullscreen mode Exit fullscreen mode

/etc/systemd/system/claude-nightly.timer:

[Unit]
Description=Run Claude nightly job at 02:30

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
RandomizedDelaySec=5min

[Install]
WantedBy=timers.target
Enter fullscreen mode Exit fullscreen mode

Then:

  1. sudo systemctl daemon-reload
  2. sudo systemctl start claude-nightly.service (one test run right now)
  3. journalctl -u claude-nightly.service -n 50 (read the result)
  4. sudo systemctl enable --now claude-nightly.timer
  5. systemctl list-timers | grep claude (confirm the next run time)

With Persistent=true, systemd records the last run time on disk. If the server was down when the job was due, the job runs right after boot.

When to use Restart=always instead

Use Restart=always only for a process that should never exit, such as your own chat-bot wrapper that calls Claude Code. systemd restarts it however it exits, and RestartSec defaults to 100ms. If a long-running agent hits a rate limit or an auth error, that default can create a tight restart loop that burns through your usage. Set RestartSec=60 or more. For retry logic around limits, see Claude Code Rate Limit Reached: Retry Setup for Cron Jobs.

Stopping a run: systemctl stop sends SIGTERM, and the headless docs say Claude Code then exits with code 143 and leaves the current turn unfinished. That's fine for a nightly job, but don't read code 143 in your logs as a crash.

How do you connect Claude Code to a VPS?

You connect to the VPS over SSH with a key, then run Claude Code in that remote shell. Claude Code doesn't attach to a server by itself.

  1. On your laptop, create a key if you don't have one: ssh-keygen -t ed25519.
  2. Copy it to the server: ssh-copy-id agent@203.0.113.10 (or paste the .pub file into the provider's SSH key field).
  3. Add a shortcut to ~/.ssh/config (example):
   Host agentbox
     HostName 203.0.113.10
     User agent
     IdentityFile ~/.ssh/id_ed25519
Enter fullscreen mode Exit fullscreen mode
  1. Connect with ssh agentbox.

Pick how you work once you're connected:

Way of working How Good for Limitation
tmux session tmux new -s agent, run claude, detach with Ctrl-b then d, come back with tmux attach -t agent Long interactive sessions you check later Lost on reboot
VS Code Remote-SSH Connect to agentbox and use the integrated terminal Editing files next to the agent Needs a laptop session open
Remote Control Start from a session signed in with your claude.ai account Checking in from your phone Doesn't work with a setup-token token
systemd timer The setup in the previous section Recurring jobs with no one watching Not interactive

Remote Control keeps running on the machine you started it from and reconnects when that machine is back online. On a VPS that machine never sleeps, which is why people pair it with tmux. To read the output of timer runs, journalctl -u claude-nightly.service and the JSON files in ~/logs cover most needs.

How do you secure a VPS running Claude Code?

Use key-only SSH, a firewall that opens only SSH, and a non-sudo agent user.

Also block root login. An always-on box that can push to your repos and holds a one-year token is a better target than your laptop. Claude Code connects out to Anthropic, so it needs no open inbound port of its own.

SSH hardening

OpenSSH's defaults are PasswordAuthentication yes and PermitRootLogin prohibit-password, so password logins are allowed unless you turn them off.

  1. Make sure your key login works for your sudo user first.
  2. Create /etc/ssh/sshd_config.d/99-hardening.conf:
   PasswordAuthentication no
   KbdInteractiveAuthentication no
   PermitRootLogin no
Enter fullscreen mode Exit fullscreen mode
  1. Check the config: sudo sshd -t. Then reload: sudo systemctl reload ssh.
  2. Keep your current session open, and log in from a second terminal before you close it.

Moving SSH to a non-default port cuts down log noise, but it doesn't replace key-only login. On Hostinger, any port change also needs a matching firewall rule.

Firewall

Ubuntu's firewall guide says "ufw by default is initially disabled." Turn it on in this order:

  1. sudo ufw allow OpenSSH
  2. sudo ufw enable
  3. sudo ufw status verbose

If you also use a provider firewall (Hostinger's, for example), both have to allow SSH. If either blocks it, you're locked out.

Agent-level hardening

  • No sudo for agent. If a prompt goes wrong, the damage stays inside /home/agent.
  • Scoped Git access. Use a deploy key or a fine-grained GitHub token limited to the repos the agent works on, and protect main with branch rules.
  • Token hygiene. /etc/claude-agent.env stays 600 root:root. Set a reminder to rotate it before the one-year expiry. If a token leaks, revoke it and run claude setup-token again.
  • Untrusted folders. Without --bare, a -p run loads hooks and .mcp.json servers from the project folder without a trust prompt, according to the headless docs. Only point jobs at repos you control.

Copy-paste rule sets are in AI Agent Guardrails Example: Copy-Paste Claude Code Rules.

How do you use Claude Code on a VPS for recurring tasks?

Give each recurring task its own prompt file, script and systemd timer. Then read the JSON output to check whether it worked.

Good jobs for a VPS (examples, not results):

  • Nightly test-and-fix: pull, run tests, fix what's obviously broken on a claude/nightly-fix branch, and open a draft PR.
  • Morning summary: read yesterday's git log and issue tracker export, then write reports/YYYY-MM-DD.md.
  • Weekly dependency check: list outdated packages, update the low-risk ones on a branch, run tests, and note what failed.

Each prompt should say what "done" looks like and what the agent must not touch. Name the branch it may push to and say which files are off-limits. One timer per job keeps logs separate and lets you pause a job with systemctl disable --now name.timer.

Which scheduler fits?

Scheduler Survives reboot Catches missed runs Local files on VPS Note
systemd timer Yes Yes, with Persistent=true Yes Most robust on a VPS
cron Yes No Yes Simpler syntax. See Claude Code Cron Job Setup
Anthropic cloud scheduled tasks Not your server n/a No, it clones GitHub repos Research preview, runs no more than hourly

Anthropic's scheduled tasks (formerly routines) run on Anthropic's cloud and are available on Pro, Max, Team and Enterprise. They reject cron expressions that run more often than once per hour and cap scheduled runs at 100 per hour per account (as of October 2026). Pick them when the work is only about GitHub repos. Pick the VPS when the work needs a database, local files or tools that only live on your server.

Catch silent failures. An exit code of 0 only means the process finished. Parse the JSON result field and fail the job if the expected output file is missing. Watch for the login-expiry warning, which the auth docs show three days before an interactive login expires. A monitoring setup is in AI Agent Monitoring in Claude Code: Catch Silent Failures.

Usage. Every run draws from the same plan limits as your interactive sessions. Claude Pro is $20/month billed monthly ($17/month on annual billing), and Max starts at $100/month, according to Claude's pricing page (as of October 2026; check the official page). If nightly jobs keep reaching the limit, cut the prompt's scope before you upgrade.

Next steps

Three things you can do today:

  1. Install Claude Code as a non-root agent user on your VPS, then run claude --version and claude doctor.
  2. Generate a token with claude setup-token, put it in /etc/claude-agent.env with mode 600, and turn on key-only SSH plus ufw.
  3. Write one small job (a read-only daily summary is a safe first choice). Wire it to a systemd timer, run it once with systemctl start, and read the journal.

If you'd rather not run a server: Anthropic's cloud scheduled tasks come with Pro ($20/month) and Max (from $100/month) as of October 2026 (check the pricing page). You create them at claude.ai/code/routines or with /schedule. They suit GitHub-centered work like PR reviews, issue triage and docs updates. They don't suit work that needs files or services that live only on your VPS, runs more often than hourly, or an API-key-only login. The feature is also still in research preview, so its limits may change. If you want a VPS but not the setup work, Hostinger's Claude Code template removes the install step. Hardening and scheduling are still up to you.

Related guides on this site:

FAQ

Can I install Claude Code on my own VPS without a dedicated dev machine?

Yes. You can do the whole setup from the VPS terminal or a provider's browser console. The one step that needs a browser is signing in. Over SSH, Claude Code shows a URL you open on any device (your phone works), and you paste the code back at the Paste code here if prompted prompt.

Does Claude Code on a VPS require a GUI or desktop environment?

No. The CLI needs a supported Linux (for example Ubuntu 20.04+ or Debian 10+), 4 GB+ RAM and an internet connection. Headless -p runs don't need an interactive terminal at all. A desktop app exists, but a server doesn't need it.

What do Reddit users say about running Claude Code on a VPS long-term?

Forum threads are individual reports, so this guide doesn't repeat them as fact. The long-term issues that are documented are logins that expire (setup tokens last one year), usage limits shared with your interactive sessions, background auto-updates, and processes that don't come back after a reboot. If you plan for those four, the most common long-term failures are covered.

Is a VPS or a local machine better for running Claude Code 24/7?

For around-the-clock jobs, a VPS is the better choice. It doesn't sleep, it has a fixed IP for SSH, and systemd brings jobs back after a reboot. A local machine is better for interactive work on private files you don't want on a server. If your recurring work is all on GitHub, Anthropic's cloud scheduled tasks let you skip owning a machine.

Sources


This article was created with the help of AI. Sources are linked inline; check the official documentation for the latest details.

Top comments (0)