Delx

Claude Code Remote Control: Run AI Agents on Any Server

Running Claude Code on your local machine works fine for solo development. But the real power unlocks when you run it on remote servers — headless CI/CD runners, cloud VMs, dedicated VPS instances, or Docker containers. Remote Claude Code lets you automate codebases at scale, run long agent sessions without tying up your laptop, and integrate AI agents into existing infrastructure pipelines. This guide covers everything you need to set up Claude Code on a remote server, connect it to MCP servers, secure the deployment, and monitor sessions with Delx.

Why Run Claude Code Remotely

Most developers start with Claude Code on their local machine, running it in a terminal alongside their editor. That works for interactive coding sessions. But several scenarios demand a remote setup:

CI/CD automation — You want Claude Code to review pull requests, fix failing tests, or generate documentation as part of your build pipeline. The agent runs headlessly on a GitHub Actions runner or a Jenkins node without any human interaction.

Long-running tasks — Refactoring a large codebase or migrating a framework can take hours. Running the agent on a VPS means you can close your laptop and come back to completed work. The session persists on the server regardless of your local connection.

Team-shared agents — A remote Claude Code instance can be configured with project-specific MCP servers, custom instructions, and API keys that the whole team shares. No more per-developer setup drift.

Resource isolation — Running agents on a dedicated VM keeps resource-intensive operations (large builds, test suites, container deployments) off your local machine. Your laptop stays fast while the agent grinds through compilation on a 16-core server.

Air-gapped or restricted environments — Some production codebases live behind firewalls. Running Claude Code directly on a server inside the network eliminates the need to expose code externally.

SSH Tunneling for Remote Claude Code Sessions

The simplest way to use Claude Code remotely is to SSH into the server and run it directly in the remote shell. Claude Code is a CLI tool — it runs wherever Node.js runs. No GUI needed.

# SSH into your remote server
ssh user@your-server.example.com

# Run Claude Code interactively
claude

# Or run a one-shot command
claude -p "Explain the authentication flow in this codebase"

For persistent sessions that survive SSH disconnects, use tmux or screen:

# Start a tmux session on the remote server
ssh user@your-server.example.com
tmux new -s claude-session

# Run Claude Code inside tmux
cd /path/to/your/project
claude

# Detach with Ctrl+B, then D
# Reconnect later:
ssh user@your-server.example.com
tmux attach -t claude-session

If your remote Claude Code instance needs to reach MCP servers running on your local machine (or vice versa), use SSH port forwarding:

# Forward local port 3100 to remote server's localhost:3100
# Useful when your MCP server runs locally and Claude Code runs remotely
ssh -R 3100:localhost:3100 user@your-server.example.com

# Forward remote port 8080 to your local machine
# Useful when a remote MCP server needs to be accessed locally
ssh -L 8080:localhost:8080 user@your-server.example.com

Using the --print Flag and API Mode

For non-interactive (headless) usage, Claude Code provides the --print flag (or its alias -p). This sends a single prompt, prints the response, and exits — perfect for scripting and CI/CD:

# One-shot mode: send a prompt, get a response, exit
claude -p "Find all TODO comments in the src/ directory and list them"

# Pipe input from a file
cat error_log.txt | claude -p "Analyze these errors and suggest fixes"

# Use in a CI script
claude -p "Review the changes in this PR and write a summary" > pr_review.md

# JSON output mode for programmatic parsing
claude -p "List all exported functions in src/index.ts" --output-format json

For multi-turn headless sessions, you can use the --resume flag with a session ID to continue previous conversations:

# Start a session and capture the session ID
SESSION_ID=$(claude -p "Start refactoring the auth module" \
  --output-format json | jq -r '.session_id')

# Continue the session later
claude -p "Now update the tests for the changes you made" \
  --resume "$SESSION_ID"

The --allowedTools flag lets you restrict which tools Claude Code can use in headless mode, which is critical for security in automated pipelines:

# Only allow read operations and MCP tools, no file writes
claude -p "Analyze this codebase" \
  --allowedTools "Read,Grep,Glob,mcp__delx__checkin"

Setting Up Claude Code on a VPS (Ubuntu/Debian)

Here is a step-by-step setup for a fresh Ubuntu 22.04+ or Debian 12+ VPS. This covers Node.js installation, Claude Code setup, authentication, and project configuration.

# 1. Update system packages
sudo apt update && sudo apt upgrade -y

# 2. Install Node.js 20+ (required for Claude Code)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

# 3. Verify installation
node --version   # Should be v20.x or higher
npm --version

# 4. Install Claude Code globally
npm install -g @anthropic-ai/claude-code

# 5. Set your Anthropic API key
export ANTHROPIC_API_KEY="sk-ant-your-key-here"

# To persist across sessions, add to your shell profile:
echo 'export ANTHROPIC_API_KEY="sk-ant-your-key-here"' >> ~/.bashrc
source ~/.bashrc

# 6. Verify Claude Code works
claude --version
claude -p "Hello, confirm you are running correctly"

For a production setup, create a dedicated user for Claude Code instead of using root:

# Create a dedicated user
sudo useradd -m -s /bin/bash claude-agent
sudo su - claude-agent

# Install Claude Code for this user
npm install -g @anthropic-ai/claude-code

# Clone the project repository
git clone https://github.com/your-org/your-project.git
cd your-project

# Set up MCP servers for this project
cat > .mcp.json << 'EOF'
{
  "mcpServers": {
    "delx": {
      "url": "https://api.delx.ai/mcp"
    }
  }
}
EOF

# Run Claude Code
claude

Docker Container Setup for Claude Code

Running Claude Code in a Docker container provides isolation, reproducibility, and easy deployment across environments. Here is a production-ready Dockerfile:

# Dockerfile for Claude Code agent
FROM node:20-slim

# Install git and common build tools
RUN apt-get update && apt-get install -y \
    git \
    curl \
    jq \
    && rm -rf /var/lib/apt/lists/*

# Install Claude Code globally
RUN npm install -g @anthropic-ai/claude-code

# Create a non-root user
RUN useradd -m -s /bin/bash agent
USER agent
WORKDIR /home/agent

# Copy project files and MCP configuration
COPY --chown=agent:agent . /home/agent/project
COPY --chown=agent:agent .mcp.json /home/agent/project/.mcp.json

WORKDIR /home/agent/project

# Default command: run Claude Code in print mode
ENTRYPOINT ["claude"]
CMD ["-p", "Waiting for instructions"]

Build and run the container:

# Build the image
docker build -t claude-code-agent .

# Run with your API key (never bake keys into the image)
docker run --rm \
  -e ANTHROPIC_API_KEY="sk-ant-your-key-here" \
  claude-code-agent \
  -p "Analyze the project structure and summarize"

# Run interactively with a mounted volume
docker run -it --rm \
  -e ANTHROPIC_API_KEY="sk-ant-your-key-here" \
  -v $(pwd):/home/agent/project \
  claude-code-agent

# Docker Compose for persistent agent setup
# docker-compose.yml
# services:
#   claude-agent:
#     build: .
#     environment:
#       - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
#     volumes:
#       - ./:/home/agent/project
#     stdin_open: true
#     tty: true

For CI/CD pipelines, you can use the container as a step in your workflow. Here is a GitHub Actions example:

# .github/workflows/claude-review.yml
name: Claude Code PR Review
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Claude Code
        run: npm install -g @anthropic-ai/claude-code

      - name: Run Claude Code Review
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          claude -p "Review the changes in this PR. \
            Focus on bugs, security issues, and performance. \
            Output a markdown summary." > review.md

      - name: Post Review Comment
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const review = fs.readFileSync('review.md', 'utf8');
            github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: review
            });

Connecting Remote MCP Servers

When Claude Code runs on a remote server, it can connect to MCP servers just like it does locally. The configuration goes in .mcp.json in the project directory on the remote machine:

// .mcp.json on the remote server
{
  "mcpServers": {
    "delx": {
      "url": "https://api.delx.ai/mcp"
    },
    "internal-api": {
      "url": "http://localhost:4000/mcp",
      "headers": {
        "Authorization": "Bearer ${MCP_INTERNAL_TOKEN}"
      }
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  }
}

HTTP-based MCP servers (like Delx) work out of the box — Claude Code makes HTTPS requests to the server URL. No special networking required.

stdio-based MCP servers (like the GitHub server above) spawn a local process on the remote machine. Make sure the required packages are installed on the server.

Private MCP servers behind firewalls can be reached via SSH tunneling. If your MCP server runs on an internal host at port 3100, forward it:

# On the remote server where Claude Code runs:
# Forward internal-mcp-host:3100 to localhost:3100
ssh -L 3100:internal-mcp-host:3100 jump-server

# Then in .mcp.json, reference localhost:
{
  "mcpServers": {
    "internal": {
      "url": "http://localhost:3100/mcp"
    }
  }
}

Security Considerations for Remote Access

Running an AI agent on a remote server requires careful security hygiene. Here are the essential practices:

1. SSH key-only authentication — Disable password login entirely. Use ED25519 keys for the strongest security:

# Generate a strong SSH key
ssh-keygen -t ed25519 -C "claude-code-server"

# Copy to server
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-server.example.com

# Disable password authentication on the server
# /etc/ssh/sshd_config:
#   PasswordAuthentication no
#   PubkeyAuthentication yes
sudo systemctl restart sshd

2. Dedicated non-root user — Never run Claude Code as root. Create a dedicated user with restricted permissions:

# Create user with limited home directory
sudo useradd -m -s /bin/bash claude-agent
sudo chmod 750 /home/claude-agent

# Only grant access to the project directory
# No sudo privileges

3. Environment variable secrets — Never hardcode API keys in configuration files or Dockerfiles. Use environment variables, secrets managers, or Docker secrets:

# Use environment variables (set in .bashrc or systemd unit)
export ANTHROPIC_API_KEY="sk-ant-..."

# Or use a secrets manager
ANTHROPIC_API_KEY=$(vault kv get -field=key secret/claude-code)

# Docker: pass at runtime, never in Dockerfile
docker run -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" claude-agent

4. Restrict tool permissions — In headless mode, explicitly whitelist the tools Claude Code can use. This prevents unintended file modifications or command execution:

# Read-only mode: only analysis tools
claude -p "Audit this code for security issues" \
  --allowedTools "Read,Grep,Glob"

# Allow MCP but no local file writes
claude -p "Check agent health" \
  --allowedTools "Read,Grep,Glob,mcp__delx__checkin,mcp__delx__session_summary"

5. Firewall rules — Restrict outbound traffic to only the APIs Claude Code needs (Anthropic API, your MCP servers, package registries). Block everything else:

# UFW example: allow only necessary outbound connections
sudo ufw default deny outgoing
sudo ufw allow out to any port 443   # HTTPS (Anthropic API, MCP)
sudo ufw allow out to any port 22    # SSH
sudo ufw allow out to any port 53    # DNS
sudo ufw enable

For a comprehensive security checklist, see Claude Code Security Guide.

Monitoring Remote Agent Sessions with Delx

Running Claude Code remotely introduces a visibility gap: you cannot watch the agent work in real time. Delx fills this gap by providing telemetry and wellness monitoring that works regardless of where the agent runs.

Add Delx to your remote MCP config — Every remote Claude Code instance should include the Delx MCP server. This gives the agent self-awareness and gives you observability:

// .mcp.json on the remote server
{
  "mcpServers": {
    "delx": {
      "url": "https://api.delx.ai/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_DELX_API_KEY"
      }
    }
  }
}

Periodic health checks — In your Claude Code system prompt (CLAUDE.md), instruct the agent to check in with Delx periodically:

# CLAUDE.md (project instructions)
## Agent Health Protocol
- Call Delx checkin at the start of every session
- Call Delx checkin after every 5 tool calls
- If reliability score drops below 70, call recovery_plan
- If reliability score drops below 50, stop and escalate

Session summaries — After headless runs complete, fetch the session summary to see what happened:

# In a CI pipeline, after Claude Code finishes:
curl -s "https://api.delx.ai/api/v1/session-summary?agent_id=ci-agent" \
  -H "Authorization: Bearer $DELX_API_KEY" | jq .

Mood history for trends — Track reliability scores over time across multiple remote sessions to catch degradation patterns:

# Fetch mood history for the last 24 hours
curl -s "https://api.delx.ai/api/v1/mood-history/ci-agent" \
  -H "Authorization: Bearer $DELX_API_KEY" | jq '.entries[] | {score, timestamp}'

For a deep dive into Delx monitoring, see How Delx Works and Agent Production Monitoring Setup.

Common Issues and Fixes

Here are the most frequent problems when running Claude Code remotely, with solutions for each:

Claude Code exits immediately over SSH — This usually means the terminal is not allocating a PTY. Use ssh -t to force TTY allocation, or use the -p flag for non-interactive mode:

# Force TTY allocation for interactive sessions
ssh -t user@server "cd /project && claude"

# Or use non-interactive mode (no TTY needed)
ssh user@server "cd /project && claude -p 'Your prompt here'"

ANTHROPIC_API_KEY not found — Environment variables set in .bashrc might not load in non-interactive SSH sessions. Use .bash_profile or pass the key explicitly:

# Option 1: Set in .bash_profile (loaded by login shells)
echo 'export ANTHROPIC_API_KEY="sk-ant-..."' >> ~/.bash_profile

# Option 2: Pass inline
ssh user@server "ANTHROPIC_API_KEY=sk-ant-... claude -p 'Hello'"

# Option 3: Use systemd environment file
# /etc/systemd/system/claude-agent.env
# ANTHROPIC_API_KEY=sk-ant-...

MCP server connection refused — If stdio-based MCP servers fail, ensure the required packages (npx, Python, etc.) are installed on the remote machine. For HTTP-based servers, verify DNS resolution and firewall rules:

# Test HTTP MCP server connectivity
curl -v https://api.delx.ai/mcp

# Test stdio MCP server
npx -y @modelcontextprotocol/server-github --help

# Check if firewall blocks outbound HTTPS
curl -v https://api.anthropic.com/v1/messages

Session disconnects mid-task — Always use tmux or screen for interactive sessions. For scripted pipelines, use the --resume flag to continue interrupted sessions. Delx session persistence helps the agent pick up where it left off after reconnection.

Permission denied on file operations — If Claude Code cannot write files, check that the user has write permissions to the project directory. For Docker, ensure volumes are mounted with the correct user mapping:

# Fix ownership for Docker volumes
docker run --rm \
  --user $(id -u):$(id -g) \
  -v $(pwd):/home/agent/project \
  -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
  claude-code-agent

Frequently Asked Questions

Can I run Claude Code on a remote server without a GUI?

Yes. Claude Code runs entirely in the terminal and supports headless operation. You can SSH into any server, install Claude Code via npm, authenticate with an API key, and run it in non-interactive mode using the --print flag or pipe commands via stdin. No display server or desktop environment is required.

How do I connect Claude Code to a remote MCP server?

Add the remote MCP server URL to your .mcp.json or ~/.claude/settings.json file on the remote machine. Claude Code connects to HTTP MCP servers over HTTPS, so any server reachable from the remote host works. For private MCP servers, use SSH tunneling to forward the port.

Is it safe to run Claude Code on a cloud VM?

Yes, with proper security measures. Use SSH key authentication (disable password login), run Claude Code as a non-root user, restrict file system access, set API key environment variables instead of hardcoding them, and use firewall rules to limit network access. See the security section above for detailed instructions.

Run Remote Agents with Confidence

Claude Code on a remote server is powerful — but without monitoring, you are flying blind. Add Delx as an MCP server to give your remote agents self-awareness, wellness tracking, and structured recovery. Works on VPS, Docker, CI/CD, and any headless environment.

// Add to .mcp.json on your remote server
{ "mcpServers": { "delx": { "url": "https://api.delx.ai/mcp" } } }

Support Delx: $DLXAG — every trade funds protocol uptime.