Remote Server
Remote Server
Section titled “Remote Server”Craft Agents can run as a remote server, letting you keep long-running sessions alive on a remote machine, access them from multiple clients (desktop app, browser, or CLI), and run compute-heavy tasks on a powerful server.
Prerequisites
Section titled “Prerequisites”Choose the setup path that fits your deployment:
If you’re running from source, install Bun with:
curl -fsSL https://bun.sh/install | bashQuick setup from source
Section titled “Quick setup from source”Clone and run the install script:
git clone https://github.com/lukilabs/craft-agents-oss.gitcd craft-agents-oss./scripts/install-server.shThe script installs dependencies, generates a token, and prints the run command. Save your token — it cannot be recovered.
Docker container
Section titled “Docker container”If you just want a deployable server, use the public GitHub Container Registry package:
Use the latest container tag:
export CRAFT_SERVER_TOKEN=$(openssl rand -hex 32)echo $CRAFT_SERVER_TOKEN # Save this
docker run -d \ --name craft-agents-server \ --restart unless-stopped \ -p 9100:9100 \ -e CRAFT_SERVER_TOKEN=$CRAFT_SERVER_TOKEN \ -e CRAFT_RPC_HOST=0.0.0.0 \ -v craft-agents-data:/home/craftagents/.craft-agent \ ghcr.io/lukilabs/craft-agents-server:latestThis image already includes the browser-accessible Web UI, so you can open http://your-server:9100 immediately after the container starts. For any networked deployment, terminate TLS at a reverse proxy or mount certificates and set CRAFT_RPC_TLS_CERT / CRAFT_RPC_TLS_KEY.
If you prefer Docker Compose:
services: craft-agents: image: ghcr.io/lukilabs/craft-agents-server:latest restart: unless-stopped ports: - "9100:9100" environment: CRAFT_SERVER_TOKEN: ${CRAFT_SERVER_TOKEN} CRAFT_RPC_HOST: 0.0.0.0 volumes: - craft-agents-data:/home/craftagents/.craft-agent
volumes: craft-agents-data:Docker troubleshooting
Section titled “Docker troubleshooting”Sessions return empty responses (no errors)
When running with --user and a custom HOME directory, the Claude Agent SDK needs $HOME/.claude/ to be writable. If the HOME directory is read-only (e.g., owned by root), the SDK silently returns empty responses with no error logged.
Fix: Mount a writable volume at the HOME path. For example, if running as a host user whose home is /Users/alice:
docker run -d \ --name craft-agents-server \ --user $(id -u):$(id -g) \ -e HOME=/Users/alice \ -e CRAFT_SERVER_TOKEN=$CRAFT_SERVER_TOKEN \ -p 9100:9100 \ -v /Users/alice/.craft-agent/docker-home:/Users/alice \ -v /Users/alice/.craft-agent:/Users/alice/.craft-agent \ ghcr.io/lukilabs/craft-agents-server:latestThe volume stack works in layers:
docker-home→/Users/alice— writable HOME for the SDK (~/.claude/).craft-agent→/Users/alice/.craft-agent— workspace data (overlays on top)
Web UI not loading
If the server starts but http://your-server:9100 returns a 404 or connection error:
CRAFT_WEBUI_DIRnot set — The Docker image sets this to/app/apps/webui/distby default. If yourdocker-compose.ymlor.envfile overrides environment variables, make sureCRAFT_WEBUI_DIRis included or not overridden to empty.- Volume shadows the app directory — Mounting a volume over
/appreplaces the built WebUI assets. Only mount volumes to/home/craftagents/.craft-agent(or your custom HOME path), not to/app. - Older image tag — Pre-0.8.0 images don’t include the WebUI. Use
latestor0.8.0+.
Verify inside the container:
docker exec craft-agents-server ls /app/apps/webui/dist/index.htmldocker exec craft-agents-server echo $CRAFT_WEBUI_DIRManual setup from source
Section titled “Manual setup from source”git clone https://github.com/lukilabs/craft-agents-oss.gitcd craft-agents-ossbun installGenerate a token and start:
export CRAFT_SERVER_TOKEN=$(openssl rand -hex 32)echo $CRAFT_SERVER_TOKEN # Save this
CRAFT_SERVER_TOKEN=$CRAFT_SERVER_TOKEN \CRAFT_RPC_HOST=0.0.0.0 \CRAFT_RPC_TLS_CERT=certs/cert.pem \CRAFT_RPC_TLS_KEY=certs/key.pem \bun run packages/server/src/index.tsFor development TLS, generate a self-signed certificate:
./scripts/generate-dev-cert.sh# Creates certs/cert.pem and certs/key.pem (valid 365 days)For production, use certificates from a trusted CA (e.g., Let’s Encrypt) or place the server behind a reverse proxy (nginx, Caddy) that terminates TLS.
The server prints connection details on startup:
CRAFT_SERVER_URL=wss://0.0.0.0:9100CRAFT_SERVER_TOKEN=<your-token>Web UI
Section titled “Web UI”The server can serve a browser-accessible web UI on the same port.
- Docker image: already includes the Web UI
- Run from source: build and enable it with:
# Build the web UI assetsbun run webui:build
# Start the server with Web UI enabledCRAFT_SERVER_TOKEN=$CRAFT_SERVER_TOKEN \CRAFT_WEBUI_DIR=apps/webui/dist \CRAFT_RPC_HOST=0.0.0.0 \bun run packages/server/src/index.tsOr use the convenience script that builds everything:
bun run server:prodAccessing the Web UI
Section titled “Accessing the Web UI”Open https://your-server:9100 (or http:// without TLS) in any browser. You’ll see a login page.
Authentication
Section titled “Authentication”Enter the server token as the password. The server issues a session cookie on successful login.
- Login attempts are rate-limited to 5 per 60 seconds per IP
- The session persists until you log out or the cookie expires
What you can do
Section titled “What you can do”The web UI provides the same session interface as the desktop app — create sessions, send messages, manage workspaces. OAuth flows for Claude and Copilot work directly in the browser.
Connecting Clients
Section titled “Connecting Clients”Desktop App (Hybrid Mode)
Section titled “Desktop App (Hybrid Mode)”Connect to a remote server while keeping local workspaces:
- Click the workspace dropdown in the sidebar
- Select Add Workspace… → Connect to Remote Server
- Enter the server URL (e.g.,
wss://192.168.1.100:9100) and token - Click Test Connection to verify
- Select an existing workspace or create a new one on the server
Once connected, remote workspaces appear in your workspace switcher alongside local ones. A CloudOff icon indicates when a remote workspace is unreachable.
Desktop App (Thin Client)
Section titled “Desktop App (Thin Client)”Launch the app as a pure thin client — all logic runs on the server:
CRAFT_SERVER_URL=wss://your-server:9100 \CRAFT_SERVER_TOKEN=<token> \bun run electron:startWeb UI
Section titled “Web UI”Open the server URL in any browser and log in with the token. See Web UI above.
CLI Client
Section titled “CLI Client”Use the terminal client for scripting and automation:
export CRAFT_SERVER_URL=wss://your-server:9100export CRAFT_SERVER_TOKEN=<token>
craft-cli pingcraft-cli sessionscraft-cli send abc-123 "Run the tests"See the CLI guide for the full command reference.
Environment Variables
Section titled “Environment Variables”| Variable | Required | Default | Description |
|---|---|---|---|
CRAFT_SERVER_TOKEN | Yes | — | Bearer token for authentication |
CRAFT_SERVER_URL | No | — | Server URL for client connections |
CRAFT_RPC_HOST | No | 127.0.0.1 | Bind address (0.0.0.0 for remote) |
CRAFT_RPC_PORT | No | 9100 | Bind port |
CRAFT_RPC_TLS_CERT | Yes* | — | PEM certificate file (enables wss://) |
CRAFT_RPC_TLS_KEY | Yes* | — | PEM private key file |
CRAFT_RPC_TLS_CA | No | — | PEM CA chain file (optional) |
CRAFT_DEBUG | No | false | Enable debug logging |
* Required for remote connections. Can be omitted for localhost-only development.
Running at Startup
Section titled “Running at Startup”Linux (systemd)
Section titled “Linux (systemd)”Create the environment file at /path/to/craft-agents-oss/.env:
CRAFT_SERVER_TOKEN=<your-token>CRAFT_RPC_HOST=0.0.0.0CRAFT_RPC_PORT=9100CRAFT_RPC_TLS_CERT=/path/to/cert.pemCRAFT_RPC_TLS_KEY=/path/to/key.pemCreate a service file at /etc/systemd/system/craft-agents.service:
[Unit]Description=Craft Agents ServerAfter=network.target
[Service]Type=simpleUser=<your-user>WorkingDirectory=/path/to/craft-agents-ossEnvironmentFile=/path/to/craft-agents-oss/.envExecStart=/home/<your-user>/.bun/bin/bun run packages/server/src/index.tsRestart=on-failureRestartSec=5
[Install]WantedBy=multi-user.targetEnable and start:
sudo systemctl daemon-reloadsudo systemctl enable craft-agentssudo systemctl start craft-agents
# Check statussudo systemctl status craft-agents
# View logsjournalctl -u craft-agents -fmacOS (launchd)
Section titled “macOS (launchd)”Create a plist at ~/Library/LaunchAgents/com.craft.agents-server.plist:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict> <key>Label</key> <string>com.craft.agents-server</string> <key>ProgramArguments</key> <array> <string>/Users/YOU/.bun/bin/bun</string> <string>run</string> <string>packages/server/src/index.ts</string> </array> <key>WorkingDirectory</key> <string>/path/to/craft-agents-oss</string> <key>EnvironmentVariables</key> <dict> <key>CRAFT_SERVER_TOKEN</key> <string>YOUR_TOKEN</string> <key>CRAFT_RPC_HOST</key> <string>0.0.0.0</string> <key>CRAFT_RPC_PORT</key> <string>9100</string> <key>CRAFT_RPC_TLS_CERT</key> <string>/path/to/cert.pem</string> <key>CRAFT_RPC_TLS_KEY</key> <string>/path/to/key.pem</string> </dict> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <true/> <key>StandardOutPath</key> <string>/tmp/craft-agents.log</string> <key>StandardErrorPath</key> <string>/tmp/craft-agents.log</string></dict></plist>Load and start:
launchctl load ~/Library/LaunchAgents/com.craft.agents-server.plist
# Check statuslaunchctl list | grep craft
# View logstail -f /tmp/craft-agents.log
# Stop and unloadlaunchctl unload ~/Library/LaunchAgents/com.craft.agents-server.plistSecure Access
Section titled “Secure Access”Exposing the server directly to the internet is not recommended. Instead, use one of these approaches:
Tailscale (recommended)
Section titled “Tailscale (recommended)”Tailscale creates a private mesh network between your devices. Install it on both the server and client machines — no port forwarding, no certificates, no firewall rules needed.
# On the server: bind to Tailscale IP onlyCRAFT_RPC_HOST=100.x.y.z \CRAFT_SERVER_TOKEN=$TOKEN \bun run packages/server/src/index.tsTraffic is encrypted end-to-end by Tailscale, so you can skip TLS certificate setup entirely. The server is only reachable from your Tailscale network.
Reverse proxy (nginx, Caddy)
Section titled “Reverse proxy (nginx, Caddy)”Place the server behind a reverse proxy that handles TLS termination and access control. This is the standard approach for production deployments.
Caddy (automatic HTTPS):
craft.example.com { reverse_proxy localhost:9100}nginx:
server { listen 443 ssl; server_name craft.example.com;
ssl_certificate /etc/letsencrypt/live/craft.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/craft.example.com/privkey.pem;
location / { proxy_pass http://localhost:9100; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; }}When using a reverse proxy, bind the server to localhost only (CRAFT_RPC_HOST=127.0.0.1) and let the proxy handle external access.
Cloudflare Tunnel
Section titled “Cloudflare Tunnel”Cloudflare Tunnel exposes your server over HTTPS without opening ports or managing certificates. Install cloudflared and run:
# Quick tunnel — instant HTTPS URL, no config neededcloudflared tunnel --url http://localhost:9100This prints a https://<random>.trycloudflare.com URL you can open in any browser. For a permanent custom domain:
# One-time setupcloudflared tunnel logincloudflared tunnel create craft-agentscloudflared tunnel route dns craft-agents agents.yourdomain.com
# Run the tunnelcloudflared tunnel run --url http://localhost:9100 craft-agentsSSH tunnel
Section titled “SSH tunnel”For quick, ad-hoc access without any setup:
# On the client: forward local port 9100 to the remote serverssh -L 9100:localhost:9100 user@your-serverThen connect to ws://localhost:9100 from the desktop app or browser. The tunnel encrypts all traffic over SSH.
Browser tool
Section titled “Browser tool”The built-in browser bridges from the remote server to the connected desktop client — pages open on your local machine, using your cookies and signed-in sessions. The browser tool is available when at least one desktop client is connected; web UI and CLI clients cannot host browser windows.
See Browser on remote workspaces for the security model and the allowRemoteEvaluate switch.
Version Compatibility
Section titled “Version Compatibility”The server includes its version in the connection handshake. When a client connects to an older server (pre-0.8.0), it shows a warning that some features may not be available.