DeepSeek Harness Web Docker
August 28, 2026 · View on GitHub
Containerized deployment of the DeepSeek Harness (dsh) web client: a single container bundles dsh + Caddy Basic Auth, with configuration and project/session data persisted, and CI automatically pushes GHCR images.
Features
- Self-contained single container: dsh (loopback only, inside the container) + Caddy username/password Basic Auth
- Configuration and project/session data persisted: bind mount
./data→/home/node(the whole HOME: settings.yaml, API Key, profiles, sessions, storages, plus agent-installed tools under~/.x-cmd.root) - Runs as non-root (uid 1000); dsh is not exposed directly
- Built-in health check:
docker compose psshows the real service health (starting/healthy/unhealthy), probing dsh through basic auth with credentials - Pinnable image version: build argument
DSH_VERSION - CI automatically builds and pushes
ghcr.io/xidong-ai/deepseek-harness-web-docker(latest + date-time-hash tags) - A scheduled CI job checks the dsh upstream daily: on a new version it bumps
DSH_VERSION, builds and smoke-tests the image, pushes to master on success, or opens an Issue on failure (a failed version is not retried automatically while its Issue is open; manual dispatch bypasses the gate) - The GHCR release can be triggered manually (Actions tab → "Run workflow") or is hooked automatically after an upstream auto-upgrade (
workflow_dispatch)
Quick Start
Option 1: Use the GHCR image
git clone https://github.com/Xidong-AI/deepseek-harness-web-docker
cd deepseek-harness-web-docker
cp .env.example .env # edit DSH_AUTH_USER / DSH_AUTH_PASSWORD / DEEPSEEK_API_KEY
docker compose up -d # pull the latest image and start
Option 2: Build locally
docker compose up -d --build
# or pin a dsh version:
docker build --build-arg DSH_VERSION=0.1.1-rc.2 -t dsh-web:latest .
After startup, open http://<host>:3080 in a browser (the port is controlled by DSH_WEB_PORT in .env) and enter the Basic Auth username and password.
Environment Variables (.env)
| Variable | Required | Default | Description |
|---|---|---|---|
DSH_AUTH_USER | Yes | admin | Basic Auth username |
DSH_AUTH_PASSWORD | Yes | None | Basic Auth plaintext password (bcrypt hash generated automatically at container startup) |
DEEPSEEK_API_KEY | Yes | None | DeepSeek API Key (referenced by the provider via apiKeyEnv) |
DSH_WEB_PORT | No | 3080 | Host port exposed to the outside (change it when it conflicts with an existing service) |
DSH_TRUSTED_HOSTS | No | Empty | Comma-separated extra trusted hosts, injected into the profile's cordis.patch.yml (only when the file is absent or still the empty template; user-maintained files are skipped — edit the file directly); by default Caddy rewrites Host/Origin to loopback, which covers normal access |
DSH_VERSION | No (build-time) | 0.1.1-rc.2 | dsh version; rebuild with --build after changing it |
.envcontains passwords and the API Key — never commit it to the repository.
Data Persistence
All configuration and data is stored in ./data/ under the project directory (git-ignored):
settings.yaml: dsh configuration (auto-generated from the default template on first startup).credentials.yaml: credentials (e.g. API Keys configured via the web UI)profiles/web/: web profile (auto-initialized by dsh on first startup)sessions/,storages/: session and project data
Deleting the container does not affect the data; configuration is preserved after upgrades.
Upgrading
docker compose pull && docker compose up -d # when using the GHCR image
# or rebuild locally:
docker compose build && docker compose up -d
In-Container Tools & Environment
dsh agents run commands inside the container through the bash tool; the available toolset = what's preinstalled in the image + tools the agent installs itself (x-cmd).
Preinstalled in the image
- Runtime: node 22, npm, pnpm (corepack, required by
dsh plugin), python3, Caddy, dsh - Build toolchain: make/gcc/g++/pkg-config (node-gyp fallback for native modules, e.g. a dsh plugin's node-pty), Rust (rustup stable minimal + rustfmt + clippy)
- Agent tools: git, openssh-client, curl/wget (network), jq/yq (JSON/YAML), ripgrep (search), rsync (sync), procps (processes), zip/unzip/tar, file, dig, sqlite3, python3-pip, vim-tiny, ca-certificates
Agent self-installation (x-cmd, no root required)
The image ships x-cmd (auto-installed to the data volume on first startup; idempotent; Alibaba Cloud OSS source). Inside a dsh session you can run:
x env use git python jq # install/enable tools (no root)
x env ls # list enabled tools
x env which jq # show tool path
x jq . data.json # call with x prefix (always available)
jq . data.json # bare command: enabled packages are symlinked to /usr/local/bin, directly usable
- Install location:
~/.x-cmd.root(inside the data volume./data), preserved across container restart/rebuild - The
xcommand and enabled tools are automatically symlinked to/usr/local/bin(the agent's bash PATH is fixed; the symlink is the only entry point) - Newly installed tools are invoked with the
x <pkg>prefix in the current session; bare commands become available after the container restarts - Tools come from the x-cmd package source (Alibaba Cloud OSS, reachable from mainland China) and support version management (
x env use node=v20)
Sandbox caveat: x-cmd writes to ~/.x-cmd.root (inside the data volume) to run. The file sandbox (workspace-write) only permits writes inside the session workspace plus /tmp, so this directory is not writable: under a bwrap sandbox x refuses to start with folder defined ___X_CMD_ROOT specified is not writable; under the Landlock sandbox (this image ships no bwrap) x starts and read-only use works — built-in modules (x version, x passwd) and already-enabled or cached packages (x <pkg>, symlinked bare commands) — but installing/enabling new packages fails: x env use errors with permission denied, x env ls silently returns empty. To install new tools the agent must request full permissions (approval), or pick /home/node as the session workspace.
For the in-container agent environment guide, see AGENTS.md in the data volume (auto-loaded by dsh sessions).
The image already ships a lightweight build toolchain (make/gcc/g++) and Rust, so agents can run pnpm install/cargo build to compile native modules and projects directly. Other system packages that require root can be added by modifying the apt-get install line in the Dockerfile and rebuilding, or by adding a layer on top of this image:
FROM ghcr.io/xidong-ai/deepseek-harness-web-docker:latest
RUN apt-get update && apt-get install -y --no-install-recommends <pkg> \
&& rm -rf /var/lib/apt/lists/*
Changing the Password
Edit DSH_AUTH_PASSWORD in .env, then run docker compose up -d (the entrypoint regenerates the hash automatically).
Acknowledgements
Thanks to the Linux.do community for support.