DeepSeek Harness (DSH) + Web Login | DeepSeek Harness Docker 镜像,支持网页登录
10K+
DeepSeek Harness on Docker Hub publishes two image families:
/data application-state bindBoth variants are built from the same release pipeline and are published as multi-arch images for linux/amd64 and linux/arm64.
The browser authentication layer is provided by a custom Caddy build with caddy-security and caddy-ratelimit. Its entry point is a standard username/password web form, not WebAuthn or passkeys, so browser password managers can autofill it. Built-in, proxy-aware limits protect username and password submissions at the image boundary.
These badges show the current non-floating release values automatically. Use the value shown in the badge when you want to pin a specific runtime or workstation release.
| Tag | Purpose |
|---|---|
latest | Runtime floating alias |
workstation | Workstation floating alias |
<DSH_VERSION> / <DSH_VERSION>-workstation | Versioned release tags generated by the release pipeline |
Important for upgrades: the application-state persistence path has changed to /data. Both image variants require /data to be an exact bind mount or named-volume mount. Mounting only the legacy /home/node/.local/share/deepseek-harness path does not persist the current layout. To prevent silent state loss, the container prints a bilingual migration error and exits when /data is not mounted; recreate it with a persistent /data mount.
Both variants use /workspace as the image working directory and DSH_WORKSPACE default. The web Add workspace dialog opens at /workspace, and its Home shortcut also resolves there. In the workstation image, /home/node remains the user HOME and persistent tool volume; it is not the default project directory.
docker pull moelin/deepseek-harness:latest
# Replace /opt/deepseek-harness with any persistent host directory you control.
sudo install -d -m 0750 /opt/deepseek-harness/data /opt/deepseek-harness/workspace
docker run -d \
--name deepseek-harness \
--restart unless-stopped \
-p 127.0.0.1:56789:8080 \
-e PUBLIC_URL=https://dsh.example.com \
-e AUTH_USERNAME=admin \
-e AUTH_PASSWORD=replace-with-a-unique-password-of-at-least-12-characters \
-v /opt/deepseek-harness/data:/data \
-v /opt/deepseek-harness/workspace:/workspace \
moelin/deepseek-harness:latest
The runtime requires a persistent mount at /data; the host bind shown above is the recommended layout for normal deployments. It stores:
/data/auth: authentication users and the persistent JWT signing key/data/caddy: Caddy configuration and certificates/state/data/dsh: DeepSeek Harness application stateThe entrypoint normalizes the bind root and creates the required directories and files for the node user (UID/GID 1000:1000). Keep the bind source a regular directory and preserve its ownership and permissions when copying or restoring data.
docker pull moelin/deepseek-harness:workstation
# Replace /opt/deepseek-harness with any persistent host directory you control.
docker run -d \
--name deepseek-harness-workstation \
--restart unless-stopped \
-p 127.0.0.1:56789:8080 \
-e PUBLIC_URL=https://dsh.example.com \
-e AUTH_USERNAME=admin \
-e AUTH_PASSWORD=replace-with-a-unique-password-of-at-least-12-characters \
-v /opt/deepseek-harness/data:/data \
-v dsh-home:/home/node \
-v /opt/deepseek-harness/workspace:/workspace \
moelin/deepseek-harness:workstation
The workstation persists application state under /data, keeps user-installed pnpm, pipx, Cargo, and Go tools in the named dsh-home volume, and stores projects through the direct /workspace bind.
To migrate an older workstation deployment, keep its existing /home/node volume or direct /home/node/.local/share/deepseek-harness mount attached for the first start and add the new /data mount. When /data/auth is empty, the entrypoint copies the legacy workstation application state into /data. Subsequent containers still require /data; the legacy mount cannot replace it. The old path is not deleted automatically, so remove it only after you confirm the migrated /data copy is working.
If you are moving from an older runtime named volume such as dsh-data, copy its contents into the new host data directory before switching tags so the same authentication and JWT state is reused.
If you run the repository Compose files locally, they already use the package-local ./data/data, ./data/workspace, and dsh-home layout with the same split between application state, workspace files, and user-installed tools.
| Variable | Meaning |
|---|---|
PUBLIC_URL | Required browser origin, for example https://dsh.example.com. Use the exact public origin, not a subpath. |
AUTH_MODE | Login mode. Default caddy-security; none is only for deployments with another auth layer; dsh is reserved and fails closed. |
AUTH_USERNAME | Single login username. Default admin. |
AUTH_PASSWORD | Plaintext password, at least 12 characters. Set exactly one credential source. |
AUTH_PASSWORD_FILE | Readable secret file path for the password source. |
AUTH_PASSWORD_HASH | bcrypt:<cost>:<hash> form generated by Caddy. |
AUTH_TOKEN_LIFETIME | Token and cookie lifetime in seconds. Valid range: 300 to 2592000. |
CADDY_TRUSTED_PROXIES | Space-separated trusted proxy CIDRs, private_ranges (default), or none for direct client connections. |
AUTH_COOKIE_INSECURE | false for normal HTTPS deployments. true only for isolated HTTP tests, where cookies lose Secure and HttpOnly. |
DSH_TRUSTED_HOSTS | Optional comma-separated extra Host authorities when the app is reached through additional trusted origins. |
Recommended defaults:
| Variable | Default | Meaning |
|---|---|---|
PORT | 8080 | Container port where Caddy listens. Publish it through a loopback host port or private network. |
DSH_INTERNAL_PORT | 3080 | Internal DeepSeek Harness loopback port inside the container. Do not publish it directly. |
GOMEMLIMIT | 128MiB | Soft memory limit for Caddy's Go runtime only. It does not cap DSH workloads. |
GOMAXPROCS | 2 | Caddy Go runtime CPU scheduling limit. |
DSH_TELEMETRY_DISABLED | 1 | Disables DSH telemetry. |
The default login username is admin. There is no built-in default password; set exactly one credential source with AUTH_PASSWORD, AUTH_PASSWORD_FILE, or AUTH_PASSWORD_HASH.
The image limits username-stage POSTs to 10 per minute and password-stage POSTs to 10 per 10 minutes for each resolved client IP. Rejected requests return HTTP 429 with Retry-After. These budgets are fixed image defaults rather than runtime settings; changing them requires a custom rebuild and smoke test.
CADDY_TRUSTED_PROXIES controls which proxy hops Caddy trusts while resolving X-Forwarded-For from right to left. The default private_ranges matches the documented loopback/private reverse-proxy deployment. Set it to none when clients connect directly to Caddy. When a CDN or another proxy sits in front of 1Panel/OpenResty, normalize the real client IP in that outer proxy or list every trusted proxy range. Unrestricted /0 ranges are rejected. Keep a matching limit in the outer WAF or reverse proxy as defense in depth.
Stop the container before backing up /opt/deepseek-harness/data to obtain a consistent archive:
docker stop deepseek-harness
sudo tar -C /opt/deepseek-harness/data \
-czf /opt/deepseek-harness/dsh-data.tar.gz .
docker start deepseek-harness
Restore only while the container is stopped, preferably into an empty data directory. A bind-mounted /data directory is not a Docker volume, so docker compose down --volumes, docker volume rm, and docker volume prune do not delete it. Remove the host directory separately only when its data is no longer needed.
The workstation dsh-home named volume must be backed up separately. Ordinary container removal and docker compose down preserve named volumes; docker compose down --volumes can remove them.
Host, X-Forwarded-Proto, a trustworthy X-Forwarded-For chain, and WebSocket upgrade headers.PUBLIC_URL must match the browser-visible origin exactly. If you use an IP address or a private certificate, the browser must trust that certificate chain first.AUTH_COOKIE_INSECURE=true./var/run/docker.sock only when host Docker control is intentionally required.Content type
Image
Digest
sha256:27afe99d0…
Size
227.6 MB
Last updated
3 days ago
docker pull moelin/deepseek-harness