dsh-model-fix

修复特定模型在 DeepSeek Harness(DSH)里「流式内容正常但回合必报错」的流式收尾缺陷

本仓库是 bitterSmilezzz/dsh-model-fix 的增强版:
在原版(muse-spark-1.2)基础上,加入了对 gpt-5.6-luna 的支持(同一缺陷,实测
2026-08-23:gpt-5.6-luna 流式/非流式响应的 finish_reason 均为 null,且流式不发 [DONE])。

背景:缺陷根因

opencode 聚合端点(https://opencode.ai/zen/go/v1)上的 muse-spark-1.2
gpt-5.6-luna 实现有缺陷:流式响应正常吐出内容,但从不发送 finish_reason、也不发送
[DONE]
,流直接关闭(同端点对照 deepseek-v4-flash / glm-5.2 均正常发送
finish_reason: 'stop' + [DONE])。

DSH 的 llm-pi-ai 走 pi-ai SDK(强制 stream: true 且要求流以 finish_reason 收尾),
于是每次对话的真实表现是:

  1. 内容正常流式显示;
  2. 结尾报 Stream ended without finish_reason(映射为 TRANSPORT 错误);
  3. 回合被判失败,且 TRANSPORT 在默认可重试列表里 → agent 级重试插件按
    maxRetries 反复重跑整步,烧多份 token

这与代理无关:直连与走代理的响应完全相同,换代理解决不了。

⚠️ 重要说明:无需开启 opencode 的「Allow models that train on request data」

使用 muse-spark-1.2 / gpt-5.6-luna(经 opencode-go 路由)不需要在 opencode 平台设置里
开启**「Allow models that train on request data」**。

  • 该开关是 opencode 的数据训练授权:开启后你的请求数据可能被用于模型训练,属于
    需要慎重对待的隐私授权,不要为了使用这些模型而开启它
  • 实测:不开启该开关,直连 https://opencode.ai/zen/go/v1 即可正常
    返回内容(本插件修复的只是流式收尾缺陷,与训练授权无关);
  • 若在 opencode 设置里看到该开关,保持关闭即可;本文档所述修复不依赖它。

开关位置见下图(opencode 设置页 → 提供商区域,与「启用部署在中国的模型」相邻):

opencode 设置页中的「Allow models that train on request data」开关(opencode 设置页 → 提供商区域)

本插件做什么

llm/stream waterfall 上,对匹配的模型把上述缺陷收尾为正常 stop

  • 仅当流已输出内容text-delta / reasoning-delta / tool-call-delta)且
    结尾错误代码为 TRANSPORT / STREAM_CLOSED 且错误信息明确是「缺少终止事件」
    (如 Stream ended without finish_reason)时才改写;
  • 真实传输故障(如 SocketError: other side closed不受影响,照常失败
  • 无内容的空响应也照常失败,不会被误吞。

修复后 muse-spark-1.2 / gpt-5.6-luna 直连即可正常使用,无需代理、不触发重试。

安装

1
2
3
4
5
# 从 GitHub 安装(推荐)
npx -y @deepseek-ai/dsh plugin --profile web add github:Retr67/dsh-model-fix

# 本地路径
# dsh plugin --profile web add /path/to/dsh-model-fix

安装后重启目标 profile(如 dsh web)生效。

配置

cordis.patch.ymlconfig 两个字段:

字段 默认 说明
modelPattern ^(muse-spark|gpt-5\.6-luna) 对模型 id 测试的正则;只修复匹配的模型
providers [] provider 路由键白名单(如 opencode-go3);空 = 所有 provider 中匹配的模型
1
2
3
4
5
- id: model-fix
name: dsh-model-fix
config:
modelPattern: '^(muse-spark|gpt-5\.6-luna)'
providers: []

只修 luna 可改为 modelPattern: '^gpt-5\.6-luna';只想限定某个路由可加
providers: [ 'opencode-go' ]

开发

1
2
pnpm install
pnpm verify # typecheck + build + node --test

验证矩阵

  • 单元测试:tests/fix.test.mjs 覆盖缺陷识别、内容保留、空响应放行、真实故障放行等 10 例。
  • 真实端点集成验证:用 pi-ai 同款 SDK 直连 muse-spark-1.2 / gpt-5.6-luna,内容经本插件转换后
    结尾由 error(Stream ended without finish_reason) 变为 {"kind":"stop"}

致谢

  • 上游:bitterSmilezzz/dsh-model-fix(MIT)
  • 缺陷取证(gpt-5.6-luna):2026-08-23 直连 opencode.ai/zen/go/v1 复现——流式 10 个 chunk
    finish_reason 全程 null、无 [DONE],尾部为 data: {"choices":[],"cost":"0"}
    非流式响应 finish_reason 同样为 null

dsh-plugin-manager

DeepSeek Harness (DSH) 插件管理器:在 WebUI 设置 → 插件 → 插件管理 里可视化查看、临时打开、关闭其他插件。

  • 入口位于 设置 → 插件 → 插件管理(作为 settings.plugins.tab 槽位注册的一个标签页,与自带「可配置」标签并列)。
  • 用户插件(可开关):你在 profile/package.json 里安装的社区插件 + 你自己在 cordis.patch.yml 里加的条目(如 MCP 桥梁)。
  • 系统组件(只读):DSH 自带的 host/web 基础设施,只展示、不提供开关,避免误关导致 Harness 起不来。
  • 开关无需重启 dsh:走的是 Cordis loader 的 entry.update({ disabled })(与官方 dsh-market 主题开关同一条路)。默认在切换后自动刷新网页,让带前端界面的插件(桌宠、侧边栏等)也立即完全生效;也可在面板里切到手动刷新模式(选择保存在浏览器 localStorage)。
  • 跨重启保持:被关闭的插件 id 会记在 <profile>/.plugin-manager/state.json,下次启动时自动回放为关闭,直到你把它打开。
  • 「全部恢复开启」按钮一键清空所有保持关闭的插件。

结构

1
2
3
4
5
6
7
dsh-plugin-manager/
├── package.json # dsh.bundle + dsh.client 声明
├── cordis.patch.yml # 挂载 plugin-manager 主机条目
├── dsh/
│ ├── index.js # 主机端:HTTP API + loader 枚举/开关 + 状态持久化
│ └── client.js # 浏览器端:注册 设置→插件→插件管理 标签页(React)
└── README.md

与官方机制的关系

  • 不走 package.jsondsh.profile.bundles 增删(那需要重启才生效),而是对运行中的 loader entry 做热开关——这是 dsh-market 主题切换验证过的做法。
  • 状态持久化与启动回放、自愈守卫(internal/plugin 事件)同样移植自 dsh-market。
  • group 插件(如记忆插件 openviking-memory)无法直接置 disabled,管理器会自动改为开关其子条目。

HTTP API(同源校验)

方法 路径 说明
GET /plugin-manager/list 返回插件列表与开关状态
POST /plugin-manager/toggle { id, enabled } 热开关某个插件
POST /plugin-manager/reset 恢复所有被保持关闭的插件

POST 接口(toggle/reset)做了 Origin === Host 的同源校验;GET 列表是只读、且只暴露在回环地址绑定的 web server 上,不再要求 Origin 头(同源 GET fetch 默认不携带 Origin,要求它会导致面板报 untrusted origin)。

安全

  • 主机端仅使用 node 内置模块(fs/os/path),无网络调用、无子进程、无 eval。
  • 客户端用 React 渲染插件名(自动转义,无 XSS),所有请求都是同源 fetch。
  • 管理器自己(plugin-manager)不会被关闭;系统组件不会提供开关。

License

MIT

原因:酒馆发送的请求主体中不能有stop主体参数。

解决办法:点击API设置界面的附加参数按钮,在排除主体参数栏内填写stop,以不发送此主体参数。

Automatic Gemini API key rotation for modlens on DeepSeek Harness (dsh) — when one key hits its quota (HTTP 429), the read
automatically switches to the next key in the pool and retries, with zero
intervention. Works everywhere modlens reads an image: the dsh GUI paste flow,
the modlens_read_image tool, and the CLI.

⚠️ Unofficial: this patches the installed modlens package. The patch is
wiped by any modlens upgrade; patch.ps1 re-applies it in one command.
If modlens upstream ever ships native multi-key support, drop this project.

Why

modlens reads images through a single Gemini API key stored in ~/.modlens/config.json. Free-tier keys hit daily quota (429 RESOURCE_EXHAUSTED) / rate limits quickly, and modlens has no retry or
failover for that. This project adds:

  • a key pool (~/.modlens/api-keys.json) — list, add, rotate, inspect
  • an engine patch — 429 triggers an automatic switch to the next pool key,
    persisted to the config, then a retry of the same request (up to 8 rotations)
  • a CLI wrapper — 429 → rotate + retry; 5xx → backoff retry on the same key
  • a re-patch script — re-applies the engine patch after a modlens upgrade

Requirements

  • DeepSeek Harness (dsh) with the modlens plugin installed: npx -y @deepseek-ai/dsh plugin --profile web add @liustack/modlens@<version>
  • Node 22.19+ (modlens requirement)
  • PowerShell (Windows) — the scripts are .ps1

Install

Clone this repo (or copy scripts/), then:

1
2
3
4
5
6
7
8
9
# 1. copy scripts next to the modlens config
Copy-Item scripts\* "$env:USERPROFILE\.modlens\"
# or link: New-Item -ItemType SymbolicLink ... (per-file)

# 2. apply the engine patch (idempotent)
powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.modlens\patch.ps1"

# 3. seed the key pool (one command per key)
powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.modlens\rotate.ps1" add <GEMINI_API_KEY>

The active key is the one modlens uses: if you already configured a key via modlens config set gemini-api.apiKey, add it to the pool too so rotation can
cycle back to it.

Usage

1
2
3
4
5
6
7
8
# manage the pool
rotate.ps1 list # show pool, >> marks the active key
rotate.ps1 status # pool size + active key (masked)
rotate.ps1 rotate # switch to the next key (persists)
rotate.ps1 add <key> # add a key to the pool

# read an image with automatic rotation
ml.ps1 -Image <path-or-url>

The engine patch makes rotation automatic for every read path (GUI paste, modlens_read_image tool, CLI), so rotate.ps1 rotate is mainly for manual
override or diagnosis.

If you use a proxy

modlens itself supports it — no changes needed here:

1
modlens config set proxy http://127.0.0.1:<port>

Note: Google’s Gemini API is region-restricted. A proxy exit in an unsupported
region (e.g. mainland China, Thailand) fails with 400 User location is not supported for all keys — rotation cannot fix
that; switch the proxy node instead.

After a modlens upgrade

1
powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.modlens\patch.ps1"

It detects whether the patch is still present; if a new version changed the
targeted code and the hunks no longer match, it reports which hunk failed and
tells you to file a new patch.

How it works

modlens ships two components in one package:

  • dsh/index.js — the dsh plugin shell: registers modlens_read_image,
    handles paste-to-path. It contains no image-reading logic; it spawns a
    child process running the CLI engine.
  • dist/main.js — the CLI engine: reads the image, calls Gemini
    (executeGeminiApi), parses structured JSON. Every read path funnels
    through this file.

The patch lives in executeGeminiApi: a single request becomes a loop that
rotates the pool on 429. See PATCH.md for the exact change.

Security

  • Keys are stored in plain text at ~/.modlens/api-keys.json (same trust
    level as modlens’s own config.json, which also stores the key in plain
    text). Do not share your home directory.
  • This repo contains no keys, no credentials, no machine-specific paths
    all paths derive from $env:USERPROFILE.

Credits & license

  • modlens by Leon Liu (liustack) — the vision engine this project wraps and patches. MIT licensed
    (Copyright © 2026 Leon Liu), see LICENSE.modlens.
    The patch hunks in this repo are a derivative modification of modlens
    source and carry its MIT notice as required.
  • This project is not endorsed by upstream — it is an independent utility
    that depends on modlens.
  • Our own scripts and docs: MIT (see LICENSE).
  • Full attribution: ACKNOWLEDGMENTS.md — please star
    the upstream project, the real work lives there.

修复 OpenViking 在 Windows + 本地向量库 + 本地 embedding 模型 组合下,记忆文件已生成但搜索不到的问题。

问题现象

  • OpenViking 服务可以正常启动
  • 记忆文件可以正常生成
  • 但执行搜索时返回空结果
1
ov find "LoopingIsle" --context-type memory

返回:

1
2
3
4
5
6
7
8
9
{
"ok": true,
"result": {
"memories": [],
"resources": [],
"skills": [],
"total": 0
}
}

服务日志出现:

1
2
openviking.storage.viking_vector_index_backend - ERROR - Error reading existing record before partial update: Strings must be encoded before hashing
openviking.storage.collection_schemas - ERROR - Failed to write to vector database: Strings must be encoded before hashing

根本原因

OpenViking 在把字符串 ID 转成 64 位整数时,使用了:

1
xxhash.xxh64(input_string)

xxhash 在 Python 3 中要求传入 bytes,不能直接传入 str,因此抛出:

1
Strings must be encoded before hashing

这导致:

  • 记忆 Markdown 文件正常写入
  • 向量没有成功写入向量库
  • 所以记忆文件存在,但语义搜索找不到

修复

修改文件:

1
openviking/storage/vectordb/utils/str_to_uint64.py

修改前:

1
2
def str_to_uint64(input_string: str) -> int:
return xxhash.xxh64(input_string).intdigest()

修改后:

1
2
def str_to_uint64(input_string: str) -> int:
return xxhash.xxh64(input_string.encode("utf-8")).intdigest()

补丁文件

文件 说明
patches/0001-fix-str_to_uint64-xxhash-encoding.patch Git 补丁,可直接 git apply
patches/patch-openviking-xxhash.ps1 Windows PowerShell 一键打补丁脚本
patches/fix-openviking-memory.ps1 重置向量库并重新索引记忆的修复脚本

使用方法

方法一:Git apply

1
git apply patches/0001-fix-str_to_uint64-xxhash-encoding.patch

方法二:PowerShell 脚本

1
powershell -ExecutionPolicy Bypass -File patches\patch-openviking-xxhash.ps1

修复后重新索引

1
2
ov reindex viking://user/default/memories --mode semantic_and_vectors --wait true
ov find "LoopingIsle" --context-type memory

环境

项目
操作系统 Windows
Python 3.14.7
OpenViking 0.4.14
向量库 local 本地向量库
Embedding 本地 GGUF 模型(512 维)
VLM OpenCode Go(deepseek-v4-flash

为什么很多人没遇到

这个 bug 主要在以下组合下出现:

  • Windows
  • Python 3.14
  • 本地向量库
  • 本地 GGUF embedding 模型

大多数用户使用的是:

  • Linux + Docker
  • 云端 embedding API
  • 云端/托管向量数据库
  • 较旧的 Python 版本

所以这条本地路径测试覆盖较少。

额外注意

如果只是移动了 OpenViking 目录导致向量库元数据路径不匹配,可以在配置中加:

1
2
3
4
5
{
"embedding": {
"allow_metadata_override": true
}
}

前提是模型没有换、维度没有变。

有始有终,值得好评。

虽然后面有点赶,但感觉把想呈现的效果都呈现了。

就像看了一段也许真的存在的冒险。人物的变化和成长也悄然地推进,不突兀挺好。

原本是单人游戏,但我是跟朋友一起用合作模式通的关。

对于多人体验而言,如果不是多人游戏荒了,不建议把这游戏作为首选项。

各种解密和动作体验中规中矩,在2026年下,没有啥新鲜内容。

各种互动还算不错,动作有些僵硬。

剧情方面中等偏上水准。

值得一提的是,在剧情的最后,当主角处在一个特殊状态下时,一开始无法正确地前往目的地,当我以为附近有什么谜题时,突然脑子里意识到了一个新的可能性,当我把这个可能性告诉我朋友,并真的成功时,当时带给我的尤里卡时刻,还是非常震撼的,并且这个设计也十分符合剧情和玩法,让游戏的机制玩法解释了剧情,让剧情和体验更上了一层楼。甚至我有点怀疑,作者是因为这个时刻,才做了这么一款游戏。

准备工作

在开始之前,请确保你具备以下条件:

  • 一台 Linux 服务器:本文以 Ubuntu为例。

  • 一个公网 IP:确保你的服务器拥有独立的公网 IP,或已做好端口映射。

  • 开放防火墙端口:确保服务器防火墙和云服务商的安全组放行以下端口:

端口 协议 用途
9987 UDP 语音通信 (最核心)
30033 TCP 文件传输 (头像/图标)
10011 TCP 服务器远程管理 (ServerQuery)
41144 TCP 新版客户端查询端口

许可证说明:TeamSpeak 3 对非商业用途免费,内置 1个虚拟服务器 和 32个在线用户 的限制,对绝大多数私人团队来说完全够用。


开始安装

系统更新与创建用户

为了安全,我们强烈建议不要使用 root 账号运行 TS3 服务。

更新系统

sudo apt update && sudo apt upgrade -y

创建一个名为 teamspeak 的系统用户

sudo adduser teamspeak

切换到该用户

su - teamspeak

下载服务端软件

进入用户目录,并从官网下载最新版服务端(请以官网最新版本号为准):

cd /home/teamspeak

下载服务端压缩包 (以 3.13.7 版本为例)

wget https://files.teamspeak-services.com/releases/server/3.13.7/teamspeak3-server_linux_amd64-3.13.7.tar.bz2

解压

tar -xjvf teamspeak3-server_linux_amd64-*.tar.bz2

启动服务器

进入解压后的目录,接受许可协议并启动:

cd teamspeak3-server_linux_amd64

创建同意许可协议的文件

touch .ts3server_license_accepted

启动服务器

./ts3server_startscript.sh start


🚨 关键步骤:保存管理员令牌

首次启动时,终端日志中会显示两行极其重要的信息:

ServerAdmin privilege key created, please use it to gain serveradmin rights for your virtualserver.
token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

请立即复制并保存这个 token(令牌)。如果你关闭了终端,将无法找回,只能清空数据重新初始化。


设置开机自启 (Systemd)

为了确保服务器在重启后自动运行,我们可以将其注册为系统服务。

创建服务文件 (需要 root 权限):

sudo nano /etc/systemd/system/teamspeak3.service

粘贴以下配置 (注意将 /path/to 替换为你的实际绝对路径):

[Unit]
Description=TeamSpeak 3 Server
After=network.target
[Service]
User=teamspeak
Group=teamspeak
WorkingDirectory=/home/teamspeak/teamspeak3-server_linux_amd64
ExecStart=/home/teamspeak/teamspeak3-server_linux_amd64/ts3server
ExecStop=/home/teamspeak/teamspeak3-server_linux_amd64/ts3server_startscript.sh stop
ExecReload=/home/teamspeak/teamspeak3-server_linux_amd64/ts3server_startscript.sh restart
Restart=always
RestartSec=15
[Install]
WantedBy=multi-user.target

重载配置并启用

sudo systemctl daemon-reload
sudo systemctl enable teamspeak3
sudo systemctl start teamspeak3


连接与使用

下载客户端:从 TeamSpeak 官网 下载适用于你系统的客户端。

连接服务器:打开客户端,点击 Connections -> Connect,输入你的 服务器 IP 地址(端口默认 9987,可不填)。

获取管理员权限:首次进入频道时,客户端会弹出窗口要求输入 Token。粘贴你在第三步保存的令牌,即可获得管理员权限。


常见问题排查 (Troubleshooting)

问题现象 可能原因与解决方案
客户端连接不上 1. 检查 UDP 9987 端口是否放行,这是最常见的坑。
2. 检查云服务商安全组策略。
听不到声音/语音卡顿 检查服务器带宽是否跑满,或客户端 Codec 设置是否过高。
丢失了管理员 Token 停止服务端,删除 /home/teamspeak/teamspeak3-server_linux_amd64 下的 query_ip_whitelist.txt 和 query_ip_blacklist.txt,重启后控制台会生成新 Token。

搭建 TeamSpeak 音乐机器人 (teamspeak-music-bot)

有了 TeamSpeak 服务器之后,不妨再给它配上一个“点歌台”。teamspeak-music-bot 是一个功能强大的开源音乐机器人,链接,支持从网易云音乐、QQ音乐、酷狗音乐、哔哩哔哩等多个平台搜索并播放音乐。它最大的亮点在于提供了一个 YesPlayMusic 风格的 WebUI 控制面板,让你可以通过浏览器轻松管理播放,体验非常接近专业的音乐播放器。

从零搭建自托管加密 DNS:AdGuard Home 完整配置指南

如果你受够了运营商的 DNS 劫持,想在手机、电脑上全局去广告,又希望保护上网隐私,这篇文章就是为你准备的。


📖 前言

我花了几天时间,从一台云服务器开始,一步步搭建了自己的加密 DNS 服务。整个过程踩了不少坑:证书申请、端口配置、iOS 描述文件、安卓 DoT 连接失败……最终所有设备都成功跑了起来。

这篇文章就是完整的操作记录,希望能帮你少走弯路。


🎯 最终效果

  • 全屋去广告:所有连接到 AdGuard Home 的设备自动屏蔽广告
  • 加密 DNS:手机蜂窝网络、公共 Wi-Fi 下 DNS 查询全程加密
  • 跨设备支持:iPhone、安卓、Windows 全部配置完成
  • 自动续期:证书到期自动更新,无需人工干预

🧱 整体架构

1
2
3
4
5
6
7
8
9
10
11
12
13
互联网


┌─────────────────┐
│ 云服务器 │
│ (公网 IP) │
│ 运行 AdGuard Home│
│ 监听 443/853 端口│
└─────────────────┘
│ │
▼ ▼
iPhone 安卓手机 电脑
(DoH/TLS) (DoH) (DoH)

第一部分:准备工作

1.1 域名与服务器

  • 域名:我使用的是在 NameSilo 注册的域名
  • 服务器:一台有公网 IP 的云服务器(我是阿里云)
  • 系统:Ubuntu

1.2 域名解析

在 DNS 服务商控制台添加 A 记录:

记录类型 主机记录 记录值
A @ 你的服务器公网 IP
A www 你的服务器公网 IP

第二部分:安装 AdGuard Home

2.1 一键安装

1
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v

安装完成后,访问 http://你的服务器IP:3000 进行初始化设置。

2.2 设置用户名和密码

按照网页指引完成设置,记住你设置的管理员账号密码。


第三部分:申请 SSL 证书

3.1 为什么需要证书?

AdGuard Home 启用 DoH/DoT 加密必须使用 SSL/TLS 证书。我使用 Let’s Encrypt 的免费证书。

3.2 手动申请证书(首次)

先通过手动 DNS 验证方式申请:

1
sudo certbot certonly --manual --preferred-challenges=dns -d 域名

系统会提示你添加 TXT 记录:

1
_acme-challenge.域名 TXT "这里是一串验证值"

添加完成后等待生效,按回车继续。证书申请成功,一共有两份。

⚠️ 注意--manual 方式不会自动续期!我们后面会改成自动方式。

3.3 查看证书内容

将输出的内容(从 -----BEGIN CERTIFICATE----------END CERTIFICATE-----)复制下来。


第四部分:配置 AdGuard Home 加密

4.1 进入加密设置

登录 AdGuard Home 管理面板 → 设置加密

4.2 填写证书

配置项 填写内容
启用加密 ✅ 勾选
服务器名称 域名
证书 粘贴 fullchain.pem 的全部内容
私钥 粘贴 privkey.pem 的全部内容
HTTPS 端口 443(DoH 端口)
DNS-over-TLS 端口 853(DoT 端口)

💡 进阶做法:填完内容后,可以改为填写文件路径,方便自动续期时自动加载。

4.3 放行端口

服务器防火墙(如 ufw):

1
2
3
sudo ufw allow 443/tcp
sudo ufw allow 853/tcp
sudo ufw reload

云服务商安全组:在控制台添加入站规则,允许 TCP 443 和 853 端口。


第五部分:各设备端配置

5.1 iPhone / iPad(通过描述文件)

推荐方式:使用在线工具生成描述文件

  1. 访问 dns.notjakob.com
  2. 选择 DNS-over-HTTPS (DoH)
  3. DoH server URL 填写:https://域名/dns-query
  4. IPv4/IPv6 填写你喜欢的公共DNS
  5. 生成并下载 .mobileconfig 文件
  6. 通过 QQ/微信/邮件传到 iPhone,iPhone用自带的文件APP另存,并在文件APP里打开,进行安装

安装路径:设置 → 通用 → VPN 与设备管理 → 已下载的描述文件

5.2 安卓手机(推荐 DoH)

安卓系统内置的“私人 DNS”仅支持 DoT(853 端口),但国内网络环境可能干扰 853 端口。推荐使用 DoH

使用 Intra 应用(Google 官方开源):

  1. 在 Google Play 下载 Intra

5.3 Windows 电脑

方法一:系统网络设置(推荐)

  1. 设置 → 网络和 Internet → Wi-Fi/以太网
  2. 点击当前网络 → DNS 服务器分配 → 编辑 → 填写你的服务器公网IP
0%