dsh-server-setup
Production-tested setup for running DeepSeek Harness on a VPS with reverse proxy, systemd, and optional Pangolin tunnel
- Stars
- 1
- Language
- JavaScript
- Created
- Sep 2, 2026
- Updated
- Sep 3, 2026
Introduction
DSH Server Setup
Run DeepSeek Harness on a remote VPS with reverse proxy as a DSH plugin.
This is a production-tested setup for running DSH on an Ubuntu server (ARM64 or x64) with:
- systemd service — auto-restart, logging, persistence
- Reverse proxy plugin — smanx/dsh-proxy runs inside DSH, configurable from Settings
- Basic Auth (optional) — protect your instance from unauthorized access
- Telegram bridge (optional) — notifications and cron alerts to your phone
Architecture
Browser/Phone
│
▼
DSH (0.0.0.0:3080) ← dsh-proxy plugin handles external access
│
▼
DSH core (127.0.0.1:3079) ← internal port
│
▼
DeepSeek API / MCP servers / Filesystem
The proxy runs as a DSH plugin — no separate process needed. It starts and stops with dsh web.
Quick Start
1. Install prerequisites
# Node.js (via fnm or nvm)
curl -fsSL https://fnm.vercel.app/install | bash
source ~/.bashrc
fnm install 24
# pnpm
npm install -g pnpm
# DSH
npm install -g @deepseek-ai/dsh
2. Create a web profile
mkdir -p ~/.dsh/profiles/web
cd ~/.dsh/profiles/web
3. Add plugins
# Core (already installed with dsh)
# Reverse proxy
pnpm add github:smanx/dsh-proxy
# Your other plugins
pnpm add dshmarket dsh-cron dsh-mnemon dsh-free-search dsh-config-manager ...
4. Configure the profile
~/.dsh/profiles/web/package.json:
{
"name": "dsh-profile-web",
"private": true,
"dependencies": {
"@smanx/dsh-proxy": "github:smanx/dsh-proxy",
"dshmarket": "^1.39.0"
},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"@smanx/dsh-proxy",
"dshmarket"
]
}
}
}
~/.dsh/profiles/web/cordis.patch.yml:
# dsh-proxy: reverse proxy for LAN/remote access
- id: dsh-proxy
name: "@smanx/dsh-proxy"
config:
listenPort: 3080
# username: admin # Uncomment to enable Basic Auth
# password: changeme # Uncomment to enable Basic Auth
5. Install the systemd service
sudo cp systemd/dsh.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable dsh
sudo systemctl start dsh
6. Verify
# Check DSH is running
curl -s http://127.0.0.1:3079/ | head -5
# Check proxy is accessible
curl -s http://YOUR_SERVER_IP:3080/ | head -5
Configuration
Proxy Settings (via UI)
Go to Settings → LAN Proxy in the DSH web GUI to:
- Start/stop the proxy
- Change the listen port
- Set username and password for Basic Auth
- View connection status
Proxy Settings (via cordis.patch.yml)
- id: dsh-proxy
name: "@smanx/dsh-proxy"
config:
listenPort: 3080 # External port (0.0.0.0)
username: admin # Basic Auth username (empty = disabled)
password: changeme # Basic Auth password
HTTPS / Remote Access
The proxy does not handle HTTPS. For production, put a TLS terminator in front:
- Pangolin (recommended) — self-hosted identity-aware VPN + reverse proxy with WireGuard, dashboard, and access control
- Cloudflare Tunnel —
cloudflared tunnel --url http://127.0.0.1:3080 - Caddy — auto HTTPS with
reverse_proxy localhost:3080 - Nginx + Let's Encrypt — standard reverse proxy config
Pangolin Setup
Pangolin (22k+ stars) is a self-hosted tunnel that gives you HTTPS + authentication + WireGuard VPN without opening ports. It runs as Docker containers on the same VPS.
1. Install Pangolin:
# Clone and install
git clone https://github.com/fosrl/pangolin.git ~/pangolin
cd ~/pangolin
bash install.sh
2. Configure (~/pangolin/config/config.yml):
domain: yourdomain.com
# TLS (Let's Encrypt or custom cert)
letsencrypt:
email: you@yourdomain.com
useLetsEncrypt: true
# Flask secret (generate with: openssl rand -hex 32)
flask_secret: <random-secret>
jwt_secret: <random-secret>
3. Add DSH resource in Pangolin dashboard:
- Open
https://yourdomain.com→ login - Go to Resources → New Resource
- Set:
- Name:
dsh - Protocol:
HTTP - Target IP:
127.0.0.1 - Target Port:
3080
- Name:
- Create a Target (the Gerbil client) and generate a config
- On your VPS, add the Gerbil client:
# Add the client config from the Pangolin dashboard
sudo nano /etc/pangolin/client/config.yml
sudo systemctl restart pangolin-client
4. Access DSH:
https://dsh.yourdomain.com
Your DSH instance is now accessible over HTTPS with Pangolin's authentication layer on top.
Advantages over direct proxy:
- HTTPS with automatic Let's Encrypt certificates
- Built-in authentication (email-based or SSO)
- WireGuard VPN option for full network access
- Access control and audit logs
- No need to open additional ports
Reverse Proxy Features
The proxy (smanx/dsh-proxy, MIT license) provides:
crypto.randomUUID polyfill
DSH's frontend uses crypto.randomUUID() for RPC IDs, but this API is only available in secure contexts (HTTPS/localhost). When accessing via LAN IP or public URL, the polyfill injects a compatible implementation using getRandomValues().
Loopback trust patch
DSH 0.1.1+ checks location.hostname to determine if the browser is local. Non-loopback hosts get degraded behavior (memory-only mode, no settings). The proxy patches the client JS to treat proxied connections as loopback, enabling full functionality.
WebSocket support
The proxy forwards WebSocket connections for real-time DSH features (streaming, live updates).
Public path whitelist
/manifest.webmanifest, /favicon.svg, and /favicon.ico are served without auth so browsers can fetch PWA metadata without credentials.
Telegram Integration (Optional)
For cron notifications to Telegram, see the cron-telegram-bridge setup:
# Create the bridge script at ~/.dsh/scripts/cron-telegram-bridge.js
# Create systemd service
sudo cp systemd/cron-telegram-bridge.service /etc/systemd/system/
sudo systemctl enable cron-telegram-bridge
sudo systemctl start cron-telegram-bridge
Troubleshooting
DSH won't start
- Check logs:
journalctl -u dsh -f - Verify Node.js is in PATH:
which node - Check DSH home exists:
ls ~/.dsh/
Proxy not accessible
- Check if the plugin loaded: Settings → Plugins → dsh-proxy
- Check port is open:
ss -tlnp | grep 3080 - Check firewall:
sudo ufw allow 3080/tcp
WebSocket not working
- The proxy must forward
UpgradeandConnectionheaders - If behind another proxy (nginx/Caddy), ensure WebSocket is enabled there too
Settings page shows "unavailable in this browser"
- The loopback patch may not be applied
- Check the proxy plugin is enabled in Settings → Plugins
- Clear browser cache and reload
Files
dsh-server-setup/
├── README.md # This file
├── PLUGINS.md # Plugin stack list
├── run.sh # DSH wrapper script
├── systemd/
│ └── dsh.service # Systemd unit file
└── dsh-proxy/ # Standalone proxy (alternative)
└── node/
├── index.js
├── proxy-core.js
└── package.json
Plugins
See PLUGINS.md for a full list of installed plugins with descriptions.
Credits
- Reverse proxy — smanx/dsh-proxy (MIT license). Also provides Go builds for standalone deployments.
- Remote access — Pangolin (self-hosted VPN + reverse proxy with WireGuard)
- DSH — DeepSeek Harness by DeepSeek AI
License
MIT