Preface¶
DSH’s web_fetch works fine in a direct connection environment, but once software like Clash, Surge, or v2rayN is running, fetching often fails. Troubleshooting usually points to two types of issues: TUN mode resolves domains to fake addresses like 198.18.x.x, and direct connection security checks reject them; or only “System Proxy” is enabled without TUN, DSH doesn’t read the system proxy, and websites requiring a proxy won’t open. Hardcoding HTTP_PROXY into ~/.dsh/.env does connect, but once the proxy is turned off, the model conversation also breaks. Below is an introduction to dsh-proxy-switch, a plugin written specifically for this scenario.
What is it¶
- Maintainer: lightrivers
- Package name:
@lightrivers/dsh-proxy-switch, version0.4.4, license MIT - GitHub: https://github.com/lightrivers/dsh-proxy-switch
- Directory page: https://www.skillhub.cn/plugins/lightrivers/dsh-proxy-switch, category “Network Tools”, starred 0
One-sentence positioning: Automatically detects the local HTTP proxy; when the proxy is on, web_fetch goes through the proxy, and after the proxy is turned off, it automatically switches back to direct connection, providing a switchable line for web_fetch. The default scope is “web_fetch only”, does not modify global network settings, process environment variables, or subprocess environments, so model conversations and other tools are not affected.
What problems does it solve¶
Applicable situations listed in README:
web_fetchreportsnon-public IP address, or domain is resolved to198.18.x.x- Proxy has TUN / Enhanced Mode / Fake-IP enabled,
web_fetchfails - Only System Proxy is enabled, TUN is not, DSH cannot read the system proxy, websites requiring a proxy cannot be opened
- After hardcoding
HTTP_PROXY, once the proxy is off, even model conversations are disconnected - Need to manually change configuration every time the proxy is toggled
The reason is that TUN mode resolves domains to fake addresses in the 198.18.0.0/15 segment; the web_fetch security check does not allow accessing internal network addresses when connecting directly. And once the proxy address is hardcoded, nothing can connect when the proxy is closed. The plugin provides a switchable line for web_fetch outside of these two paths.
It should be noted that the README explicitly states: Starting from DeepSeek Harness 0.2.2, web_fetch no longer rejects fake-IP and internal network addresses, so if only TUN is used, the new version can scrape web pages without installing the plugin. The plugin is still suitable for users who only enable system proxy or need to automatically switch based on proxy on/off; additionally, the plugin still only allows public network addresses during direct connection, which can block access to the local machine and internal network services.
Environment requirements¶
| Item | Requirement |
|---|---|
| DeepSeek Harness | Desktop 0.2.1, 0.2.2 (0.2.2-rc.1 tested) |
| System | macOS (fully verified); Windows, Linux (code supported, not fully verified on real machines) |
| Proxy | Local HTTP proxy or “Mixed Port” (Clash / mihomo / Clash Verge, Surge, v2rayN, etc.), SOCKS, PAC not supported |
Core features¶
-
Automatic proxy detection. Prioritizes reading system proxy settings (macOS Network Settings, Windows Internet Options, Linux GNOME/KDE proxy settings), then reads environment variables like
HTTPS_PROXYwhen DSH starts, and finally scans common ports 7890, 7897, 6152, 1087, 10809, etc. Each candidate address undergoes an actual handshake verification to ensure it is truly an HTTP proxy. -
Three lines:
auto(follows detection results),forward(fixed through proxy),direct(fixed direct connection). Defaultauto. Before eachweb_fetch, the plugin probes the proxy port locally, about 1 millisecond, so it won’t take the wrong line if the proxy was just turned off; if the proxy is not found, it connects directly, and the direct connection security check proceeds as normal. -
Switchable scope. Default
web_fetch_only, other modules only follow this line when explicitly choosingglobal. -
Manual entry for proxy requiring username/password. Use
http://user:pass@address:port. Passwords are only stored locally with permission 600, and are displayed as***in the interface, logs, and prompts. -
Current status attached to
web_fetchresults. The model can see this and tell you.
Installation and Enablement¶
In DeepSeek Harness, say the following to the model, then completely exit and reopen DSH:
用 plugin_manager 安装插件 @lightrivers/dsh-proxy-switch
After restarting, a small button will appear at the bottom right of the sidebar, showing the current line and status dot (e.g., “Through Proxy ●”).
If you previously wrote
HTTP_PROXY/HTTPS_PROXYin~/.dsh/.env, delete them before restarting. Otherwise, after the plugin is disabled, DSH will revert to the hardcoded proxy.
README also provides installation steps from source: download source code to ~/dsh-proxy-switch, then say to the model “Use plugin_manager to install plugin ~/dsh-proxy-switch” (it will execute plugin_manager action=install_bundle target=<absolute_path>), then completely exit and reopen DSH. When upgrading, git pull in the source code directory, then execute the installation steps again. This article only summarizes the README original text; for actual installation, please use the official installation method above.
When upgrading from version 0.4.1 and earlier (package name changed to @lightrivers/dsh-proxy-switch starting from 0.4.2), first let the model use plugin_manager to uninstall the old dsh-proxy-switch, then install the new version as above; settings and status will be retained.
Typical usage¶
Most people don’t need to do anything after installing. The default is “Auto”: the plugin reads system proxy settings, finds the proxy port, web_fetch goes through the proxy while the proxy is running, and automatically switches to direct connection after the proxy is turned off.
Click the button at the bottom of the sidebar to open the panel. Main area:
- Top large block: Which line is currently being used. Animated lines indicate smooth flow, symbols mark issues (✕ indicates a break there, 🔒 indicates proxy needs login, ❗ indicates instability). Small tag in top right corner is scope: “web_fetch only” or “All Tools”.
- Auto / Through Proxy / Direct: Select line.
- Proxy row: Found proxy address, how it was found (System Proxy, Env Var, or Port Scan), and latency; right button can re-detect.
- More settings: Manually enter proxy address, scope, where to put the button.
Button dots: 🟢 Normal, 🟠 Needs attention, 🔴 Problem, ⚪ Detecting.
The button position at the bottom left of the sidebar can be changed to the top of the conversation bar (suitable for people who often collapse the sidebar, on Windows the default row is hidden when the sidebar is collapsed) or “Do not display”. After selecting “Do not display”, settings remain in the “Plugins -> Proxy Switch” page.
When line and proxy status don’t match, the panel provides a sentence explaining it and a fix button. Follow the instructions on the button: click “Change to Auto” when proxy is on but fixed to direct; click “Manually enter address” when proxy is running but port not found, just fill in the port number (e.g., 7890).
Configuration and Status¶
Settings that can be changed in the panel are saved in ~/.dsh/storages/dsh-proxy-switch/state.json (directory permission 0700, file permission 0600), generally no need to edit manually.
| Field | Default | Description |
|---|---|---|
mode |
auto |
auto / forward (fixed proxy) / direct (fixed direct) |
upstreamSource |
auto |
When auto, proxy address is updated by detection results; when manual, only manually entered addresses are used |
upstream |
http://127.0.0.1:1082 |
Proxy address, only accepts http://host:port, can include user:pass@ |
scope |
web_fetch_only |
web_fetch_only (web_fetch only) / global (all tools) |
listenPort |
7899 |
Local port used only in “All Tools” mode |
probeIntervalMs |
15000 |
Interval for background proxy detection (3000–600000 ms), not provided for modification in the interface |
Button placement is a browser-side preference, saved in localStorage as dsh-proxy-switch.placement.
The plugin also provides a local status interface:
GET /dsh-proxy-switch/state
POST /dsh-proxy-switch/mode { "mode": "auto" | "forward" | "direct" }
POST /dsh-proxy-switch/settings { "scope"?, "upstream"?, "upstreamSource"?, "listenPort"?, "probeIntervalMs"? }
POST /dsh-proxy-switch/probe Immediately probe current proxy once
POST /dsh-proxy-switch/detect Immediately re-find proxy
The interface only accepts local requests, Host must be DSH’s own address, and validates Origin, Sec-Fetch-Site; POST also requires Content-Type: application/json and request header x-dsh-proxy-switch-request: 1.
How it works¶
The plugin only replaces the “send request” step of web_fetch: requests first enter the plugin’s own web_fetch provider, then pass through a local private channel (random port, listening only on 127.0.0.1), and are then routed to the HTTP proxy or the target website directly. Redirects, timeouts, size limits, and encoding handling still use DSH’s original implementation.
- When connecting directly, all DNS results must be public network addresses; fake-IP, internal network, loopback, NAT64 embedded private addresses, etc., are all rejected.
- When going through a proxy, local names like
localhost,.local,.lanand targets resolved to internal addresses on the local machine are rejected, but ultimately resolved by the proxy, so it is only mitigation. - The private channel generates a random token on each start; other programs on the local machine cannot borrow it (nor the saved proxy username/password); each request uses a new connection, so after switching lines, the old proxy tunnel is not reused.
Use cases and notes¶
Suitable:
- DSH
web_fetchfails in TUN / Fake-IP environments - Only System Proxy enabled without TUN
- Want automatic switching when proxy is toggled
- Want
web_fetchresults to include status prompts
Need to note:
- Only supports HTTP proxy (or Mixed Port), SOCKS, PAC not supported. Use
http://user:pass@host:portform manually if account/password is needed. - Currently fully verified only on macOS, Windows, Linux code is supported but not yet verified on real machines.
- The plugin runs with the permissions of the current DSH process. It is recommended to read the source code and LICENSE (MIT) before installing to confirm the source is trustworthy.
- Internal network access blocking when going through proxy is only mitigation, cannot guarantee 100%. When TUN is on, the local machine can only resolve to fake addresses, and the plugin cannot judge the real target; if DNS pollution resolves a normal website to an internal address, that website will be mistakenly rejected when going through the proxy, prompting “Forward mode rejected request”. Opening TUN or switching to a trusted DNS can restore it.
- README reminder: Plugin dependencies must be written in
peerDependencies, not independencies, otherwise a second copy of@deepseek-ai/dsh-http-proxywill be installed, and “All Tools” mode will silently fail. - README also provides test commands:
npm test(unit tests),DSH_RUNTIME_MODULES=/path/to/dsh/node_modules node scripts/e2e-host.mjs(real Cordis/WebRuntime integration tests),node scripts/e2e-real.mjs(optional, tested with real local HTTP proxy),node scripts/e2e-web-fetch-warning.mjs(warning text attached toweb_fetchresults).
Conclusion¶
The value of dsh-proxy-switch lies not in new capabilities, but in changing the line selection for web_fetch in proxy environments from “relying on hardcoding HTTP_PROXY and gambling” to “automatic detection, one-click switching, and defaulting not to affect other tools”. Whether to install depends on whether you usually have TUN on or only System Proxy on. Plugin directory page: https://www.skillhub.cn/plugins/lightrivers/dsh-proxy-switch , source code: https://github.com/lightrivers/dsh-proxy-switch .