Deploy OpenCode in an isolated Docker container with SSH key auth — step by step from zero to free AI code generation.
Run OpenCode in an isolated Docker container, accessible via SSH from any external client (including Hermes Agent). This guide documents the actual deployment on a VPS at [YOUR_VPS_IP].
Hermes Agent (local) --SSH--> OpenCode Container (VPS:2222)
└── opencode run --model opencode/deepseek-v4-flash-free
| Component | Detail |
|---|---|
| Base image | Debian Bookworm Slim |
| OpenCode version | v1.18.4 |
| SSH port | 2222 (host) |
| SSH user | opencode |
| Authentication | SSH public key (password disabled) |
| Memory usage | ~200MB |
/opt/opencode/
├── docker-compose.yml # Container orchestration
└── opencode-sandbox/
└── Dockerfile # Image build
~/.ssh/id_ed25519)ssh root@[YOUR_VPS_IP] "mkdir -p /opt/opencode/opencode-sandbox"
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y \
openssh-server \
curl \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir -p /run/sshd
# Create .ssh directory with correct permissions
RUN mkdir -p /home/opencode/.ssh && chmod 700 /home/opencode/.ssh
# Install opencode CLI
RUN curl -sL "https://github.com/anomalyco/opencode/releases/download/v1.18.4/opencode-linux-x64.tar.gz" | \
tar -xzf - -C /usr/local/bin && chmod 755 /usr/local/bin/opencode
# Create user with password (fallback, SSH key is primary)
RUN useradd -m -s /bin/bash opencode && \
echo "opencode:@3dd(4/" | chpasswd && \
chown -R opencode:opencode /home/opencode
# SSH config: enable pubkey, disable password auth
RUN echo "PubkeyAuthentication yes" >> /etc/ssh/sshd_config && \
echo "PasswordAuthentication no" >> /etc/ssh/sshd_config && \
echo "PermitRootLogin no" >> /etc/ssh/sshd_config
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
services:
opencode-sandbox:
build: ./opencode-sandbox
container_name: opencode-sandbox
ports:
- "2222:22"
restart: unless-stopped
volumes:
ssh-keys:
Upload the Dockerfile and docker-compose.yml to the VPS:
# Via heredoc (no SCP approval needed)
ssh root@[YOUR_VPS_IP] "cat > /opt/opencode/opencode-sandbox/Dockerfile" < Dockerfile
ssh root@[YOUR_VPS_IP] "cat > /opt/opencode/docker-compose.yml" < docker-compose.yml
ssh root@[YOUR_VPS_IP] "cd /opt/opencode && docker compose up -d --build"
ssh root@[YOUR_VPS_IP] \
"docker exec opencode-sandbox bash -c \
\"mkdir -p /home/opencode/.ssh && \
echo '$(cat ~/.ssh/id_ed25519.pub)' > /home/opencode/.ssh/authorized_keys && \
chmod 600 /home/opencode/.ssh/authorized_keys && \
chown opencode:opencode /home/opencode/.ssh/authorized_keys && \
echo 'Key added'\''
# Verify SSH key login works
ssh -i ~/.ssh/id_ed25519 -p 2222 opencode@[YOUR_VPS_IP] "opencode --version"
# List available free models
ssh -i ~/.ssh/id_ed25519 -p 2222 opencode@[YOUR_VPS_IP] "opencode models"
Expected output:
opencode/big-pickle
opencode/deepseek-v4-flash-free
opencode/hy3-free
opencode/mimo-v2.5-free
opencode/nemotron-3-ultra-free
opencode/north-mini-code-free
Once deployed, call OpenCode from Hermes like this:
ssh -i ~/.ssh/id_ed25519 -p 2222 opencode@[YOUR_VPS_IP] \
"opencode run --model opencode/deepseek-v4-flash-free \
--dangerously-skip-permissions \
'Write a markdown article about your topic here. Save to /tmp/wiki-topic.md'"
1. Analyze image with Ollama (local, your GPU cost):
from PIL import Image
img = Image.open('screenshot.png')
img.thumbnail((200, 200), Image.LANCZOS)
img.save('compressed.jpg', 'JPEG', quality=50)
# Send to Ollama gemma4:31b-cloud for vision analysis
2. Generate wiki article with OpenCode (free model):
ssh -i ~/.ssh/id_ed25519 -p 2222 opencode@[YOUR_VPS_IP] \
"opencode run --model opencode/deepseek-v4-flash-free \
--dangerously-skip-permissions \
'Write a markdown wiki article about [topic from Ollama analysis]. Save to /tmp/wiki-topic.md'"
3. Convert and deploy on VPS:
# Fetch the generated markdown
ssh -i ~/.ssh/id_ed25519 -p 2222 opencode@[YOUR_VPS_IP] "cat /tmp/wiki-topic.md" > /tmp/wiki-topic.md
# Upload to VPS web directory
ssh root@[YOUR_VPS_IP] "cat > /tmp/wiki-topic.md" < /tmp/wiki-topic.md
# Convert markdown -> HTML with python3-markdown
ssh root@[YOUR_VPS_IP] python3 << 'PYEOF'
import markdown
with open('/tmp/wiki-topic.md', 'r') as f:
md = f.read()
html = markdown.markdown(md, extensions=['tables', 'fenced_code'])
# ... wrap with dark theme CSS ...
with open('/var/www/wiki/topic.html', 'w') as f:
f.write(html)
PYEOF
Check if the container is running:
ssh root@[YOUR_VPS_IP] "docker ps | grep opencode"
Verify the authorized_keys file:
ssh root@[YOUR_VPS_IP] \
"docker exec opencode-sandbox cat /home/opencode/.ssh/authorized_keys"
This means the free model API requires credentials. Both opencode/deepseek-v4-flash-free and similar models need an API token from opencode.ai. The local exec fallback (writing files directly) works when model invocation fails, but for full free usage, an OpenRouter API key can be added via:
ssh -i ~/.ssh/id_ed25519 -p 2222 opencode@[YOUR_VPS_IP] "opencode providers add openrouter"
| Setting | Value |
|---|---|
| Password auth | Disabled |
| Root login | Disabled |
| SSH port | 2222 (non-standard) |
| User permissions | opencode user, home directory owned |
For additional security, restrict the opencode user to only run the opencode binary using command= in authorized_keys, though this requires careful configuration to avoid breaking normal operation.
ssh root@[YOUR_VPS_IP]
# Edit /opt/opencode/opencode-sandbox/Dockerfile, change version number
# Rebuild:
cd /opt/opencode && docker compose up -d --build
Deployed: July 2026 on [YOUR_VPS_IP]:2222
Status: ✅ SSH key auth working, free models available
wiki: https://wiki.8883888.xyz/