Skip to content

Latest commit

 

History

History
189 lines (135 loc) · 4.75 KB

File metadata and controls

189 lines (135 loc) · 4.75 KB

Server Deployment

Initialization

Local mode (direct PTY)

relay-runner init

Creates:

  • CA certificate and key in ~/.local/share/relay/ (macOS: ~/Library/Application Support/relay/)
  • Server certificate signed by the CA
  • Default config.toml

Cloud mode (Docker-backed sessions)

relay-runner init --cloud

Additional steps beyond local mode:

  • Creates data directory structure (projects/, workspaces/ for git worktrees, sessions/)
  • Initializes SQLite database with WAL mode
  • Generates a bearer token (printed to stdout — save it securely)
  • Writes cloud-mode config with cloud_mode = true

Configuration

Config file location: <state_dir>/config.toml

Full reference

# Enable cloud mode — gRPC CRUD RPCs return FAILED_PRECONDITION,
# clients must use REST API. AttachSession routes through Docker exec.
cloud_mode = false

# gRPC server port
port = 50051

# REST API port
rest_port = 8080

# Data directory for SQLite, projects, workspaces
# Default: ~/.local/share/relay (Linux) or ~/Library/Application Support/relay (macOS)
data_dir = "/var/lib/relay-data"

# Maximum concurrent terminal sessions
max_sessions = 50

# VT parser scrollback buffer size (lines)
scrollback_lines = 10000

# Shells available for session creation
shell_allowlist = ["/bin/bash", "/bin/zsh", "/bin/sh"]

[tls]
cert_path = "/path/to/server.crt"
key_path = "/path/to/server.key"
ca_cert_path = "/path/to/ca.crt"    # For mTLS client verification
require_mtls = false                 # Reject non-mTLS clients

[auth]
token_hash = "..."    # Argon2 hash — generate with: relay-runner hash-token <token>
require_mtls = false

[docker]
socket_path = "/var/run/docker.sock"
default_image = "ubuntu:24.04"
allowed_images = []           # Empty = all images allowed
exec_timeout_secs = 30
memory_limit = "2g"
memory_swap = "2g"            # Equal to memory_limit disables swap
cpu_limit = 2.0
# seccomp_profile = "/path/to/seccomp.json"  # None = Docker default

[git]
clone_timeout_secs = 300
allowed_hosts = []            # Empty = all hosts allowed (SSRF validation still applies)

[mdns]
enabled = true
instance_name = "Relay Runner"

# Session profiles — terminal initialization templates
[[profiles]]
name = "claude-default"
# init_command = "claude"
# env_vars = { "NODE_ENV" = "production" }

Authentication

Two methods, can coexist:

Bearer token

# Generate hash for config
relay-runner hash-token "my-secret-token"
# Add to [auth] section: token_hash = "<output>"

# Client usage
curl -H "Authorization: Bearer my-secret-token" http://host:8080/api/v1/health

mTLS (recommended for production)

relay-runner init                        # Creates CA
relay-runner add-client "MacBook Pro"    # Issues client cert, prints PEM

Client receives:

  • Certificate + key PEM (stdout)
  • Fingerprint and 6-digit verification code (stderr)

The verification code uses TOFU (Trust On First Use) — the client compares it with the server's advertised code.

Token rotation

relay-runner rotate-token
# Prints new token to stdout, updates config.toml automatically

CA rotation

relay-runner rotate-ca
# Old CA saved as ca.crt.old / ca.key.old
# Re-issue client certs: relay-runner add-client <name>

Docker Compose

docker compose up -d

The docker-compose.yml includes:

  • runner — the relay-runner server with resource limits (512MB RAM, 2 CPUs)
  • docker-socket-proxy — restricts Docker API access to safe endpoints only (containers, images, exec)

Volumes:

  • runner-state — CA, certs, config
  • runner-data — SQLite database, project clones, workspaces

Ports:

  • 50051 — gRPC (terminal I/O)
  • 8080 — REST API

Security

The Docker socket proxy (tecnativa/docker-socket-proxy) allows only:

  • Container lifecycle (create, start, stop, remove)
  • Image inspection
  • Exec attach (for PTY)
  • Info, version, events, ping

All other Docker APIs (auth, secrets, networks, volumes, build, swarm, etc.) are denied.

systemd

sudo cp relay-runner /usr/local/bin/
sudo cp systemd/relay-runner.service /etc/systemd/system/
sudo systemctl enable --now relay-runner

mDNS Discovery

Enable with mdns.enabled = true. Advertises via Bonjour (mdns-sd crate).

Docker limitation: mDNS requires network_mode: host on Linux. On macOS, use the native runner for mDNS during development.

Logging

Structured JSON logging via tracing + tracing-subscriber. Control verbosity with RUST_LOG:

RUST_LOG=info cargo run          # Standard
RUST_LOG=debug cargo run         # Verbose
RUST_LOG=relay_runner=trace cargo run  # Trace runner only

Audit logging: all mutating REST requests (POST, PUT, PATCH, DELETE) are logged with method, path, source IP, and response status.