dotdsh
August 23, 2026 ยท View on GitHub
Personal DeepSeek Harness host setup with first-run owner authentication.
The repository tracks how DSH is built, authenticated, and supervised. Values that identify one server stay in an ignored host patch, so the same checkout can be configured independently on another machine.
Architecture
public origin
-> external reverse proxy
-> configured auth proxy host:port
-> DSH 127.0.0.1:<ephemeral>
The built-in DSH webserver remains on loopback. Only @dotdsh/dsh-auth accepts external HTTP, API, and WebSocket traffic.
Authenticated users intentionally receive the same full-admin surface as a local DSH browser. dsh-auth remains the security boundary; the small client compatibility patches only tell built-in UI consumers that an authenticated remote page may use host-scoped settings and host file actions.
The files under patches/ are exact-version pnpm patches for DSH 0.1.1-rc.2. They make upgrades fail closed when the upstream client changes. pnpm check:compat also scans the installed Web composition for new UI consumers that still gate host-admin features on connection.isLoopback, so every DSH upgrade must pass that check before its patches are refreshed.
Host configuration
Create the ignored host patch:
cp config/host.patch.example.yml config/host.patch.yml
$EDITOR config/host.patch.yml
Configure:
publicOrigin: the exact HTTPS origin used in the browser;host:127.0.0.1for a reverse proxy on the host, or0.0.0.0when a containerized reverse proxy must reach the host;port: the host port owned by the auth proxy.
Authentication policy such as session lifetime and login throttling remains versioned in the plugin defaults. Password state and host values are not tracked.
Install
Requirements:
- Linux with a user systemd manager;
nodeandpnpmavailable to the current shell;- user lingering enabled when the service must start before login.
If lingering is disabled, enable it once:
sudo loginctl enable-linger "$USER"
Install from any working directory:
/path/to/dotdsh/scripts/install
The installer:
- derives the checkout, user, Node, DSH home, and XDG config paths;
- installs the locked dependency tree, builds the auth plugin, and verifies DSH compatibility;
- links the plugin into the current DSH Web profile;
- validates
config/host.patch.yml; - renders and verifies the user systemd unit;
- enables and restarts
dsh.service.
Re-run the installer after moving the checkout or changing the Node installation so the rendered unit receives the new paths.
First-run authentication
Open the configured publicOrigin. With no owner state, the auth proxy exposes only the password setup form. The password is persisted only as a scrypt hash under ${DSH_HOME:-$HOME/.dsh}/auth/state.json.
After setup, every page, API request, and WebSocket upgrade requires the secure session cookie. Restarting the service clears sessions but preserves the owner password.
Verify
pnpm check:compat
pnpm check:config
systemctl --user status dsh.service
journalctl --user -u dsh.service
To inspect the unauthenticated HTTP boundary directly, substitute the host and port from config/host.patch.yml:
curl -I -H 'Host: dsh.example.com' http://127.0.0.1:3080/
The response should be the setup or login surface, never the unprotected DSH application.
Reverse proxy
For a reverse proxy running directly on the same host:
dsh.example.com {
reverse_proxy 127.0.0.1:3080
}
For Caddy in a Linux container, bind the auth proxy to 0.0.0.0, restrict the port at the firewall, and route through the host gateway:
dsh.example.com {
reverse_proxy host.docker.internal:3080
}
The container may also need:
extra_hosts:
- "host.docker.internal:host-gateway"
Reverse-proxy configuration remains outside this repository.
Operate
systemctl --user restart dsh.service
systemctl --user stop dsh.service
systemctl --user start dsh.service
Move to another host
- clone the repository;
- create that host's ignored
config/host.patch.yml; - enable lingering if needed;
- run
scripts/install; - complete first-run password setup on the new host.
The authentication state is intentionally host-local. Copy it separately only when preserving the same owner password is required.
Remove
systemctl --user disable --now dsh.service
rm "${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/dsh.service"
systemctl --user daemon-reload
Removal leaves the DSH profile and owner-password state intact.