Skip to main content
Jason Finance
AI Startup

Running Claude Code Remote Control on a Free Oracle Cloud Server: PAYG, Ampere A1 and an Always-On systemd Setup

Run Claude Code Remote Control on an Oracle Cloud Always Free Ampere A1 VM: PAYG, ARM64 setup, GitHub access and systemd to survive SSH disconnects, with fixes.

On this page
  1. 1.Overall architecture: Oracle provides the server, the Claude subscription is separate
  2. 2.Oracle’s free allowance: two official documents give different numbers
  3. 3.Step 1: Sign up for Oracle, upgrade to PAYG, and set a budget first
  4. 4.Step 2: Create the Ampere A1 VM
  5. 5.Step 3: Connect over SSH, update the system and create dedicated users
  6. 6.Step 4: Install Claude Code and sign in
  7. 7.Step 5: GitHub access: the SSH key handles code, gh handles Issues
  8. 8.Step 6: Start Remote Control manually to test it
  9. 9.Step 7: Turn it into an always-on systemd service
  10. 9.1How to confirm it really is always-on
  11. 10.Multiple projects, multiple Remote Controls
  12. 11.Common errors at a glance
  13. 12.Security, backups and cost
  14. FAQ

I hand off website and product work to Claude Code from my phone. Claude Code runs on an Oracle Cloud ARM server, and Remote Control lets me connect to it from my phone or a browser. Each project has its own systemd service, set up to keep running after SSH disconnects and to start automatically when the server reboots. This post is the full set of steps from a real setup in October 2026, including the errors I ran into and how I fixed them.

The short version: the server can be an Oracle Always Free Ampere A1, but Claude Code needs its own Pro, Max, Team or Enterprise subscription. Upgrading to Pay As You Go (PAYG) lets the account use more kinds of resources, but it does not guarantee you will get a server, and it can incur charges. ā€œAlways-onā€ comes from a systemd user service plus linger, not from any service promising it will never disconnect.

This is my own setup log, not an official tutorial. Oracle’s free allowances and Claude Code’s commands and supported plans can change. I checked the official documentation on 12 October 2026; before you follow along, go by the latest official guidance and your own bill. Usernames and URLs in the commands are examples; replace them with your own.

Overall architecture: Oracle provides the server, the Claude subscription is separate

iPhone / Mac / browser
        │  Claude Code Remote Control (connected via Anthropic's service)
        ā–¼
Oracle Cloud VM: Ubuntu 24.04 / ARM64 (Ampere A1)
  ā”œā”€ Linux user: project-a  → Git repo A → claude-project-a.service
  ā”œā”€ Linux user: project-b  → Git repo B → claude-project-b.service
  └─ Linux user: content    → separate worktree → claude-content.service
Component What it does Cost
Oracle Cloud VM Provides an always-on Linux server Free within the Always Free limits; charged above them
Claude Code Writes code, edits files and runs commands on the server Needs a Claude subscription (Remote Control supports Pro, Max, Team, Enterprise)
GitHub Code lives in the repo; Claude Code pushes and pulls with an SSH key Depends on your GitHub plan
systemd user service Keeps running after SSH disconnects, starts at boot, restarts on failure Built into Ubuntu

Oracle only provides the server and does not cover Claude’s model costs. ā€œFreeā€ in this post refers only to the server, not to the whole AI development setup.

Oracle’s free allowance: two official documents give different numbers

Official document (checked 12 October 2026) Ampere A1 free allowance
Always Free Resources First 1,500 OCPU hours and 9,000 GB hours per month, roughly 2 OCPUs and 12 GB of memory for Always Free accounts
Arm-based Compute First 3,000 OCPU hours and 18,000 GB hours per month (including paid and trial accounts)

Since the two disagree, I plan around the conservative 2 OCPU / 12 GB, estimating about 750 hours a month:

Configuration OCPU hours GB hours Against the conservative allowance
1 VM with 2 OCPU / 12 GB 1,500 9,000 Within the allowance
2 VMs with 1 OCPU / 6 GB each 1,500 9,000 Within the allowance
1 VM with 4 OCPU / 24 GB 3,000 18,000 May exceed it; check your own account first

A few more official rules worth knowing:

  • It must be in your Home Region: Always Free servers have to be created in the tenancy’s home region, and disks outside the home region are charged at regular prices.
  • Total disk: boot volumes and block volumes share 200 GB in total, plus 5 volume backups. The same document gives the minimum boot volume as both 47 GB and 50 GB; go by what the Console shows.
  • Idle servers may be reclaimed: if, over 7 consecutive days, the 95th percentile of CPU utilization, network utilization and memory utilization (A1 only) are all below 20%, Oracle may reclaim the server. Don’t generate fake load just to avoid reclamation.

Step 1: Sign up for Oracle, upgrade to PAYG, and set a budget first

  1. Sign up for an OCI account on the Oracle Cloud website and complete identity and payment method verification.
  2. Think before you pick a Home Region: Always Free servers can only be created there, so don’t treat it as something you can change at any time later. Decide based on where you are, latency and A1 availability.
  3. If you want to upgrade, find Upgrade at the top of the Console, choose Pay As You Go and follow the official steps. According to Oracle’s documentation, resources that meet the Always Free conditions stay free after the upgrade.
  4. Set a budget right after upgrading: Billing & Cost Management → Budgets → Create Budget. Set a low monthly budget with email alerts. Budgets only send alerts and do not block charges automatically, so you still need to check Cost Analysis regularly.

Whether PAYG makes it easier to create an A1 depends on the region, timing and actual capacity, so I won’t claim that ā€œupgrading gets you one.ā€

Step 2: Create the Ampere A1 VM

  1. Compute → Instances → Create Instance. Check the Compartment, Home Region and Availability Domain.
  2. For Image, choose Ubuntu 24.04 and make sure it is the ARM64 (aarch64) build.
  3. For Shape, choose VM.Standard.A1.Flex and start with 1 OCPU / 6 GB or 2 OCPU / 12 GB.
  4. For Capacity type, choose On-demand. Don’t choose Preemptible for an always-on server.
  5. Let Oracle choose the Fault Domain automatically.
  6. Use a sensible minimum boot volume, and first check that you have free disk allowance left.
  7. Networking: open TCP 22 (SSH) only to the sources that need it. Remote Control normally doesn’t need any extra inbound ports opened.
  8. For the SSH key, paste the public key (the .pub file). Never paste the private key into the Console or any chat.

Generate an SSH key on a Mac:

ssh-keygen -t ed25519 -f ~/.ssh/oci_claude -C 'oci-claude'
cat ~/.ssh/oci_claude.pub

If you see Out of host capacity when creating the instance, there is temporarily no host capacity for the options you chose. It is not a problem with your SSH key, image or credit card. I cover the troubleshooting order and what PAYG actually does in What to Do About Oracle’s Out of host capacity.

Step 3: Connect over SSH, update the system and create dedicated users

chmod 600 ~/.ssh/oci_claude
ssh -i ~/.ssh/oci_claude ubuntu@<YOUR_VM_PUBLIC_IP>

You can set up a short name in ~/.ssh/config on the Mac, so afterwards you only need ssh my-claude-vm:

Host my-claude-vm
    HostName <YOUR_VM_PUBLIC_IP>
    User ubuntu
    IdentityFile ~/.ssh/oci_claude
    IdentitiesOnly yes

On the VM, update the system, install the tools and confirm it is ARM64:

sudo apt update && sudo apt upgrade -y
sudo apt install -y git curl ca-certificates jq unzip gh
uname -m   # should be aarch64
free -h

Don’t run every project under ubuntu or root. Create a Linux user for each project that needs separate permissions, and enable linger so its systemd services keep running when nobody is logged in:

sudo adduser --disabled-password --gecos '' project-a
sudo loginctl enable-linger project-a
loginctl show-user project-a -p Linger   # should be Linger=yes

If memory runs short, you can add swap (swap is not RAM and adds disk reads and writes). Before running this, check with df -h that you have enough disk space, and don’t append to /etc/fstab more than once:

sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
printf '/swapfile none swap sw 0 0\n' | sudo tee -a /etc/fstab

Step 4: Install Claude Code and sign in

Switch to the project user to install it. Don’t use sudo to install it into root’s home directory:

sudo -iu project-a
curl -fsSL https://claude.ai/install.sh | bash
~/.local/bin/claude --version
~/.local/bin/claude   # first run: follow the on-screen steps to sign in

Once you have signed in, you can exit the interactive Claude session. For installation, follow the official setup guide. Two things to watch:

  • Remote Control only supports claude.ai subscription sign-in: if ANTHROPIC_API_KEY is set in the environment, the official documentation says you will see ā€œRemote Control requires claude.ai subscription auth.ā€
  • Don’t copy ~/.claude/ to other users: each Linux user signs in on their own.

Step 5: GitHub access: the SSH key handles code, gh handles Issues

As the project user, generate an SSH key just for GitHub and add the public key to GitHub (as a personal SSH key, or as a Deploy key for a single repo, which has narrower permissions):

mkdir -p ~/.ssh && chmod 700 ~/.ssh
ssh-keygen -t ed25519 -f ~/.ssh/github -C 'project-a-github'
cat ~/.ssh/github.pub
cat >> ~/.ssh/config <<'EOF'
Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/github
    IdentitiesOnly yes
EOF
chmod 600 ~/.ssh/config
ssh -T git@github.com
mkdir -p ~/projects && cd ~/projects
git clone git@github.com:<OWNER>/<REPO>.git

Something I ran into: Git could push, but Claude Code said it couldn’t read GitHub Issues. The reason is that the SSH key only covers Git transfers; reading Issues and PRs requires a separate sign-in with the GitHub CLI. The steps and the permission risks are in Claude Code Can’t Read GitHub Issues.

Step 6: Start Remote Control manually to test it

Run this inside the project’s repo directory:

sudo -iu project-a
cd ~/projects/<REPO>
~/.local/bin/claude remote-control --name 'My Project - Development' --spawn=worktree

The first time, it asks Enable Remote Control? (y/n); answer y. Once it succeeds, the screen shows the connection status. Check in the Claude app on your phone or at claude.ai/code that you can see this environment, then press Ctrl+C to stop the manual test.

According to the official documentation, claude remote-control is server mode. Common flags:

Flag What it does
--name "name" The name shown in the claude.ai/code list
--spawn worktree Each new session gets its own git worktree (requires a git repo); the default, same-dir, has everyone share the current directory
--capacity <N> Maximum concurrent sessions, 32 by default
-c, --continue Resume the session the server last opened in this directory
--debug-file <path> Writes debug logs to a file, useful when troubleshooting startup failures

--spawn=worktree only separates working directories. It is not permission isolation at the operating system level.

Step 7: Turn it into an always-on systemd service

As the project user, create a user service (replace project-a, my-repo and the name with your own):

mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/claude-my-repo.service <<'SERVICE_UNIT'
[Unit]
Description=Claude Code Remote Control - My Repo
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
WorkingDirectory=/home/project-a/projects/my-repo
ExecStart=/home/project-a/.local/bin/claude remote-control --name "My Project - Development" --spawn=worktree
Restart=on-failure
RestartSec=15
Environment=HOME=/home/project-a
Environment=PATH=/home/project-a/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MemoryHigh=2500M
MemoryMax=3500M
NoNewPrivileges=true
UMask=0077

[Install]
WantedBy=default.target
SERVICE_UNIT

After writing it, check that the file is complete. I have had a heredoc that never ended and a missing [Install] section:

tail -n 12 ~/.config/systemd/user/claude-my-repo.service

Then go back to the admin account ubuntu to start the service. Running systemctl --user directly in a sudo -iu shell gave me Failed to connect to bus: No medium found, so you need to specify the user’s runtime directory and D-Bus explicitly (the reason is in systemctl –user No medium found):

exit   # back to ubuntu
uid=$(id -u project-a)
sudo loginctl enable-linger project-a

sudo -u project-a XDG_RUNTIME_DIR="/run/user/$uid" \
  DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$uid/bus" \
  systemctl --user daemon-reload

sudo -u project-a XDG_RUNTIME_DIR="/run/user/$uid" \
  DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$uid/bus" \
  systemctl --user enable --now claude-my-repo.service

MemoryHigh and MemoryMax are per-service limits. When running several services, adjust them to the server’s actual memory.

How to confirm it really is always-on

sudo -u project-a XDG_RUNTIME_DIR="/run/user/$uid" \
  DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$uid/bus" \
  systemctl --user status claude-my-repo.service --no-pager -l
  1. It shows Active: active (running). enabled is not the same as running: I once had a service that showed enabled but was actually inactive (dead).
  2. The log has a successful connection message and the name you set. My successful log showed Capacity: 1/32 Ā· New sessions will be created in an isolated worktree, which matches the official default limit of 32.
  3. You can see this environment on your phone or in the browser, and you can start new work in it.
  4. Close SSH completely and reconnect; the service is still running.
  5. At a time when nothing important is running, reboot to test whether it comes back automatically.

To read the logs or restart a single service:

sudo -u project-a XDG_RUNTIME_DIR="/run/user/$uid" \
  DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$uid/bus" \
  journalctl --user -u claude-my-repo.service -n 80 --no-pager

sudo -u project-a XDG_RUNTIME_DIR="/run/user/$uid" \
  DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$uid/bus" \
  systemctl --user restart claude-my-repo.service

Restart only the one that has a problem, so you don’t interrupt the other Remote Control sessions that are running.

Multiple projects, multiple Remote Controls

I run several environments on the same server: different products use different Linux users, while ā€œdevelopmentā€ and ā€œwriting articlesā€ for the same repo are split into two working directories and two services with git worktree. When to use separate users, how to create the worktrees, and what to watch with branches and PRs are covered in Running Multiple Claude Code Remote Controls on One Server.

Common errors at a glance

Symptom Check first What to do
Out of host capacity Availability Domain, Fault Domain, shape Automatic Fault Domain, another AD, a smaller shape, try again later
SSH timeout IP, Security List, SSH key Fix the network and keys first; don’t open ports to everyone
claude: command not found PATH Use the full path ~/.local/bin/claude
systemctl --user shows No medium found linger, user bus, XDG_RUNTIME_DIR Run it from ubuntu, specifying the UID and D-Bus
enabled but inactive (dead) Whether it was stopped manually, the logs Read the journal, then start it
Repeated status=1/FAILURE Logs, sign-in, working directory Stop the restart loop first, then run it manually as the same user to see the real error
Remote Control disappears when SSH closes Whether it was only run manually Create a systemd user service and enable linger
Git can push but Issues can’t be read Git over SSH is not the GitHub API Authorize separately with gh auth login
exec format error Whether the downloaded program is the ARM64 build Switch to the Linux ARM64 build; changing permissions won’t fix it
Charges appear on the bill Resources over the limit, disks, backups, network Check Cost Analysis and adjust resources

For startup failures such as status=1/FAILURE, I first stop that service, read journalctl --user -u <service> -n 100, then switch to the same user and directory and run claude remote-control manually. I deal with the real error message once I have it, rather than guessing whether it is sign-in, the network or the number of concurrent connections. The official documentation also notes that in server mode the process exits on its own after a network outage of roughly 10 minutes, so the service needs automatic restart configured.

Security, backups and cost

  • Keep keys private: never put SSH private keys, GitHub tokens, ~/.claude/ or ~/.config/gh/ in a repo, a systemd unit file or a screenshot.
  • Least privilege: projects that touch production or databases get their own Linux user; NoNewPrivileges=true is not a complete sandbox.
  • GitHub only protects what has been pushed: uncommitted changes, worktrees and Claude’s local settings are not backed up automatically, so commit and push important changes.
  • Check the bill every week: OCPU hours, GB hours, disks, backups and network traffic. If you want to claim it costs nothing per month, you need that month’s bill to back it up.
  • A daily health check:
PROJECT_USER=project-a
uid=$(id -u "$PROJECT_USER")
loginctl show-user "$PROJECT_USER" -p Linger
sudo -u "$PROJECT_USER" XDG_RUNTIME_DIR="/run/user/$uid" \
  DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$uid/bus" \
  systemctl --user --no-pager --failed
free -h
df -h /
uptime

--failed only lists failed services, so you still need to confirm that important services are active (running). Restart=on-failure also can’t fix an expired sign-in or an outage at an external service.

This setup is where Jason Finance runs every day. For how the site itself was built, see Jason Finance from Zero to One. More posts are on the AI startup topic page.

FAQ

Is Oracle Cloud Always Free really free?

Resources that meet the Always Free conditions and limits are free, and they stay free after upgrading to Pay As You Go; resources beyond the limits are charged. For the Ampere A1 free allowance, two official Oracle documents give different figures (1,500 OCPU hours / 9,000 GB hours per month, versus 3,000 / 18,000). This post uses the conservative 2 OCPU and 12 GB; your account's Always Free labels and your bill are what count.

Does upgrading to Pay As You Go guarantee I can create an Ampere A1 instance?

No. PAYG lets the account use more kinds of resources, but it does not add physical host capacity in a region, so you can still hit Out of host capacity. A PAYG account can also incur real charges, and Budgets only send alerts; they do not block charges automatically.

Which plans does Claude Code Remote Control need?

According to the Claude Code documentation, Remote Control supports the Pro, Max, Team and Enterprise plans and does not support API keys. It is off by default on Team and Enterprise, and an Owner has to turn it on in the Claude Code admin settings.

Does Claude Code keep running after I close SSH?

If you run it directly in the SSH window, the process usually ends when the connection closes. With a systemd user service plus loginctl enable-linger, the process keeps running after SSH disconnects and also starts automatically after the server reboots.

Does Permanent Remote Control mean it never disconnects?

No. In this post, always-on means it starts automatically, restarts automatically on failure and keeps running after SSH disconnects. It is not an availability guarantee from Oracle or Anthropic. The official documentation also says that in server mode the claude remote-control process exits after a network outage of roughly 10 minutes.

Can Oracle's ARM64 servers run Claude Code?

Yes. My environment is Ubuntu 24.04 aarch64 (Ampere A1). I installed Claude Code with the official install script and started Remote Control successfully. When downloading other tools, check that a Linux ARM64 build exists.

Related articles

About the author

Photo of Jason

Jason

Account Manager in Google Large Customer Sales and Columbia MBA admit, sharing the money tools and experience he actually uses.

Comments

Sign in with Google to comment. Your comment will not show your Google profile picture or name; it appears under a randomly generated nickname to protect your privacy.

By signing in you agree to this site's privacy policy.

  1. Loading comments…