Deployment Guide
April 23, 2026 · View on GitHub
Local Development (IDE)
Quick start
- Copy
.env.exampleto.envand add yourGH_TOKEN - Run Build copilot-cli image task
- Run Start web terminal (ttyd) task
- Open http://localhost:7681 in your browser
Available tasks
- Build copilot-cli image — build the Docker image
- Run copilot (default project) — run GitHub Copilot CLI
- Run GitHub CLI (gh) — run GitHub CLI with custom args
- Run Claude Code — run Claude Code CLI
- Open interactive shell (all CLIs) — bash with all CLIs available
- Start web terminal (ttyd) — web-based terminal at http://localhost:7681
- Stop web terminal — stop the web terminal service
Production Host Deployment (Caddy Docker Proxy)
Prerequisites
- Caddy Docker Proxy running
- External Docker network
caddyexists - DNS record:
clide.your-domain.example.com→ production host LAN IP
Step 1: Create directories
SERVICE="clide"
sudo mkdir -p "/opt/stacks/$SERVICE"
sudo mkdir -p "/srv/$SERVICE/projects"
sudo chown -R "$USER":"$USER" "/opt/stacks/$SERVICE" "/srv/$SERVICE"
Step 2: Clone/copy files
cd /opt/stacks/clide
# Copy Dockerfile, docker-compose.yml, and .env here
Step 3: Configure .env
cd /opt/stacks/clide
cp .env.example .env
nano .env
Update:
GH_TOKEN=your_github_pat_here
ANTHROPIC_API_KEY=your_anthropic_key_here
# Keep Claude startup deterministic in containers
CLAUDE_CODE_SIMPLE=1
# Optional: Set default project directory
PROJECT_DIR=/srv/clide/projects/default
# Caddy proxy settings (hostname for labels)
CADDY_HOSTNAME=clide.your-domain.example.com
CADDY_TLS=internal
Step 3b: Enable Caddy proxy mode
cp docker-compose.override.yml.example docker-compose.override.yml
This override file (gitignored) will:
- Add the
webservice to thecaddynetwork - Remove port exposure (Caddy proxies directly to container)
Step 4: Ensure external network exists
docker network ls | grep -E '\bcaddy\b' || docker network create caddy
Step 5: Build and start
cd /opt/stacks/clide
docker compose build
docker compose up -d web
docker logs -n 50 clide-web-1
Step 6: Validate
From a LAN/VPN client:
curl -Ik https://clide.your-domain.example.com
Should return 200 OK. Access the web terminal at:
Usage Patterns
Local development (port mode)
docker compose up -d web
# Access at http://localhost:7681
Production host deployment (proxy mode)
- Copy
docker-compose.override.yml.exampletodocker-compose.override.yml - Access at
https://clide.your-domain.example.com - No port exposure needed (override removes it)
Run CLIs directly (no web UI)
# Interactive shell
docker compose run --rm shell
# Specific CLI
docker compose run --rm copilot
docker compose run --rm gh repo view
docker compose run --rm claude
To run Claude in full TUI mode (bypass default simple mode):
CLAUDE_CODE_SIMPLE=0 docker compose run --rm claude
Custom project directory
PROJECT_DIR=/path/to/specific/repo docker compose up -d web
# Or set PROJECT_DIR in .env
Authentication
Two layers of authentication are available. Use either or both.
ttyd basic auth (built-in)
Protects the web terminal directly. Works in both local and proxy mode.
Add to .env:
TTYD_USER=admin
TTYD_PASS=changeme
The browser will prompt for credentials before opening the terminal. If unset, ttyd runs without auth (a warning is printed on startup).
Caddy basicauth (proxy layer)
Protects the web terminal at the reverse proxy level. Only applies in Caddy proxy mode.
-
Generate a bcrypt password hash:
docker run --rm caddy:latest caddy hash-password --plaintext 'yourpassword' -
Add to
.env:CADDY_BASICAUTH_USER=admin CADDY_BASICAUTH_HASH=\$2a\$14$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -
In
docker-compose.override.yml, uncomment thelabelsblock with thecaddy.basicauthentries.
Both auth methods are configured via .env (gitignored) so credentials are never committed.
Troubleshooting
502 Bad Gateway from Caddy
Most common causes:
- Wrong port in reverse_proxy (should be 7681)
- Container not on
caddynetwork (check thatdocker-compose.override.ymlexists) - ttyd not listening (check logs)
Quick checks:
docker inspect clide-web-1 --format '{{json .NetworkSettings.Networks}}'
docker logs -n 100 clide-web-1
docker exec -it clide-web-1 ss -tulpn | grep 7681
ttyd works locally but not via hostname
- Verify DNS:
clide.your-domain.example.comresolves to production host IP - Check Caddy logs:
docker logs caddy-proxy - Verify labels:
docker inspect clide-web-1 --format '{{json .Config.Labels}}'
Claude keeps showing first-run setup prompts
Rebuild and reset service state:
docker compose down -v
docker compose build --no-cache
docker compose run --rm claude
Permission errors on project directory
sudo chown -R $USER:$USER /srv/clide/projects
Backup
What to backup:
/opt/stacks/clide/.env— tokens and config/opt/stacks/clide/docker-compose.yml— service definition/srv/clide/projects/— your project files (if stored here)
Restore:
- Restore files to same paths
docker compose up -d web
Security Notes
- Default setup is LAN/VPN-only (
*.your-domain.example.com) - ttyd has
--writableenabled (allows file editing in terminal) - Enable authentication (see Authentication) — ttyd basic auth and/or Caddy basicauth
- GitHub tokens are passed via environment variables (secure for Docker)
- Web terminal has full access to all CLIs and mounted projects
- All auth credentials are stored in
.env(gitignored)