Miles WardandClaude Fable 5 768de4ac75
Sync upstream and build image / sync-and-build (push) Successful in 19s
Unraid template support: baked --patch layer, /workspace, logo, template in README
- Ship /opt/deepseek-harness/web.cordis.patch.yml and pass it via upstream's
  --patch launcher flag (must precede the web command's own flags) instead of
  seeding DSH_HOME; entrypoint accepts template Post Arguments verbatim.
- Add /workspace (agent WORKDIR) and pin DSH_HOME=/home/node/.dsh; drop the
  implicit /home/node volume so templates mount .dsh and /workspace cleanly.
- README: Unraid template (repo/support/icon/versions corrected for this
  image, lanmode plugin caution), first-run chown note, DeepSeek logo.

Verified: no-args, flags-only, and full template invocations all serve the
web UI; trust fence still 403s unknown Hosts; state persists to mounted .dsh.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-09-02 03:07:45 -04:00

DeepSeek logo

deepseek-harness — trusted mirror & container build

Mirror of the official deepseek-ai/deepseek-harness with a locally-built, auditable container image for homelab use (Unraid).

Branch layout

Branch Contents
master Exact mirror of upstream master (plus all dsh-v* tags). Never edited locally.
main This branch: Dockerfile, entrypoint, and the sync/build workflow.

Image

gitea.milesward.dev/mward4/deepseek-harness:<version>
gitea.milesward.dev/mward4/deepseek-harness:latest

Built from node:22-bookworm-slim + the official @deepseek-ai/dsh npm release, pinned to the exact version. Upstream publishes no container image; this repo exists so the image provenance is: upstream tag → upstream npm release → this Dockerfile → this registry.

No upstream code is modified. Upstream deliberately refuses --host 0.0.0.0 on the CLI (the web UI can execute code, so exposing it to a network is a deliberate opt-in); the supported opt-in is a --patch launcher layer, which this image ships at /opt/deepseek-harness/web.cordis.patch.yml (bind 0.0.0.0:3080). The UI is reachable only through ports you explicitly publish, and the /api trust fence still refuses any Host it doesn't know.

Paths inside the container:

Path Purpose
/home/node/.dsh dsh state: settings, credentials, sessions, plugins (DSH_HOME)
/workspace The agent's working directory (container WORKDIR)
/opt/deepseek-harness/web.cordis.patch.yml Baked web-server bind patch

Entrypoint behavior: no arguments → dsh web --patch <baked patch> --no-open (the --patch launcher flag must precede the web command’s own flags); arguments starting with a flag (e.g. --trusted-host tower.local) are appended to that default; a full command line (e.g. web --patch /opt/deepseek-harness/web.cordis.patch.yml --no-open) runs as given. Runs as user node (UID/GID 1000).

Unraid template

First run (required): the container runs as UID 1000. Before starting, from the Unraid terminal:

mkdir -p /mnt/user/appdata/deepseek-harness/workspace
chown -R 1000:1000 /mnt/user/appdata/deepseek-harness

Otherwise dsh fails with EACCES on /home/node/.dsh.

<?xml version="1.0"?>
<Container version="2">
  <Name>DeepSeek-Harness</Name>
  <Repository>gitea.milesward.dev/mward4/deepseek-harness:latest</Repository>
  <Registry>https://gitea.milesward.dev/mward4/deepseek-harness</Registry>
  <Network>bridge</Network>
  <Shell>sh</Shell>
  <Privileged>false</Privileged>
  <Project>https://github.com/deepseek-ai/deepseek-harness</Project>
  <Support>https://gitea.milesward.dev/mward4/deepseek-harness/issues</Support>
  <Overview>
DeepSeek Harness (dsh) - browser-based agent runtime from DeepSeek AI, packaged from the official npm release (built and served from this Gitea; non-root).

FIRST RUN (required): the container runs as UID 1000. Before starting, from the Unraid terminal:
  mkdir -p /mnt/user/appdata/deepseek-harness/workspace
  chown -R 1000:1000 /mnt/user/appdata/deepseek-harness
Otherwise dsh fails with EACCES on /home/node/.dsh.

SECURITY - READ BEFORE EXPOSING: the dsh Web UI has no authentication or TLS, and its web API can execute code on this container. Anything that can reach the port can run commands. Keep it on a trusted LAN, or put an authenticated reverse proxy (e.g. Cloudflare Access, Authelia) in front. Never port-forward it directly to the internet.

REMOTE ACCESS: dsh rejects non-loopback requests (HTTP 403 on /api) unless the address you browse from is trusted. To use the Web UI from another machine, edit Post Arguments and append:  --trusted-host YOUR-UNRAID-IP-OR-HOSTNAME
The Settings/credentials pages are additionally restricted to loopback pages by upstream design; edit them via SSH tunnel (ssh -L 3080:127.0.0.1:3080 root@unraid-ip, then browse http://127.0.0.1:3080). The @goodandready/dsh-lanmode community plugin can lift that restriction, but it is third-party code from an unaffiliated author that disables an upstream security fence - review it yourself before trusting it with your credentials.

VERSIONS: this registry publishes immutable version tags AND a :latest tag that CI moves to each new official npm release. dsh is a developer preview with breaking changes between releases - pin a version tag if you want to update deliberately.

Your DeepSeek API key can be set below (stored in the container env) or entered later in Settings once running.
  </Overview>
  <Category>AI: Tools:</Category>
  <WebUI>http://[IP]:[PORT:3080]</WebUI>
  <TemplateURL/>
  <Icon>https://gitea.milesward.dev/mward4/deepseek-harness/raw/branch/main/assets/deepseek-logo.png</Icon>
  <ExtraParams/>
  <PostArgs>web --patch /opt/deepseek-harness/web.cordis.patch.yml --no-open</PostArgs>
  <Config Name="WebUI Port" Target="3080" Default="3080" Mode="tcp" Description="dsh Web UI. Reachable by everything on your LAN - see the security note in the Overview." Type="Port" Display="always" Required="true" Mask="false">3080</Config>
  <Config Name="DeepSeek API Key" Target="DEEPSEEK_API_KEY" Default="" Description="Optional. Official DeepSeek API key (sk-...). Can also be configured later in the dsh Settings UI." Type="Variable" Display="always" Required="false" Mask="true"></Config>
  <Config Name="DSH Home" Target="/home/node/.dsh" Default="/mnt/user/appdata/deepseek-harness" Mode="rw" Description="Persistent dsh state: settings, credentials, sessions, plugins. Must be owned by UID/GID 1000 (see Overview)." Type="Path" Display="always" Required="true" Mask="false">/mnt/user/appdata/deepseek-harness</Config>
  <Config Name="Workspace" Target="/workspace" Default="/mnt/user/appdata/deepseek-harness/workspace" Mode="rw" Description="The agent's working directory. Only mount data you are willing to let the agent read and modify. Must be writable by UID 1000." Type="Path" Display="always" Required="true" Mask="false">/mnt/user/appdata/deepseek-harness/workspace</Config>
</Container>

To reach the UI from your LAN, append your Unraid host to Post Arguments, e.g.:

web --patch /opt/deepseek-harness/web.cordis.patch.yml --no-open --trusted-host tower.local --trusted-host 192.168.1.50

(port-less entries match any port). Without it, anything but a loopback Host header gets a 403 from /api — that's upstream's DNS-rebinding/CSRF fence, working as intended.

Keeping current

.gitea/workflows/sync-upstream.yml runs every 6 hours on the Gitea Actions runners:

  1. Force-syncs upstream master and dsh-v* tags into this repo.
  2. Resolves the official npm latest version of @deepseek-ai/dsh.
  3. If the registry lacks an image for that version, builds and pushes it, moving :latest along with it.

Validating an image

.gitea/workflows/validate-suspect-image.yml (manual dispatch) forensically compares any third-party deepseek-harness image already present on the runner host's docker daemon against this repository's trusted build — without ever executing the suspect image (docker create + filesystem export only). It reports: image config/entrypoint/labels, whether any containers use it, a byte-level diff of dsh's own code against the official release, dependency-tree drift, and tampering red flags (patched-out 0.0.0.0 refusal, startup hooks, unexpected network callouts).

Ran 2026-09-02 against runzhliu/deepseek-harness:0.1.1-rc.2: dsh code byte-identical to the official npm release; no tampering found.

S
Description
Trusted, immutable container builds of DeepSeek Harness (dsh) from the official npm release. Upstream mirror + scheduled CI.
https://github.com/deepseek-ai/deepseek-harness Readme MIT
568 MiB
0 Stars 1 Watchers 0 Forks
v0.2.1-rc.4
Latest
2026-10-28 03:37:33 -04:00
Languages
JavaScript 60.4%
Shell 27.4%
Dockerfile 12.2%