Run OpenCode in the cloud via SSH. Connect from anywhere with a simple command.
ssh code.example.com # Open your workspace
ssh code.example.com user/repo # Clone and open a GitHub repoYour Terminal
│
│ SSH (port 22)
▼
┌─────────────────┐ WebSocket ┌────────────────────┐
│ VPS Server │─────────────────────▶│ Cloudflare Worker │
│ (SSH Relay) │ └────────────────────┘
└─────────────────┘ │
▼
┌────────────────────┐
│ Container │
│ ┌──────────────┐ │
│ │ OpenCode TUI │ │
│ └──────────────┘ │
│ Persistent R2 │
│ Storage │
└────────────────────┘
- SSH Relay (your VPS) accepts SSH connections and authenticates via public key
- Cloudflare Worker routes sessions to Durable Objects on the edge
- Container runs OpenCode TUI with persistent storage via R2
- Instant access — Just SSH to your domain, no client setup needed
- Persistent state — Sessions, config, and
~/devworkspace survive restarts - GitHub integration —
ssh domain user/repoclones and opens repos automatically - Auto-sleep — Containers sleep after 30 min idle to save costs
- SSH key auth — Secure public key authentication with auto-registration
- Edge deployment — Containers run on Cloudflare's global network
- VPS with port 22 available (Ubuntu 22.04+ recommended)
- Domain pointing to your VPS
- Cloudflare account with Workers Paid ($5/mo)
- Cloudflare Containers enabled (beta)
git clone https://github.com/R44VC0RP/ssh-opencode
cd ssh-opencode
cp .env.example .envEdit .env:
DOMAIN=code.example.com
CLOUDFLARE_ACCOUNT_ID=your-account-id
CLOUDFLARE_API_TOKEN=your-api-tokencd packages/worker
npm install
npx wrangler r2 bucket create opencode-state
npm run deployOption A: One-liner install
curl -fsSL https://raw.githubusercontent.com/R44VC0RP/ssh-opencode/main/scripts/setup-vps.sh | sudo bashOption B: Manual setup
# On your VPS
git clone https://github.com/R44VC0RP/ssh-opencode
cd ssh-opencode
sudo ./scripts/setup-vps.shThen configure and start:
sudo nano /etc/ssh-opencode/ssh-relay.env # Set WORKER_URL
sudo systemctl enable ssh-relay
sudo systemctl start ssh-relayPoint your domain's A record to your VPS IP. Proxy must be OFF (grey cloud) since SSH can't go through Cloudflare's HTTP proxy.
ssh code.example.comFirst connection auto-registers your SSH key. You'll be dropped into OpenCode TUI.
ssh-opencode/
├── packages/
│ ├── ssh-relay/ # Go SSH server (runs on VPS)
│ ├── worker/ # Cloudflare Worker + Durable Object
│ ├── container/ # Docker image with PTY bridge
│ └── local-proxy/ # Local dev: simulates CF Worker
├── scripts/
│ ├── setup.sh # Local dev setup
│ ├── setup-vps.sh # VPS provisioning
│ └── deploy-vps.sh # Deploy to VPS
└── docker-compose.yml # Local development
| Package | Description | Tech |
|---|---|---|
ssh-relay |
Accepts SSH, proxies to Worker via WebSocket | Go, gliderlabs/ssh |
worker |
Routes sessions, manages container lifecycle, WebSocket streaming | TypeScript, Cloudflare Workers |
container |
Runs PTY bridge + OpenCode TUI | Go, Docker |
local-proxy |
Local dev only: simulates CF Worker | Go |
SSH Relay (/etc/ssh-opencode/ssh-relay.env):
| Variable | Description | Default |
|---|---|---|
WORKER_URL |
Cloudflare Worker WebSocket URL | Required |
AUTH_SECRET |
Shared secret for worker auth | Optional |
SSH_LISTEN_ADDR |
Listen address | :22 |
AUTO_REGISTER |
Auto-register new SSH keys | true |
Cloudflare Worker (via wrangler.jsonc or secrets):
| Variable | Description |
|---|---|
IDLE_TIMEOUT_MINUTES |
Minutes before container sleeps (default: 30) |
AUTH_SECRET |
Shared secret (set via wrangler secret put) |
Add to ~/.ssh/config for convenience:
Host code
HostName code.example.com
User _
RequestTTY yes
ForwardAgent yes
Then: ssh code or ssh code user/repo
# Setup
./scripts/setup.sh
# Run SSH relay (port 2222 to avoid conflict)
docker-compose up ssh-relay
# Test
ssh -p 2222 localhostcd packages/worker
npm run dev # Local wrangler dev server| Component | Cost |
|---|---|
| Cloudflare Workers Paid | $5/month |
| Container compute | ~$0.036/hour when active |
| R2 Storage | ~$0.015/GB/month |
| VPS | Your existing cost |
Typical usage (few hours/day): $10-20/month total
- SSH relay server
- Cloudflare Worker + Durable Object
- PTY bridge container image
- WebSocket protocol (relay↔worker↔container)
- VPS setup scripts
- Container spawning via CF Containers
- WebSocket streaming (low-latency I/O)
- GitHub Actions CI/CD
- Multi-user support
- Check VPS firewall allows port 22
- Verify ssh-relay is running:
systemctl status ssh-relay
- Check Worker is deployed:
curl https://YOUR_WORKER.workers.dev/health - Verify WORKER_URL in ssh-relay config
- Check Cloudflare Containers is enabled in your account
- Verify container image is accessible
- Check Worker logs:
wrangler tail
Contributions welcome! Please open an issue first to discuss what you'd like to change.
- OpenCode — The AI coding assistant this project runs
- gliderlabs/ssh — Go SSH server library
- Cloudflare Workers — Edge compute platform