diff --git a/.github/DISCUSSION_TEMPLATE/q-a.yml b/.github/DISCUSSION_TEMPLATE/q-a.yml index fe91431..870d4cb 100644 --- a/.github/DISCUSSION_TEMPLATE/q-a.yml +++ b/.github/DISCUSSION_TEMPLATE/q-a.yml @@ -23,7 +23,7 @@ body: attributes: label: Version description: Relevant release, build, commit, or branch, if known. - placeholder: e.g. 0.0.16-rc.4, develop, or commit SHA + placeholder: e.g. 0.0.1; include the build commit SHA when available - type: input id: environment diff --git a/.gitignore b/.gitignore index 26b6719..a980c54 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ node_modules/ docs/.vitepress/cache/ docs/.vitepress/dist/ +dist/ *.log .DS_Store Thumbs.db diff --git a/.openai/hosting.json b/.openai/hosting.json new file mode 100644 index 0000000..409fc60 --- /dev/null +++ b/.openai/hosting.json @@ -0,0 +1,6 @@ +{ + "project_id": "appgprj_6a9afc0c8bd08191a8755ee6cd67ef09", + "static": { + "directory": "dist" + } +} diff --git a/CONTENT_SYNC.md b/CONTENT_SYNC.md new file mode 100644 index 0000000..56bb9c2 --- /dev/null +++ b/CONTENT_SYNC.md @@ -0,0 +1,36 @@ +# Content synchronization baseline + +Public guides were checked on 2026-09-09 against freshly fetched GitHub `main` revisions. None of the three product repositories has a `master` branch. Source was read from immutable Git archives, excluding develop, feature branches and uncommitted changes. In particular, the client checkout contains ongoing uncommitted work and the panel checkout is on a feature branch; neither is the documentation baseline. + +| Repository | Main revision | +| --- | --- | +| core | `503229562ef5854e3be6be3a9c8e7cbc5efffc61` | +| znet-sink | `6d822fb96140be87cdccdd0bea472ba0b089cf04` | +| zboard | `e1b7246cc4ef805bf39b22d634ba209114eb3b14` | +| docs develop before this update | `8e00ddfeec94707c1c2dd2d587f68ed23386c3ef` | + +GitHub release API responses confirmed public, non-draft, non-prerelease `v0.0.1` releases for all three products. This verifies publication, not installed behavior or every main change in a downloaded artifact. The public [implementation progress page](docs/progress.md) links the pinned evidence and release records. + +## Evidence and changes + +- Core: inspected `crates/config/src/model/route.rs`, route compilation/validation, `crates/engine/src/runtime/route.rs`, `crates/proxy/src/adapters/direct/{inbound,udp}.rs`, and management, validation-isolation and URLTest implementation notes/test references. Added `route.bypass` precedence, management-only startup, Direct UDP capability and bind semantics, validation isolation, and the distinction between policy probes and read-only diagnostics. Corrected the old Direct UDP matrix entry and develop-only version notices. +- Client: inspected `src-tauri/src/services/bypass.rs`, `services/bypass/rules.rs`, `services/kernel_settings.rs`, `models/app_config.rs`, Network/TUN settings components, kernel integration and v0.0.1 qualification records. Updated the shared bypass editor, TUN exclusions, portable settings v2, lifecycle semantics and the shared 0.0.1 installation/recovery baseline. The four-platform installed-E2E waiver remains an outstanding acceptance boundary. +- Panel: inspected `backend/internal/handler/{admin_order_assignment,node_publish_worker,node_delete_cascade,dns_deletion,certificate_deletion,network_entry_delivery,network_entry_capabilities,managed_rule_client_compatibility,kernel_automation}.go`, related tests and implementation notes. Updated fronting and explicit landing authorization, shared proxy pools, durable publication, administrator order confirmation, client-specific rules, the shared 0.0.1 capability baseline, and database-only deletion versus independent remote cleanup. The compiler still injects a bootstrap listener even though Core now supports management-only operation. +- Release and scope records distinguish existing main implementation from plans, including panel online payment/plugin runtime and product installed/long-running acceptance. No product code, live network settings or remote node state was changed. + +## Version terminology + +All three product versions are 0.0.1. Public guides no longer use pre-reset release matrices, minimum-version thresholds, package names or User-Agent examples. Git tags, download URLs and image tags retain the actual `v0.0.1` spelling. API V1, client settings v2 and ZRS 0.1 remain independent protocol/data-format versions. The public compatibility page describes the current 0.0.1 contract rather than reconstructing historical release claims. + +## Verification + +- `pnpm check:build` passed for 69 Markdown pages: links, anchors, JSON examples, project boundaries, navigation, reachability and production output. Local tools were Node 24.19.0 and pnpm 11.19.0; repository CI independently uses Node 22 and pnpm 11.9.0. +- `git diff --check` passed. The progress page and three project entry pages contain 23 pinned source references, checked against the archived trees. +- The final `/progress` development route returned HTTP 200. No browser visual acceptance was performed. +- Existing dependencies were reused; the package manifest, lockfile and hosting/workflow configuration remain unchanged; the discussion question template now uses the 0.0.1 example. + +This task did not run Rust/Go product suites, installed clients, live TUN changes, payment/email delivery or node cleanup. + +## Delivery + +The target is docs `develop` through a `codex/*` pull request. Current GitHub branch rules require a pull request and the `validate` status check. GitHub Pages listens to develop pushes; this documentation PR does not itself deploy a product or publish the separate Sites preview. diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 27162b8..3a406a5 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -28,6 +28,12 @@ export default defineConfig({ ], themeConfig: { + logo: { + light: '/brand/zerodenet-light.png', + dark: '/brand/zerodenet-dark.png', + alt: 'ZeroDeNet', + }, + siteTitle: false, nav, sidebar, search: { diff --git a/docs/.vitepress/navigation.ts b/docs/.vitepress/navigation.ts index e77020c..d6ded2c 100644 --- a/docs/.vitepress/navigation.ts +++ b/docs/.vitepress/navigation.ts @@ -9,10 +9,12 @@ const group = ( ): DefaultTheme.SidebarItem => ({ text, items, collapsed }) export const nav: DefaultTheme.NavItem[] = [ + { text: '下载客户端', link: '/download' }, { text: '项目', items: [ { text: '全部项目', link: '/projects/' }, + { text: '实现与文档进度', link: '/progress' }, { text: '客户端', items: [ @@ -46,6 +48,7 @@ export const nav: DefaultTheme.NavItem[] = [ const solutionSidebar: DefaultTheme.SidebarItem[] = [ page('使用场景', '/solutions/'), + page('实现与文档进度', '/progress'), group('项目', [ page('全部项目', '/projects/'), page('ZNet Sink', '/projects/znet-sink/'), @@ -67,6 +70,7 @@ const coreSidebar: DefaultTheme.SidebarItem[] = [ page('安装与构建', '/projects/core/guides/installation'), page('启动第一个节点', '/projects/core/guides/quickstart'), page('配置基础', '/projects/core/guides/configuration-basics'), + page('运行 TUN 与 DNS', '/projects/core/guides/tun-and-dns'), ], false), group('日常管理', [ page('运行与观测', '/projects/core/guides/operations'), @@ -90,6 +94,7 @@ const coreSidebar: DefaultTheme.SidebarItem[] = [ page('参考入口', '/projects/core/reference/'), page('能力与端口速查', '/projects/core/reference/technical-specifications'), page('配置字段', '/projects/core/configuration/'), + page('DNS 与 Fake-IP 参数', '/projects/core/configuration/dns'), page('运行模式与出站组', '/projects/core/configuration/modes-and-groups'), page('构建特性', '/projects/core/configuration/features'), page('控制接口总览', '/projects/core/control-plane/'), @@ -118,6 +123,9 @@ const sinkSidebar: DefaultTheme.SidebarItem[] = [ group('功能说明', [ page('功能总览', '/projects/znet-sink/guides/features'), page('订阅管理', '/projects/znet-sink/guides/subscriptions'), + page('DNS 与 Fake-IP', '/projects/znet-sink/guides/dns'), + page('TUN 接管与网络切换', '/projects/znet-sink/guides/tun'), + page('迁移设置与管理内核', '/projects/znet-sink/guides/settings-transfer'), page('本地代理与节点测速', '/projects/znet-sink/guides/proxy-and-probes'), ], false), group('帮助与诊断', [ @@ -135,11 +143,15 @@ const zboardSidebar: DefaultTheme.SidebarItem[] = [ page('用户指南入口', '/projects/zboard/guides/'), page('安装与部署', '/projects/zboard/guides/installation'), page('首次初始化', '/projects/zboard/guides/first-setup'), + page('后台导航与日常运营', '/projects/zboard/guides/daily-operations'), ], false), group('功能说明', [ page('节点与协议服务管理', '/projects/zboard/guides/node-management'), page('协议服务配置', '/projects/zboard/guides/protocol-services'), + page('套餐、订单与用户交付', '/projects/zboard/guides/plans-and-orders'), page('订阅交付与流量展示', '/projects/zboard/guides/subscriptions-and-traffic'), + page('公告、注册验证与邮件', '/projects/zboard/guides/announcements-and-email'), + page('系统维护与数据库迁移', '/projects/zboard/guides/maintenance'), page('DNS 与证书管理', '/projects/zboard/guides/dns-and-certificates'), page('故障排查', '/projects/zboard/guides/troubleshooting'), ]), @@ -149,6 +161,7 @@ const zboardSidebar: DefaultTheme.SidebarItem[] = [ ] export const sidebar: DefaultTheme.Sidebar = { + '/progress': solutionSidebar, '/solutions/': solutionSidebar, '/community/': communitySidebar, '/projects/core/': coreSidebar, @@ -156,6 +169,7 @@ export const sidebar: DefaultTheme.Sidebar = { '/projects/zboard/': zboardSidebar, '/projects/': [ page('项目目录', '/projects/'), + page('实现与文档进度', '/progress'), group('应用', [page('ZNet Sink', '/projects/znet-sink/')]), group('内核', [page('Zero Core', '/projects/core/')]), group('运营平台', [page('Zboard', '/projects/zboard/')]), diff --git a/docs/.vitepress/projects.json b/docs/.vitepress/projects.json index b1f8f58..069f79c 100644 --- a/docs/.vitepress/projects.json +++ b/docs/.vitepress/projects.json @@ -10,6 +10,7 @@ "docsRoot": "/projects/znet-sink/", "quickStart": "/projects/znet-sink/guides/installation", "download": "https://github.com/zerodenet/znet-sink/releases/latest", + "downloadPage": "/download", "platforms": ["Windows", "macOS", "Linux"], "audiences": ["user", "contributor"] }, @@ -33,7 +34,7 @@ "tagline": "代理服务运营管理", "description": "基础设施、协议服务、节点组、商品、订单、订阅、配置交付和流量管理。", "kind": "application", - "status": "preview", + "status": "active", "repository": "https://github.com/zerodenet/zboard", "docsRoot": "/projects/zboard/", "quickStart": "/projects/zboard/guides/installation", diff --git a/docs/.vitepress/projects.ts b/docs/.vitepress/projects.ts index a90a885..f0af714 100644 --- a/docs/.vitepress/projects.ts +++ b/docs/.vitepress/projects.ts @@ -21,6 +21,7 @@ export interface ProjectDefinition { docsRoot: string quickStart?: string download?: string + downloadPage?: string platforms?: string[] audiences: string[] } diff --git a/docs/.vitepress/theme/components/DownloadChooser.vue b/docs/.vitepress/theme/components/DownloadChooser.vue new file mode 100644 index 0000000..c61e9bd --- /dev/null +++ b/docs/.vitepress/theme/components/DownloadChooser.vue @@ -0,0 +1,320 @@ + + + + + + SMART DOWNLOAD + 为你的设备准备好安装包 + 页面只判断设备平台与浏览器可提供的架构信息;无法可靠识别时,会把可选安装包全部列出。 + + + + + 正在读取最新稳定版… + + + + 暂时无法读取安装包列表 + 可以前往 GitHub Releases 继续下载。 + 打开发布页 ↗ + + + + + 最新稳定版 {{ release.tag_name }} + {{ releaseDate }} + + + + + 已识别 {{ platformLabels[platform] }} + {{ recommended.label }} + {{ recommended.format }} · {{ recommended.architecture === 'arm64' ? 'ARM64' : 'x86-64' }} · {{ formatBytes(recommended.asset.size) }} + + 立即下载 + + + + 已识别 macOS + 浏览器没有提供芯片信息,请在下方选择 Apple 芯片或 Intel。 + + + + 这是桌面客户端 + 请在 Windows、macOS 或 Linux 电脑上打开本页,或从下方手动选择。 + + + + + {{ platformLabels[item] }} + + + + + {{ item.format }} + + {{ item.label }} + {{ item.architecture === 'arm64' ? 'ARM64' : 'x86-64' }} · {{ formatBytes(item.asset.size) }} + + ↓ + + + + + + 安装包由 ZeroDeNet 的 GitHub Releases 提供。 + 查看发布说明 ↗ + + + + + + diff --git a/docs/.vitepress/theme/components/ProjectCatalog.vue b/docs/.vitepress/theme/components/ProjectCatalog.vue index 82fb7f5..3dea670 100644 --- a/docs/.vitepress/theme/components/ProjectCatalog.vue +++ b/docs/.vitepress/theme/components/ProjectCatalog.vue @@ -6,6 +6,9 @@ defineProps<{ compact?: boolean }>() const displayAddress = (url: string) => url.replace(/^https?:\/\//, '') const quickStartLabel = (kind: string) => kind === 'application' ? '安装与使用' : '快速开始' +const downloadHref = (project: (typeof projects)[number]) => ( + project.downloadPage ? withBase(project.downloadPage) : project.download +) @@ -47,7 +50,13 @@ const quickStartLabel = (kind: string) => kind === 'application' ? '安装与使 进入文档 → {{ quickStartLabel(project.kind) }} - 下载 + 下载 源码 diff --git a/docs/.vitepress/theme/components/ProjectMeta.vue b/docs/.vitepress/theme/components/ProjectMeta.vue index 0de07ff..cc0ef7d 100644 --- a/docs/.vitepress/theme/components/ProjectMeta.vue +++ b/docs/.vitepress/theme/components/ProjectMeta.vue @@ -5,6 +5,9 @@ import { getProject, projectKindLabels, projectStatusLabels } from '../../projec const props = defineProps<{ projectId: string }>() const project = computed(() => getProject(props.projectId)) +const downloadHref = computed(() => ( + project.value.downloadPage ? withBase(project.value.downloadPage) : project.value.download +)) const displayAddress = (url: string) => url.replace(/^https?:\/\//, '') @@ -18,12 +21,12 @@ const displayAddress = (url: string) => url.replace(/^https?:\/\//, '') 下载最新版 ↗ + :href="downloadHref" + :target="project.downloadPage ? undefined : '_blank'" + :rel="project.downloadPage ? undefined : 'noreferrer'" + >下载最新版 {{ project.downloadPage ? '→' : '↗' }} {{ project.kind === 'application' ? '安装指南' : '快速开始' }} diff --git a/docs/.vitepress/theme/custom.css b/docs/.vitepress/theme/custom.css index accde56..df8a639 100644 --- a/docs/.vitepress/theme/custom.css +++ b/docs/.vitepress/theme/custom.css @@ -253,6 +253,172 @@ body { padding-bottom: 72px; } +.home-product { + display: grid; + grid-template-columns: minmax(250px, 0.72fr) minmax(460px, 1.28fr); + align-items: center; + gap: clamp(36px, 6vw, 76px); + margin: 0 0 14px; + padding: 72px 0 86px; +} + +.home-product__copy h2 { + margin: 0; + border: 0; + padding: 0; + font-size: clamp(2rem, 3.8vw, 3.05rem) !important; + line-height: 1.08 !important; + letter-spacing: -0.055em !important; +} + +.home-product__copy > p:not(.home-section-kicker) { + margin: 20px 0 0; + color: var(--vp-c-text-2); + font-size: 1rem; + line-height: 1.78; +} + +.home-product__copy nav { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 12px 22px; + margin-top: 28px; +} + +.vp-doc .home-product__copy nav a { + color: var(--vp-c-text-2); + font-size: 0.88rem; + font-weight: 750; + text-decoration: none; +} + +.vp-doc .home-product__copy nav a:hover { + color: var(--vp-c-brand-1); + text-decoration: none; +} + +.vp-doc .home-product__copy nav .home-product__primary { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 46px; + border-radius: 11px; + padding: 0 19px; + color: #fff; + background: var(--vp-c-brand-1); + box-shadow: 0 13px 30px rgba(13, 91, 215, 0.2); +} + +.vp-doc .home-product__copy nav .home-product__primary:hover { + color: #fff; + transform: translateY(-1px); +} + +.home-product__visual { + position: relative; + margin: 0; + border-radius: 22px; + padding: 10px; + background: + radial-gradient(circle at 88% 4%, color-mix(in srgb, var(--zd-accent-cyan) 32%, transparent), transparent 34%), + linear-gradient(135deg, color-mix(in srgb, var(--vp-c-brand-1) 86%, #13213a), #151a24 72%); + box-shadow: 0 30px 72px rgba(14, 42, 79, 0.24); + transform: perspective(1300px) rotateY(-3deg) rotateX(1deg); +} + +.home-product__visual::after { + position: absolute; + z-index: -1; + right: 8%; + bottom: -26px; + left: 8%; + height: 52px; + border-radius: 50%; + background: color-mix(in srgb, var(--vp-c-brand-1) 20%, transparent); + filter: blur(26px); + content: ""; +} + +.home-product__visual img { + display: block; + width: 100%; + border-radius: 14px; +} + +.home-product__visual figcaption { + position: absolute; + right: 20px; + bottom: 18px; + border: 1px solid rgba(255, 255, 255, 0.14); + border-radius: 999px; + padding: 5px 10px; + color: rgba(255, 255, 255, 0.7); + background: rgba(9, 12, 18, 0.72); + backdrop-filter: blur(10px); + font-size: 0.68rem; +} + +.product-screenshot, +.download-preview { + margin: 32px 0 38px; + border: 1px solid var(--vp-c-divider); + border-radius: 18px; + padding: 8px; + background: color-mix(in srgb, var(--vp-c-bg-alt) 72%, var(--vp-c-bg-elv)); + box-shadow: var(--zd-shadow-soft); +} + +.product-screenshot img, +.download-preview img { + display: block; + width: 100%; + border-radius: 12px; +} + +.product-screenshot figcaption, +.download-preview figcaption { + padding: 10px 8px 4px; + color: var(--vp-c-text-3); + font-size: 0.75rem; + text-align: center; +} + +.product-screenshot--wide { + width: min(980px, calc(100vw - 48px)); + margin-right: 50%; + margin-left: 50%; + transform: translateX(-50%); +} + +@media (min-width: 960px) { + .VPDoc.has-aside .product-screenshot--wide { + width: min(760px, calc(100vw - 560px)); + } +} + +.download-page .VPDoc .container, +.download-page .VPDoc .content-container { + max-width: 1040px; +} + +.download-page .vp-doc > h1, +.download-page .vp-doc > h1 + p { + max-width: 760px; +} + +.download-page .vp-doc > h1 { + font-size: clamp(2.45rem, 6vw, 4.4rem); + line-height: 1.02; + letter-spacing: -0.06em; +} + +.download-page .vp-doc > h1 + p { + color: var(--vp-c-text-2); + font-size: 1.08rem; + line-height: 1.75; +} + .home-projects .project-catalog { margin-top: 34px; } @@ -703,6 +869,20 @@ body { padding: 58px 0 62px; } + .home-product { + grid-template-columns: minmax(0, 1fr); + gap: 38px; + padding: 54px 0 68px; + } + + .home-product__copy { + max-width: 620px; + } + + .home-product__visual { + transform: none; + } + .home-work-list > div > span { grid-template-columns: minmax(0, 1fr); gap: 5px; diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts index 859ff66..6982f34 100644 --- a/docs/.vitepress/theme/index.ts +++ b/docs/.vitepress/theme/index.ts @@ -1,6 +1,7 @@ import DefaultTheme from 'vitepress/theme' import type { Theme } from 'vitepress' import DiscussionFeed from './components/DiscussionFeed.vue' +import DownloadChooser from './components/DownloadChooser.vue' import ProjectCatalog from './components/ProjectCatalog.vue' import ProjectMeta from './components/ProjectMeta.vue' import Layout from './Layout.vue' @@ -11,6 +12,7 @@ export default { Layout, enhanceApp({ app }) { app.component('DiscussionFeed', DiscussionFeed) + app.component('DownloadChooser', DownloadChooser) app.component('ProjectCatalog', ProjectCatalog) app.component('ProjectMeta', ProjectMeta) }, diff --git a/docs/download.md b/docs/download.md new file mode 100644 index 0000000..86dcb78 --- /dev/null +++ b/docs/download.md @@ -0,0 +1,31 @@ +--- +title: 下载 ZNet Sink +description: 自动识别 Windows、macOS 或 Linux,快速下载最新版 ZNet Sink 桌面客户端。 +aside: false +outline: false +pageClass: download-page +--- + +# 下载 ZNet Sink + +跨平台桌面代理客户端。选择与你的系统和处理器匹配的安装包,安装后即可导入配置或订阅。 + + + +## 安装前确认 + +- Windows 10/11 使用 x86-64 安装程序;日常安装优先选择 EXE。 +- Apple 芯片 Mac 选择 ARM64,Intel Mac 选择 x86-64。 +- macOS 安装包当前未完成 Apple 签名和公证;如果提示应用“已损坏”,请按[macOS 处理步骤](/projects/znet-sink/guides/installation#macos-提示应用-已损坏)移除该应用的隔离标记。 +- Linux 桌面端建议通过终端安装:Ubuntu/Debian 使用 DEB,Fedora/RHEL 系使用 RPM;AppImage 需要先执行 `chmod +x`。完整命令见[Linux 安装说明](/projects/znet-sink/guides/installation#linux-通过终端安装或运行)。 + +安装完成后,继续阅读 [安装与首次启动](/projects/znet-sink/guides/installation) 和 [完成第一次连接](/projects/znet-sink/guides/first-connection)。 + + + + 实机截图 · 专业模式的 DNS 与 Fake-IP 设置 + + +::: tip 下载来源 +所有安装包均来自 ZeroDeNet 官方 GitHub Releases。不要从第三方站点下载二次打包程序。 +::: diff --git a/docs/index.md b/docs/index.md index 3e322cd..340f0b1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -8,13 +8,29 @@ hero: tagline: ZeroDeNet 维护 Zero Core、ZNet Sink 和 Zboard,分别用于网络运行时、桌面代理和服务运营。 actions: - theme: brand - text: 查看项目 - link: /projects/ + text: 下载客户端 + link: /download - theme: alt - text: 使用场景 - link: /solutions/ + text: 浏览项目文档 + link: /projects/ --- + + + DESKTOP CLIENT + 从桌面开始,连接更直观 + ZNet Sink 把节点、规则、系统代理、TUN 与诊断集中在一个清晰的工作台中。简约模式专注日常连接,专业模式保留完整控制能力。 + + 为当前设备下载 ↓ + 查看客户端文档 → + + + + + 实机截图 · 专业模式 + + + PROJECTS 项目 diff --git a/docs/progress.md b/docs/progress.md new file mode 100644 index 0000000..8acf710 --- /dev/null +++ b/docs/progress.md @@ -0,0 +1,59 @@ +# 实现与文档进度 + +本页记录截至 **2026-09-09** 的主分支实现、公开发布和文档覆盖范围。三个产品仓库的正式主分支均为 `main`,没有 `master`;下列链接固定到本轮读取的提交,不包含 develop、功能分支或未提交改动。 + +## 版本术语 + +三个产品当前统一使用 **0.0.1**。安装示例、功能说明和兼容性判断均以此为产品版本基线,不沿用重置前的编号与门槛。 + +- **产品版本**:Zero Core、ZNet Sink、Zboard 均为 `0.0.1`;Git tag、下载路径和镜像标签按实际发布使用 `v0.0.1`。 +- **源码分支与构建**:`main`、`develop` 是分支名称,提交 SHA 用于定位实现;发布渠道与构建标识不替代产品版本。 +- **协议与数据格式**:`zero.api.v1`、`zero.event.v1`、配置 `schema_version: 1`、客户端设置 `v2` 和 ZRS `0.1` 各自表示独立契约,保持原有值。 + +## 核对基线 + +| 项目 | main 源码快照 | 已公开正式版 | 本轮文档重点 | +| --- | --- | --- | --- | +| Zero Core | [50322956](https://github.com/zerodenet/core/tree/503229562ef5854e3be6be3a9c8e7cbc5efffc61) | [0.0.1](https://github.com/zerodenet/core/releases/tag/v0.0.1) | 管理模式、直连例外、Direct UDP、配置校验与探测语义 | +| ZNet Sink | [6d822fb](https://github.com/zerodenet/znet-sink/tree/6d822fb96140be87cdccdd0bea472ba0b089cf04) | [0.0.1](https://github.com/zerodenet/znet-sink/releases/tag/v0.0.1) | 统一绕过、设置迁移、内核生命周期与版本切换 | +| Zboard | [e1b7246](https://github.com/zerodenet/zboard/tree/e1b7246cc4ef805bf39b22d634ba209114eb3b14) | [0.0.1](https://github.com/zerodenet/zboard/releases/tag/v0.0.1) | 前置转发、共享代理池、可靠发布、订单分配与资源清理 | + +Release 已于本轮查询确认公开且非预发布。源码快照说明实现范围;下载后的实际能力仍以制品版本、构建特性和运行时响应为准。源码存在、自动化测试存在、安装验收通过是三个不同结论。 + +## Zero Core + +| 已实现能力 | 对使用者的实际作用 | 使用说明与源码依据 | +| --- | --- | --- | +| 无入站的管理模式 | 未导入代理配置时仍可通过 IPC 管理;首次添加监听失败后可修正重试 | [热更新](/projects/core/guides/hot-reload);[管理模式契约与测试入口](https://github.com/zerodenet/core/blob/503229562ef5854e3be6be3a9c8e7cbc5efffc61/docs/project/management-idle.md) | +| `route.bypass` / `route_bypass_v1` | 直连例外优先于规则和全局模式,内网访问可保留系统路径 | [运行模式](/projects/core/configuration/modes-and-groups);[路由实现](https://github.com/zerodenet/core/blob/503229562ef5854e3be6be3a9c8e7cbc5efffc61/crates/engine/src/runtime/route.rs) | +| Direct TCP/UDP 入站 | 固定目标端口转发继续经过既有路由、策略与流量统计 | [配置示例](/projects/core/protocols/configuration);[监听实现](https://github.com/zerodenet/core/blob/503229562ef5854e3be6be3a9c8e7cbc5efffc61/crates/proxy/src/adapters/direct/inbound.rs) | +| 校验与运行状态隔离 | `zero validate` 不争用运行内核的 Fake-IP 持久化租约,可先校验再升级 | [热更新](/projects/core/guides/hot-reload);[校验边界](https://github.com/zerodenet/core/blob/503229562ef5854e3be6be3a9c8e7cbc5efffc61/docs/project/config-validation-isolation.md) | +| URLTest 与单节点诊断分离 | 手动诊断可以测试隔离中的节点,但不替代策略测速或清除隔离 | [探测语义](/projects/core/guides/proxy-and-urltest);[选择与健康规则](https://github.com/zerodenet/core/blob/503229562ef5854e3be6be3a9c8e7cbc5efffc61/docs/project/urltest-selection.md) | + +TUN、DNS/Fake-IP 和多协议能力已提供配置与控制接口;具体协议方向、传输及跨平台限制仍应读取[能力矩阵](/projects/core/reference/protocol-capabilities)。源码中的 [TUN/Fake-IP 路线](https://github.com/zerodenet/core/blob/503229562ef5854e3be6be3a9c8e7cbc5efffc61/docs/project/tun-fakeip-roadmap.md)包含后续验收目标,不能据此把所有平台防漏、网络切换和进程路由标为完成。 + +## ZNet Sink + +| 已实现能力 | 对使用者的实际作用 | 使用说明与源码依据 | +| --- | --- | --- | +| 网络设置中的统一绕过策略 | 一次维护本地网络、IP/CIDR 和域名例外,生成系统代理、TUN 与内核路由设置 | [统一绕过](/projects/znet-sink/guides/proxy-and-probes#统一绕过规则);[策略投影](https://github.com/zerodenet/znet-sink/blob/6d822fb96140be87cdccdd0bea472ba0b089cf04/src-tauri/src/services/bypass.rs) | +| 可移植设置 v2 | 导出 DNS、TUN 和绕过偏好,导入旧设置时迁移,避免静默丢失域名例外 | [设置迁移](/projects/znet-sink/guides/settings-transfer);[导入实现](https://github.com/zerodenet/znet-sink/blob/6d822fb96140be87cdccdd0bea472ba0b089cf04/src-tauri/src/services/kernel_settings.rs) | +| 受管内核启动与恢复 | 无代理配置时保留管理入口;启动确认健康 IPC,升级失败进入恢复路径 | [功能总览](/projects/znet-sink/guides/features);[内核接入与恢复](https://github.com/zerodenet/znet-sink/blob/6d822fb96140be87cdccdd0bea472ba0b089cf04/docs/gui/core.md) | + +0.0.1 已发布 Windows x86_64、macOS Intel/Apple Silicon 和 Linux x86_64 安装包。该版本的[发布记录](https://github.com/zerodenet/znet-sink/blob/6d822fb96140be87cdccdd0bea472ba0b089cf04/docs/releases/v0.0.1.md)明确保留四个平台安装运行验收的豁免:DNS 与接管模式组合、升级中断恢复、退出清理及跨资源故障注入等仍待补验。不能把发布成功写成这些场景已经安装验收通过。 + +## Zboard + +| 已实现能力 | 对运营者的实际作用 | 使用说明与源码依据 | +| --- | --- | --- | +| 前置转发与节点共享代理池 | 在协议服务中管理 A 到 B 的 TCP/UDP 路径,多入口共用代理池 | [协议服务](/projects/zboard/guides/protocol-services);[前置交付实现](https://github.com/zerodenet/zboard/blob/e1b7246cc4ef805bf39b22d634ba209114eb3b14/backend/internal/handler/network_entry_delivery.go) | +| 持久化节点发布队列 | 权益变更与发布请求一同落库;失败和服务重启后继续重试 | [节点发布](/projects/zboard/guides/node-management);[工作线程](https://github.com/zerodenet/zboard/blob/e1b7246cc4ef805bf39b22d634ba209114eb3b14/backend/internal/handler/node_publish_worker.go) | +| 管理员分配订单 | 为指定用户创建待付款订单、调整应付金额并保留原因,确认后开通权益 | [订单操作](/projects/zboard/guides/plans-and-orders);[分配实现](https://github.com/zerodenet/zboard/blob/e1b7246cc4ef805bf39b22d634ba209114eb3b14/backend/internal/handler/admin_order_assignment.go) | +| 本地删除与独立远端清理 | 节点或供应商不可达时可清理面板记录;远端停机另行执行 | [节点清理](/projects/zboard/guides/node-management#删除节点与远端清理);[删除实现](https://github.com/zerodenet/zboard/blob/e1b7246cc4ef805bf39b22d634ba209114eb3b14/backend/internal/handler/node_delete_cascade.go) | +| 规则集按客户端能力交付 | Clash/sing-box 可保留进程条件,Zero 模板拒绝不支持的规则集 | [规则兼容](/projects/zboard/guides/subscriptions-and-traffic#规则集与客户端兼容性);[兼容检查](https://github.com/zerodenet/zboard/blob/e1b7246cc4ef805bf39b22d634ba209114eb3b14/backend/internal/handler/managed_rule_client_compatibility.go) | + +当前提供用户、节点、订阅、基础订单和流量计量闭环。在线支付集成与插件运行时仍是后续方向,不作为 main 已交付能力;详见[当前范围](https://github.com/zerodenet/zboard/blob/e1b7246cc4ef805bf39b22d634ba209114eb3b14/docs/core-baseline.md)。[0.0.1 发布记录](https://github.com/zerodenet/zboard/blob/e1b7246cc4ef805bf39b22d634ba209114eb3b14/docs/release/v0.0.1.md)也未将 24 小时长稳、500 events/s 突发或完整多节点恢复标为验收完成。 + +## 本轮核对范围 + +本轮读取 main 的配置模型、路由和监听实现、客户端设置与迁移代码、面板处理器和相关测试源码,并同步相关使用页。未运行三个产品的全量测试、安装包或真实节点操作;文档检查与构建结果记录在 [CONTENT_SYNC.md](https://github.com/zerodenet/docs/blob/develop/CONTENT_SYNC.md)。 diff --git a/docs/projects/core/configuration/dns.md b/docs/projects/core/configuration/dns.md new file mode 100644 index 0000000..dc259fe --- /dev/null +++ b/docs/projects/core/configuration/dns.md @@ -0,0 +1,142 @@ +# DNS 参数参考 + +DNS 位于 `runtime.dns`。省略或为 `null` 时使用系统解析器;显式配置后,使用命名服务器和按顺序匹配的分流规则。先用真实 DNS 验证,再按需要启用 Fake-IP。 + +## 可运行的 Real DNS 示例 + +保存为 `dns.json`,先运行 `zero validate dns.json`,再运行 `zero run dns.json`。此例提供本地 Mixed 代理并直连目标,不自动启用 TUN。 + +```json +{ + "schema_version": 1, + "inbounds": [ + { + "tag": "mixed-in", + "listen": { "address": "127.0.0.1", "port": 7890 }, + "protocol": { "type": "mixed" } + } + ], + "outbounds": [], + "route": { "final": { "type": "direct" } }, + "runtime": { + "dns": { + "servers": { + "system": { "type": "system" }, + "secure": { + "type": "doh", + "host": "cloudflare-dns.com", + "bootstrap": ["1.1.1.1", "1.0.0.1"] + } + }, + "default_server": "secure", + "cache": { "max_entries": 1024, "max_ttl_seconds": 300 }, + "answer": { "type": "real" }, + "policy": { + "timeout_ms": 5000, + "fallback_servers": ["system"], + "node_server": "system", + "address_family": "prefer_ipv4" + } + } + } +} +``` + +示例中的公共上游需要从部署网络可达;可替换为自己的解析服务。TUN DNS 劫持处理经过 TUN 的 53 端口查询,配置 DNS 不会自动启动一个供整个局域网使用的 UDP 53 服务。 + +## `runtime.dns` + +| 参数 | 类型 | 默认值 | 作用 | +| --- | --- | --- | --- | +| `servers` | 名称到服务器对象的映射 | 必填 | 至少一台服务器,名称供其他字段引用 | +| `default_server` | string | 必填 | 未命中分流规则时使用的服务器名称 | +| `dispatch` | array | `[]` | 首次命中生效的 DNS 分流规则 | +| `cache` | object / null | `null` | 可选普通 DNS 缓存 | +| `reverse_mapping` | object / null | `null` | 可选真实 IP 到域名的有界索引 | +| `answer` | object | `{"type":"real"}` | 真实地址或 Fake-IP 应答 | +| `policy` | object | 见下表 | 超时、回退、角色解析链及地址族策略 | + +## `servers.<名称>` + +| `type` | 默认端口 | 支持的其他参数 | 使用限制 | +| --- | --- | --- | --- | +| `system` | 无 | 无 | 使用系统解析,TUN 路由准备时发现系统 DNS 地址 | +| `udp` | `53` | `host`、`port`、`bootstrap`、`detour` | 设置 detour 时通过该出站承载 DNS-over-TCP | +| `doh` | `443` | `host`、`port`、`path`、`bootstrap`、`server_name`、`detour` | `path` 默认 `/dns-query` | +| `dot` | `853` | `host`、`port`、`bootstrap`、`server_name`、`detour` | TLS 解析连接 | +| `doq` | `853` | `host`、`port`、`bootstrap`、`server_name` | 当前拒绝 `detour` | + +网络服务器的 `host` 必填,可为 IP 或域名。域名主机必须提供非空 `bootstrap` IP 列表,用来建立到 DNS 服务器本身的连接;它不是另一个待递归解析的域名列表。`server_name` 可覆盖 TLS 校验名称,省略时使用主机名。 + +`detour` 是已定义的出站或出站组 tag;省略时直接连接上游。只要配置了任一 detour,就必须配置 `policy.node_server`,并保证节点解析主服务器和回退服务器均不使用 detour。客户端界面的“跟随默认出站”是客户端选项,不能直接把 `$route_final` 写成内核出站 tag。 + +## `policy` + +| 参数 | 类型 / 范围 | 默认值 | 作用 | +| --- | --- | --- | --- | +| `timeout_ms` | integer,`1–120000` | `5000` | 每个上游的查询期限,毫秒 | +| `server_timeout_ms` | 名称到毫秒值的映射 | `{}` | 单台服务器覆盖,同样为 `1–120000` | +| `fallback_servers` | string[] | `[]` | 普通查询失败后的有序回退链 | +| `node_server` | string / null | `null` | 代理节点和传输端点的解析服务器;省略时按普通分流 | +| `node_fallback_servers` | string[] | `[]` | 节点解析专用回退链,需同时指定 `node_server` | +| `direct_server` | string / null | `null` | 直连目标解析服务器;省略时按普通分流 | +| `direct_fallback_servers` | string[] | `[]` | 直连解析专用回退链,需同时指定 `direct_server` | +| `reject_address_cidrs` | CIDR[] | `[]` | 拒绝含这些真实应答地址的结果,继续回退且不缓存 | +| `address_family` | enum | `prefer_ipv4` | `ipv4_only`、`ipv6_only`、`prefer_ipv4`、`prefer_ipv6` | + +服务器引用必须存在;回退链不能重复引用同一服务器。地址族策略同时约束劫持 DNS 可公布的地址族及内核自行解析时的偏好。它不创建 IPv6 出口,也不提供 NAT64。 + +## `dispatch` + +每条规则由 `condition` 和目标 `server` 组成,按顺序首次命中;不要混用路由动作 `action`。 + +```json +{ + "condition": { "type": "domain", "values": ["internal.example"] }, + "server": "system" +} +``` + +`domain` 同时匹配域名本身及其子域。还支持 `domain_keyword`、`domain_regex`、适用的 `rule_set` 以及 `and` / `or` 组合;引用规则集时需在 `route.rule_sets` 定义对应 tag。DNS 分流不接受 `inbound`、`ip`、`geoip`、`sni` 或纯 CIDR 规则集,因为解析前缺少这些事实。 + +## 缓存与真实地址反向映射 + +| 参数 | 启用对象后的默认值 | 作用 | +| --- | --- | --- | +| `cache.max_entries` | `256` | 普通 DNS 缓存容量,必须大于零 | +| `cache.max_ttl_seconds` | 省略,遵循记录 TTL | 可选 TTL 上限,秒 | +| `reverse_mapping.max_entries` | `1024` | 保留的真实 IP 数量 | +| `reverse_mapping.max_domains_per_address` | `8` | 单个真实 IP 的候选域名上限 | +| `reverse_mapping.max_ttl_seconds` | `300` | 反向映射保留 TTL 上限,秒 | + +省略整个对象表示不启用,不等同于传空对象 `{}`。反向映射容量和 TTL 必须大于零,`max_domains_per_address` 至少为 `2`;同一 IP 对应多个有效域名时属于歧义,不能据此猜测目标域名。缓存中的 wire DNS 应答会随时间递减 TTL。 + +## `answer` 与 Fake-IP + +将 `answer` 改成以下对象,并按 [TUN 使用指南](../guides/tun-and-dns)保证 DNS 和合成地址都进入同一内核: + +```json +{ + "type": "fake_ip", + "cidr": "198.18.0.0/15", + "ipv6_cidr": "fd00::/96", + "ttl_seconds": 86400, + "max_entries": 65536, + "exclude_domains": ["internal.example"] +} +``` + +| 参数 | 默认值 | 作用 | +| --- | --- | --- | +| `type` | `real` | 设为 `fake_ip` 启用合成应答 | +| `cidr` | `198.18.0.0/15` | IPv4 合成池 | +| `ipv6_cidr` | 无 | 可选 IPv6 合成池,用于 AAAA | +| `ttl_seconds` | `86400` | 映射生存期,秒,必须大于零 | +| `max_entries` | 池容量与 `65536` 的较小值 | 活跃映射上限,设置时必须大于零 | +| `exclude_domains` | `[]` | 返回真实 DNS 结果的域名 | + +IPv4 池前缀长度不得大于 `/30`,IPv6 不得大于 `/126`;显式 `max_entries` 不得超过可用池容量,双栈取两池可用容量的较小值。合成池不得与 TUN 自有地址冲突。丢失映射的合成地址会被拒绝,不会直接发往公网;内核也会隔离退役地址,避免旧连接命中新域名。 + +当前内核支持 Fake-IP 持久化和配置回滚时的映射恢复。保留运行用户的状态目录;改运行用户、配置目录或清理状态后,应让应用重新解析 DNS。对普通解析缓存、Fake-IP 映射和客户端自身 DNS 缓存分别排查,不把三者混为一体。 + +`ZERO_DNS_STATE_DIR` 可覆盖 Fake-IP 状态目录。Windows 默认 `%LOCALAPPDATA%\Zero\state`;Unix 优先 `$XDG_STATE_HOME/zero`,否则使用 `~/.local/state/zero`。文件名按配置来源目录身份生成,服务运行用户需有写入权限。它不是 `runtime.dns` 中的 JSON 参数。 diff --git a/docs/projects/core/configuration/index.md b/docs/projects/core/configuration/index.md index 07b157d..33f1f21 100644 --- a/docs/projects/core/configuration/index.md +++ b/docs/projects/core/configuration/index.md @@ -6,6 +6,7 @@ Zero 使用一个完整 JSON 文件描述入站、出站、路由、运行参数 ```json { + "schema_version": 1, "inbounds": [], "outbounds": [ { @@ -32,12 +33,13 @@ Zero 使用一个完整 JSON 文件描述入站、出站、路由、运行参数 | 字段 | 是否必需 | 用途 | |------|----------|------| -| `inbounds` | 是 | 监听地址与入站协议 | -| `outbounds` | 是 | 直连、阻断或代理出站 | +| `schema_version` | 否 | 默认 `1`;只接受支持的版本,导出时显式携带 | +| `inbounds` | 否 | 默认 `[]`;监听地址与入站协议,TUN-only 或仅管理模式均可为空 | +| `outbounds` | 否 | 默认 `[]`;需要引用命名出站时定义 | | `outbound_groups` | 否 | 手动选择、自动测速、故障切换、链式代理或负载均衡 | | `mode` | 否 | `rule`、`direct` 或 `global`;默认 `rule` | -| `route` | 否 | 规则集、匹配规则、URL 改写与默认去向 | -| `runtime` | 否 | DNS、超时、事件日志、网络和状态持久化 | +| `route` | 是 | 规则集、匹配规则、URL 改写与默认去向;明确指定 `final` | +| `runtime` | 否 | DNS、TUN、超时、事件日志、网络和状态持久化 | | `api` | 否 | 控制接口、事件投递、outbox 和 hooks | 未知字段会被拒绝。修改后先运行: @@ -64,15 +66,26 @@ zero validate config.json "tag": "direct", "protocol": { "type": "direct" } } - ] + ], + "route": { "final": { "type": "direct" } } } ``` 协议凭证写在对应协议的原生字段中,例如 VLESS/VMess 的 `id`、Trojan 的 `password`。Connector 不引入另一套用户或凭证模型。 +| 公共参数 | 所在位置 | 默认 / 说明 | +| --- | --- | --- | +| `tag` | 入站、出站 | 必填,供路由与管理引用 | +| `listen.address`、`listen.port` | 入站 | 必填,监听地址与端口 | +| `protocol.type` | 入站、出站 | 必填,协议种类;其他字段按协议选择 | +| `udp.enabled` | 入站、出站 | `true`,还受全局 UDP 策略和协议能力约束 | +| `idle_timeout_secs` | 入站 | 可选 TCP 空闲超时,省略时内核使用 `300` 秒 | + +协议内的服务器地址、认证、TLS 与传输示例见[协议配置](../protocols/configuration)。 + ## 模式与路由 -`rule` 模式先匹配 `route.rules`,未命中时执行 `route.final`: +先检查 `route.bypass` 直连例外;未命中时,`rule` 模式按顺序匹配 `route.rules`,最终回退到 `route.final`: ```json { @@ -108,27 +121,100 @@ zero validate config.json 可用规则、规则集与 ZRS 语法见[规则能力参考](/projects/core/reference/zero-rule-ir-v1)。 +| `route` 参数 | 默认 / 类型 | 说明 | +| --- | --- | --- | +| `final` | 必填 object | 未命中动作:`direct`、`reject` 或 `route`;`route` 需 `outbound` | +| `bypass` | `[]`,条件数组 | 命中即直连,优先于运行模式;复用规则条件,不带 `action` | +| `rules` | `[]` | 每条为 `condition` 与 `action`,顺序匹配 | +| `rule_sets` | `[]` | 共用规则资源,可供流量路由和适用的 DNS 分流引用 | +| `rule_sets[].tag` | 必填 string | 规则集标识 | +| `rule_sets[].type` | 必填 enum | `file` 或 `url` | +| `rule_sets[].path` | 必填 string | 本地文件或远程资源缓存路径 | +| `rule_sets[].url` | 可选 string | `type: "url"` 时必填 | +| `rule_sets[].format` | 必填 enum | `domain_list`、`cidr_list`、`zero_rule_ir`(别名 `zero_ir`)、`zrs` | +| `rule_sets[].update_interval_seconds` | `86400` | 远程更新间隔,秒 | +| `geoip_database` | 无 | 使用 `geoip` 条件时提供 GeoLite2 Country 文件 | +| `url_rewrite` | `[]` | 域名改写列表 | +| `url_rewrite[].from` / `from_regex` | 可选 string | 精确域名或正则匹配,按配置校验选择 | +| `url_rewrite[].to` | 必填 string | 目标域名;正则可使用 `$1` 等捕获 | +| `url_rewrite[].status_code` | 无 | 可选 HTTP 重定向状态码,只对适用的 HTTP 请求有意义 | + +运行模式及各组的参数见[运行模式与出站组](./modes-and-groups)。 + ## runtime 多数部署可以先省略 `runtime`。常用项包括: -| 字段 | 用途 | -|------|------| -| `event_log_capacity` | 内存中保留的事件条数 | -| `udp_upstream_idle_timeout_seconds` | UDP 上游空闲超时 | -| `latency_test_url` | 通用出站延迟探测地址 | -| `dns` | DNS 服务器、缓存、路由与 Fake IP | -| `network.mtu` | 用户态网络栈 MTU | +| 字段 | 类型 / 默认值 | 用途 | +|------|------|------| +| `event_log_capacity` | integer,`1024` | 内存事件重放容量 | +| `udp_upstream_idle_timeout_seconds` | integer,`30` | UDP 上游空闲超时,秒 | +| `latency_test_url` | string / null | 通用出站探测 URL;默认 `http://www.gstatic.com/generate_204` | +| `principal_quota_state_path` | string / null | 可选主体额度崩溃恢复快照路径 | +| `udp.enabled` | bool,`true` | 是否允许 UDP | +| `dns` | object / null | DNS 服务器、缓存、分流和 Fake-IP,详见 [DNS 参数](./dns) | +| `network.mtu` | integer,`1500` | TUN 与用户态网络栈 MTU;可由 TUN 局部值覆盖 | +| `tun` | object / null | 随代理生命周期启停的声明式 TUN 配置 | +| `log.level` | string,`info` | `trace`、`debug`、`info`、`warn`、`error` | +| `log.files` | array,`[]` | 文件输出,省略时输出到 stderr | +| `log.files[].path` | string,必填 | 日志路径 | +| `log.files[].level` | string / null | 单文件日志级别;省略时继承 `log.level` | +| `log.files[].max_bytes` | integer,`10485760` | 单文件轮转大小,字节 | +| `log.files[].max_files` | integer,`5` | 日志文件保留数量 | +| `log.rate_limit.max_per_second` | integer | 可选每秒日志上限,`0` 不限;省略 `rate_limit` 不限流 | 涉及路径的字段以主配置文件所在目录为基准。配置、证书、运行状态和日志建议分开存放。 +### 声明式 TUN + +配置中 `runtime.tun` 为对象时,Zero 会在代理运行期间管理 TUN;省略或为 `null` 时,仍可通过 `tun.start` / `tun.stop` 显式管理。以下是配置片段,完整启动示例见[运行 TUN 与 DNS](../guides/tun-and-dns)。启用 `dns_hijack` 前必须准备有效的 `runtime.dns`。 + +```json +{ + "runtime": { + "network": { + "mtu": 1500 + }, + "tun": { + "addr": "10.66.0.1/24", + "tag": "tun", + "auto_route": true, + "dual_stack": true, + "strict_route": true, + "dns_hijack": true + } + } +} +``` + +| 字段 | 默认值 | 说明 | +|------|--------|------| +| `name` | 系统默认 | 可选 TUN 接口名称 | +| `addr` | — | 主地址;必填 | +| `mask` | `255.255.255.0` | IPv4 掩码 | +| `secondary_addr` | 自动 | 双栈时另一地址族的 CIDR;省略时使用 Zero 的保留 TUN 地址 | +| `mtu` | `runtime.network.mtu` | TUN 局部 MTU 覆盖 | +| `tag` | `tun` | TUN 流量进入 Zero 后使用的 inbound tag | +| `auto_route` | `true` | 自动安装经过 TUN 的 split-default 路由 | +| `include_cidrs` | `[]` | 自动接管的目标 CIDR;空列表表示全量 | +| `exclude_cidrs` | `[]` | 从接管计划中扣除的目标 CIDR,沿用系统路由 | +| `dual_stack` | `true` | 同时准备 IPv4 与 IPv6 路由;明确单栈部署时才建议关闭 | +| `strict_route` | `true` | 自动路由安装失败时终止本次启动并回滚 | +| `dns_hijack` | `true` | 将 TUN 中的 TCP/UDP 53 端口流量交给 Zero DNS | + +自动路由启用后,Zero 会跟踪物理默认出口变化并协调捕获路由。受管 TCP、UDP 与 QUIC 出站使用物理出口避免回环;是否具备某个地址族的实际出口,应查看 TUN 状态。双栈捕获不代表 IPv6 出口或 NAT64 已可用。 + +主地址可使用 IP 或 CIDR,第二地址必须是另一地址族的 CIDR;MTU 范围为 `576–65535`。单栈时不设置第二地址。接管/排除 CIDR 依赖 `auto_route: true`;使用 Fake-IP 时还需接管合成池地址。`strict_route` 除失败回滚外,还使用平台提供的路由/防漏策略;Windows 的严格路由允许 DHCP 客户端流量以支持地址续租。 + +Windows、Linux 和 macOS 的路由实现使用相同的生命周期语义,但创建 TUN、修改路由表仍需要对应平台权限。Windows 官方发布产物会携带运行 TUN 所需的 Wintun 组件;权限或驱动问题见[故障排查](/projects/core/guides/troubleshooting)。 + ## api `api` 中的能力彼此独立: - `control`:HTTP/IPC 控制面的监听与认证。 - `event_sinks`:零到多个事件投递目标;Webhook 地址是接收方提供的完整 URL。 -- `outbox`:Connector 可靠投递、积压与磁盘保护策略。 +- `outbox_path`、`dead_letter_path`、`dispatcher`:可靠投递日志、死信及重试/磁盘保护策略,详见[控制面参数](../control-plane/configuration)。 - `hooks`:事件触发的本地命令。 启用某个 Cargo feature 只代表二进制包含该能力;是否运行仍由配置决定。管理节点时使用 Zero API、IPC 或 gRPC;Connector 只投递事件,不是第二套管理 API。 diff --git a/docs/projects/core/configuration/modes-and-groups.md b/docs/projects/core/configuration/modes-and-groups.md index b81cc17..ffc4625 100644 --- a/docs/projects/core/configuration/modes-and-groups.md +++ b/docs/projects/core/configuration/modes-and-groups.md @@ -2,11 +2,25 @@ 运行模式决定流量按什么方式选择出站,出站组则把多个出站组合成一个可引用目标。 +## 参数速查 + +每组都需唯一 `tag` 和 `type`,成员引用已有出站或组,不能形成循环。 + +| 类型 | 必填参数 | 可选参数与默认值 | +| --- | --- | --- | +| `selector` | `outbounds: string[]` | `selected`、`default`;依次回退到第一个成员 | +| `url_test` | `outbounds: string[]` | `url`;`interval_seconds: 300`;`tolerance_ms: 0` | +| `fallback` | `outbounds: string[]` | 按数组顺序尝试 | +| `relay` | `proxies: string[]` | 至少两跳,需满足逐跳协议能力 | +| `load_balance` | `outbounds: string[]` | `strategy: "round_robin"`,可设 `random`;可选 `default` | + +`tolerance_ms` 是 URLTest 切换容差:当前成员健康时,其他成员必须快出超过此值才切换,可减少延迟接近时的来回切换。它的单位是毫秒,不是测速超时。 + ## 三种运行模式 ### rule -按 `route.rules` 顺序匹配,未命中时执行 `route.final`: +未命中 `route.bypass` 时,按 `route.rules` 顺序匹配,再回退到 `route.final`: ```json { "mode": { "type": "rule" } } @@ -22,7 +36,7 @@ ### global -所有新连接使用指定出站或出站组: +未命中 `route.bypass` 的新连接使用指定出站或出站组: ```json { @@ -43,6 +57,27 @@ zero mode global proxy 切换影响之后建立的连接,现有连接不会被强行中断。 +## 直连例外:route.bypass + +`route.bypass` 默认空数组,复用现有路由条件;每项直接填写条件,不包装 `condition` 或 `action`。命中后直接访问目标,优先于 `rule` 和 `global` 模式: + +```json +{ + "route": { + "bypass": [ + { "type": "ip", "values": ["192.168.0.0/16"] }, + { "type": "domain", "values": ["intranet.example.com"] } + ], + "rules": [], + "final": { "type": "direct" } + } +} +``` + +控制器写入前检查 `route_bypass_v1` 能力。IP 条件可使用可信解析结果,在全局模式或普通域名规则已命中时仍有优先权;域名例外需要可观察的目标域名,不能从加密 DNS/ECH 的裸 IP 流量猜测名称。 + +这是内核路由决策,不会自行改写系统路由。客户端可另行将 IP 网段投影到 TUN 排除列表,并协调操作系统代理例外。 + ## selector:手动选择 ```json diff --git a/docs/projects/core/control-plane/breaking-changes.md b/docs/projects/core/control-plane/breaking-changes.md index 56d75d6..de2a7fa 100644 --- a/docs/projects/core/control-plane/breaking-changes.md +++ b/docs/projects/core/control-plane/breaking-changes.md @@ -1,184 +1,68 @@ -# 控制面兼容性与破坏性变更 +# 控制面兼容性与版本约定 -本文记录会影响 GUI、SDK、面板、事件 Sink 或进程内 Rust 集成的控制面语义变化。当前事实仍以同目录下的接口与事件文档为准;本文只维护版本边界和迁移要求。 +Zero Core、ZNet Sink 和 Zboard 的产品版本统一为 **0.0.1**,Git Release tag 使用 `v0.0.1`。本页以 0.0.1 为当前基线,说明 GUI、SDK、面板、事件 Sink 和进程内 Rust 集成需要遵守的契约。 -## 消费者如何判断兼容性 - -外部消费者连接内核后应依次检查: - -1. `health.engine_build_id`,确定实际运行的内核版本; -2. `capabilities.api_id` 和 `capabilities.schema_id`,确定请求与事件信封版本; -3. `capabilities.features`、`build_features` 和协议矩阵,确定当前构建实际启用的能力; -4. 本文对应版本的语义变更,再决定是否启用兼容分支。 - -兼容性标识的含义: - -| 标识 | 当前值 | 何时必须变化 | -|------|--------|--------------| -| `api_id` | `zero.api.v1` | 请求、响应信封或既有字段出现不兼容 wire 变化 | -| `schema_id` | `zero.event.v1` | 事件信封或既有事件字段出现不兼容 wire 变化 | -| `engine_build_id` | Cargo 包版本 | wire 兼容但行为、时序或恢复语义发生变化 | - -新增可选字段、未知事件类型和新增 capability 通常保持向前兼容;消费者必须忽略不认识的可选字段和事件。改变 ACK 时序、快照含义、增量合并规则、重放范围或既有字段含义,即使 JSON 形状不变,也必须在本文登记。 - -## 版本矩阵 - -| 版本 | 影响面 | 迁移结论 | -|------|--------|----------| -| `Unreleased` | - | No pending compatibility changes | -| `0.0.15` | - | No pending compatibility changes | -| `0.0.15-rc.4` | - | No pending compatibility changes | -| `0.0.15-rc.3` | Diagnostics API 消费者、Connector 运维与事件 Sink | `diagnostics.trace_route` 改为执行真实会话路由追踪;Connector 对事实事件施加有界内存与可选 outbox 背压,采样事件改为仅 best-effort 且不持久化;默认重试次数由 3 调整为 10 | -| `0.0.15-rc.2` | 构建脚本、事件消费者、Webhook 接收端 | 公开 Cargo feature 改用 kebab-case;引擎生成的 `event_id` 增加每次启动唯一的随机 epoch;开发期固定中心 API 被撤销,Connector 收缩为通用 Webhook 事件投递;认证项速率改为 Zero 主体策略聚合 | -| `0.0.15-rc.1` | 进程内 Rust `EventSource`、事件 Sink | Rust 实现者必须迁移到实时 `EventStream`;IPC/HTTP/gRPC GUI wire 无变化 | -| `0.0.15-rc` | GUI flow 生命周期 | 订阅 ACK 后以 `flow.snapshot` 建立活动连接基线,再合并 flow 增量 | - -## Unreleased - - - -## 0.0.15 - - - -## 0.0.15-rc.4 - - - -## 0.0.15-rc.3 - -### Diagnostics 路由追踪使用真实会话语义 - -`diagnostics.trace_route` 现在构造 TCP 或 UDP 会话并复用代理运行时的路由追踪路径。域名规则没有直接命中且路由需要解析 IP 时,会通过真实 DNS 解析结果再次匹配 IP 规则。响应中的 `effective_mode`、`route_action` 和 `matched_rule` 因此反映实际运行时决策,不再使用简化推断。依赖旧诊断结果的控制端应以新结果为准。 - -### Connector backlog 改为有界工作集 - -Connector 不再让慢速或失联 Sink 导致进程内待投递队列无界增长: - -- 配置 outbox 时,事实事件先写入持久化 journal,内存只保留有界工作集,其余记录按空位从磁盘分页恢复; -- 未配置 outbox 时,事实事件通过停止继续消费事件源施加背压,不会静默丢弃; -- `flow.updated` 与 `stats.sampled` 是可丢弃采样,只做 best-effort 投递、不会写入 outbox;工作集已满时优先替换同一 Sink 的旧采样,不驱逐事实事件; -- `api.dispatcher.max_in_memory_deliveries = 0` 表示 outbox-only 模式,因此必须同时配置 `api.outbox_path`; -- `max_retry_attempts` 默认值由 `3` 调整为 `10`,显式配置不受影响。 - -事件 Sink 不应把吞吐采样当作可靠事实流;需要恢复保证的消费者应使用事实事件并配置 outbox。 +## 0.0.1 配置与能力基线 -## 0.0.15-rc.2 +- 配置支持 `schema_version: 1`;未知版本拒绝,缺省按 V1。 +- DNS 使用命名 `servers`、`default_server`、`dispatch`、`policy` 和 `answer`;Fake-IP 位于 `answer.type: "fake_ip"`。配置方式见 [DNS 参数](../configuration/dns)。 +- 能力响应通过 `contracts` 报告独立兼容范围,权限不足使用 `insufficient_os_privilege` 错误码,见[通用契约](./contract)。 +- TUN 状态报告实际捕获范围、地址族出口及配置归属;IPC 失败不能解释为关闭。详见 [HTTP TUN 状态](./http-api#get-api-v1-tun-status)。 +- Connector 状态区分投递和 ACK 重试阶段,见[投递调度](./connector#查看投递调度与恢复状态)。 +- `route.bypass` 写入前检查 `route_bypass_v1`;[直连例外](../configuration/modes-and-groups#直连例外-route-bypass)优先于全局和规则模式。 +- Direct 入站支持 UDP,部署时检查对应构建能力;仅需 TCP 时显式设置 `udp.enabled: false`。 -### 撤销开发期固定中心 API +这些能力统一归入 0.0.1,不沿用编号重置前的发布矩阵或最低版本门槛。源码与安装验收范围见[实现进度](/progress)。 -项目尚未发布 Connector 合同,因此开发期的节点注册、同步、traffic、presence、访问配置和私有命令设计直接撤销,不保留兼容层。 - -已移除顶层 `push`、`PushConfig`、`/api/v1/nodes/{node_id}/*`、中心 OpenAPI、conformance 和 production gate。外部控制器通过 Zero API/gRPC 管理节点,并使用 `config.apply` 注册通用 `api.event_sinks`。Connector 只向完整 Webhook URL 推送 `zero.event.v1`,并定义 HTTP 状态确认分类。 - -### 公开 Cargo feature 改用 kebab-case - -构建入口不再暴露下划线式能力名。构建脚本、CI 和制品 feature 校验需要完成以下迁移: - -| 旧名称 | 新名称 | -| --- | --- | -| `status_api` | `status-api` | -| `event_dispatcher` | `event-dispatcher` | -| `sink_jsonl` | `sink-jsonl` | -| `panel_connector` | `connector` | -| `grpc_api` | `grpc-api` | - -Rust 函数、模块和变量仍按语言规范使用 `snake_case`;本次变化只影响 Cargo feature 名称和二进制对外报告的 feature 字符串。历史候选证据保留其原始名称,不得重写后冒充新候选。 - -### 引擎生成事件使用跨启动唯一 ID - -旧事件 ID 仅由事件类型、进程内 flow ID/序号和毫秒时间戳组成。进程快速重启后这些值可能复用,使 Connector 接收端或 Sink 把新事实误判为已处理事件。 - -新语义: - -- 每个 `EngineEventLog` 创建时生成一个 128 位随机 epoch; -- 所有引擎内部生成的事件 ID 均以前述 epoch 限定,在同一进程内重放时保持不变; -- 通过进程内 `emit()` 注入、由调用者拥有 ID 的外部事件保持原 ID; -- `event_id` 的内部拼接形式不是公共契约,消费者只能比较完整字符串并用于幂等去重。 - -该变化不修改 `zero.event.v1` 的 JSON 字段形状,但修正了跨进程启动的唯一性语义。任何依赖旧 `{type}:{flow_id}:{timestamp}` 格式解析的消费者必须删除该解析逻辑,改用 `event_type`、`payload.record.flow_id` 和 `occurred_at_unix_ms` 等正式字段。 - -### 用户速率改为 Zero 主体策略聚合 - -开发态预资格期间,`up_bps` / `down_bps` 曾被描述并执行为单条 TCP/UDP flow 的限制。该语义允许同一主体通过增加并发连接绕过带宽策略,不满足 Zero 主体策略的定义。 - -新语义: - -- 同一 `principal_key`、`policy_revision` 和双向速率组成一个 Zero 主体策略身份; -- 该身份下的并发 TCP/UDP 会话共享上传、下载 GCRA 时间线; -- revision 或速率变化建立新时间线,旧会话在确认式清退前继续持有旧策略; -- 没有 `principal_key` 的入站默认限速仍按会话独立执行。 - -JSON 字段形状和当时的 `zero.panel.v1` schema ID 不变。该修正发生在首个清洁 release candidate 和正式生产签字之前;历史开发态 manifest 只能证明当时的每流实现,不得继续作为当前候选产物证据。接收端无需修改 wire payload,但容量规划和限速验收必须改为并发 TCP/UDP 聚合测试。 - -## 0.0.15-rc.1 - -### `EventSource` 统一为实时订阅 - -旧语义存在两个不同实现: - -- `Engine::subscribe()` 返回一次性的 `Vec` 历史快照; -- `EngineHandle::subscribe()` 返回实时 `EventSubscriber`。 +## 消费者如何判断兼容性 -新语义: +连接内核后依次检查: -- 所有 `EventSource::subscribe()` 都返回实现 `EventStream` 的实时订阅; -- `latest(limit, filter)` 只用于读取近期历史; -- `since(sequence, limit, filter)` 用于按事件序号恢复,返回 `requested_after`、`actual_from` 和 `has_gap`; -- `has_gap = true` 时,消费者不得直接继续套用增量,必须先通过快照或 Query 重建状态; -- 包含 flow 生命周期的实时订阅仍可在增量前发送合成的 `flow.snapshot`。 +1. `health.engine_build_id`,确认实际运行的构建; +2. `capabilities.api_id` 和 `capabilities.schema_id`,确认请求与事件信封; +3. `contracts` 中的兼容区间,以及 `features`、构建特性和协议能力矩阵; +4. 实际使用的协议方向、传输、权限和 `limitations`。 -进程内 Rust 实现者需要: +同为 0.0.1 的构建仍可能裁剪不同能力,不能仅凭产品版本号启用功能。 -1. 将 `type Stream = Vec` 替换为实现 `EventStream` 的实时流; -2. 实现阻塞 `recv()` 和非阻塞 `try_recv()`; -3. 实现新的 `EventSource::since()` 游标恢复方法; -4. 不再把 `subscribe()` 当作历史查询使用。 +| 标识 | 当前含义 | 与产品版本的关系 | +| --- | --- | --- | +| `api_id: zero.api.v1` | 控制面请求与响应信封 | 独立契约版本 | +| `schema_id: zero.event.v1` | 事件信封 | 独立契约版本 | +| `schema_version: 1` | 配置结构版本 | 独立配置版本 | +| `engine_build_id` | 实际内核构建标识 | 用于定位运行构建,结合能力响应判断兼容性 | -### EventDispatcher 投递时序 +新增可选字段、事件类型和 capability 通常保持向前兼容;消费者应容忍未知可选字段与事件。产品版本重置不改变这些协议标识。 -EventDispatcher 从周期性事件环扫描改为持有一个实时订阅: +## 事件订阅与恢复 -- dispatcher 不再反复把历史快照当作新事件扫描;实时订阅仍按配置的轮询间隔排空并投递到 Sink; -- `flow.snapshot` 仍只用于实时客户端同步,不投递到 JSONL/Webhook; -- Webhook、重试、死信和 Sink 过滤语义保持不变; -- 外部 Sink 应继续使用 `event_id` 去重,并按 `source_id + sequence` 检测缺口。 +包含 flow 生命周期事件的实时订阅,在订阅确认后先用 `flow.snapshot` 建立活动连接基线: -### 对外 GUI 影响 +1. 用 `payload.records` 替换当前活动连接集合并记录 `watermark`; +2. 按 `flow_id + revision` 合并 `flow.started`、`flow.routed`、`flow.updated`; +3. 收到 `flow.completed` 后移除活动连接,使用其自包含的 `payload.record` 记录完成事实; +4. 发现事件缺口时,通过快照或 Query 重建状态,不直接继续套用增量。 -IPC、HTTP SSE 和 gRPC 的 wire 格式保持 `zero.api.v1` / `zero.event.v1`,现有 GUI 不需要因本次待发布变更修改帧解析。GUI 仍需遵守 `0.0.15-rc` 建立的快照与增量合并规则。 +`flow.snapshot` 不进入事件环,也不投递到 JSONL/Webhook;`recent_flows` 不替代断线重建或长期历史数据库。完整字段与通道行为见[事件目录](./events)。 -## `0.0.15-rc` +进程内 `EventSource::subscribe()` 返回实现 `EventStream` 的实时订阅;`latest()` 用于近期历史,`since()` 用于游标恢复。`has_gap = true` 时应重新建立基线。 -### Flow 订阅改为“基线 + 增量” +引擎生成的事件 ID 使用启动时随机 epoch 保持跨启动唯一;重放保持原 ID。外部消费者把 `event_id` 当作不透明字符串进行幂等去重,使用正式字段读取事件类型、flow ID 和时间,不解析 ID 的内部拼接格式。 -包含任一 flow 生命周期事件的 IPC/SSE/CLI 实时订阅,在订阅确认后先收到 `flow.snapshot`: +## Connector 与控制端边界 -1. 使用 `payload.records` **替换**当前活动连接集合; -2. 记录快照 `watermark`; -3. 按 `flow_id + revision` 合并后续 `flow.started`、`flow.routed`、`flow.updated`; -4. 收到 `flow.completed` 后从活动集合移除,并由 GUI 自行保存需要展示的历史; -5. 不把 `recent_flows` 当作断线重建或长期历史数据库。 +0.0.1 使用通用 Webhook 事件投递。控制器通过 Zero API/gRPC 管理节点,并通过 `config.apply` 注册 `api.event_sinks`;Connector 向完整 URL 发送 `zero.event.v1`,按 HTTP 确认规则处理重试和恢复。 -`flow.snapshot` 是同步基线,不进入事件环,也不会投递到 JSONL/Webhook。`flow.completed.payload.record` 是自包含完成事实,新客户端应优先解析 `record`,同时容忍旧内核没有该字段。 +Connector 不提供节点注册、套餐、支付、订阅或中心私有命令 API。配置不能使用开发期的顶层 `push` 或固定中心协议。 -### GUI 兼容分支建议 +事实事件使用有界工作集,配置 outbox 时持久化并按空位恢复;`flow.updated`、`stats.sampled` 是可丢弃采样,不作为可靠账务事实。重试和背压参数以当前 [Connector 配置](./connector)为准。 -| 内核版本 | GUI 行为 | -|----------|----------| -| `< 0.0.15-rc` | 使用 `active_flows` 查询作为活动连接基线,并兼容旧 flow payload | -| `>= 0.0.15-rc` | 等待 subscribe ACK 和 `flow.snapshot`,之后按 revision 合并增量 | +## 构建与主体策略 -## 新增条目的要求 +公开 Cargo feature 使用 `status-api`、`event-dispatcher`、`sink-jsonl`、`connector`、`grpc-api` 等名称。Rust 函数和模块仍使用 `snake_case`;完整选项见[构建特性](../configuration/features)。 -后续每个破坏性或语义性变更必须在发布前补充: +同一主体策略下的并发 TCP/UDP 会话共享双向速率控制;不能把主体限速理解为每条连接都各自获得完整额度。没有 `principal_key` 的入站默认限速仍按会话执行。验收主体限速时应覆盖并发连接。 -- 首个受影响版本; -- 影响的通道和消费者; -- 旧语义与新语义; -- wire 标识是否变化; -- 兼容窗口和可检测条件; -- GUI/SDK/面板的明确迁移步骤; -- 对应回归测试位置。 +## 后续文档维护 -开发期间只在版本矩阵和 `## Unreleased` 下登记,不预判最终发布版本,也不写入 Cargo 的 `-dev.N` 构建号。完整测试通过后,由 `Prepare Release` 工作流或 `scripts/release.sh` 将矩阵行、章节标题和 workspace 版本一起封板;禁止手工分别修改这些位置。 +后续兼容性变更应根据实际发布记录注明产品版本、影响的通道、契约标识、可检测条件和操作步骤,并附实现与测试依据。未发布实现使用提交标识说明范围,不推测发行编号;功能可用性始终结合实际构建能力判断。 diff --git a/docs/projects/core/control-plane/cli.md b/docs/projects/core/control-plane/cli.md index 37b829f..866199d 100644 --- a/docs/projects/core/control-plane/cli.md +++ b/docs/projects/core/control-plane/cli.md @@ -16,7 +16,20 @@ zero version zero build-info ``` -`validate` 无副作用。`build-info` 用于确认当前发行物包含的协议和可选能力。 +`validate` 不启动监听或 TUN,也不占用运行内核的 Fake-IP 租约或修复配额状态;完整边界见[配置校验](../guides/hot-reload#校验与运行状态隔离)。`build-info` 用于确认当前发行物包含的协议和可选能力。 + +| 参数 / 命令 | 取值与作用 | +| --- | --- | +| `run CONFIG` | 必填配置路径,启动前解析及验证 | +| `run --status-listen HOST:PORT` | 显式 HTTP 控制监听;不要与配置内已启用的控制监听同时指定 | +| `run --control-socket PATH` | 指定本地控制 IPC 地址 | +| `run --ipc-hook-socket PATH` | 可选外部 IPC hook socket,供已有 hook 接收端使用 | +| `status --json` | JSON 状态输出;可附配置路径或 `--socket` | +| `--socket PATH` | 客户端命令连接的 Unix socket / Windows 命名管道 | +| `validate CONFIG` | 校验完整配置,不启动监听、TUN 或业务连接 | +| `build-info` / `version` / `-V` / `--version` | 查看构建信息 | + +不指定 socket 时,Unix 默认 `~/.zero/control.sock`,Windows 默认 `\\.\pipe\zero-control`。管理多个实例时始终明确指定地址。 ## 连接运行中的进程 @@ -76,13 +89,32 @@ zero connector state --json config.json ```bash zero tun start --addr 10.0.0.1 --tag my-tun zero tun start --addr 10.0.0.1 --tag my-tun \ - --name tun0 --mask 255.255.255.0 --mtu 1500 + --name tun0 --mask 255.255.255.0 --mtu 1500 \ + --exclude-cidr 192.168.50.0/24 zero tun status zero tun stop ``` TUN 命令同样可以使用 `--socket PATH` 连接指定实例。 +| 参数 | 默认值 | 说明 | +| --- | --- | --- | +| `--addr IP或CIDR` | 必填 | 主地址 | +| `--tag TAG` | 必填 | 流量入站标识;CLI 不自动补 `tun` | +| `--name NAME` | 系统选择 | 网卡名称 | +| `--mask MASK` | `255.255.255.0` | 主地址掩码 | +| `--secondary-addr CIDR` | 自动选择另一族地址 | 仅双栈使用 | +| `--mtu MTU` | `runtime.network.mtu` | `576–65535` | +| `--include-cidr CIDR` | 全量 | 可重复,指定接管范围 | +| `--exclude-cidr CIDR` | 无 | 可重复,从接管范围扣除 | +| `--no-auto-route` | 不传则自动路由 | 禁用自动路由后不可依赖 CIDR 参数安装路由 | +| `--single-stack` | 不传则双栈 | 单栈模式,不传第二地址 | +| `--no-strict-route` | 不传则严格路由 | 显式关闭严格路由策略 | +| `--no-dns-hijack` | 不传则劫持 | 没有有效 DNS 配置时显式关闭;不会接管加密应用 DNS | +| `--socket PATH` | 平台默认 | 目标内核实例 | + +先启动 Zero 进程再执行 TUN 命令。默认启用 DNS 劫持,要求活动配置已有有效 DNS;完整示例及验证步骤见[运行 TUN 与 DNS](../guides/tun-and-dns)。命令超时后先查询状态,避免对未确认结果重复启停。 + ## 常见用法 部署前: diff --git a/docs/projects/core/control-plane/configuration.md b/docs/projects/core/control-plane/configuration.md index 64ed456..b968416 100644 --- a/docs/projects/core/control-plane/configuration.md +++ b/docs/projects/core/control-plane/configuration.md @@ -36,7 +36,7 @@ "dispatcher": { "max_in_memory_deliveries": 4096, "replay_batch_size": 4096, - "max_retry_attempts": 3, + "max_retry_attempts": 10, "retry_initial_delay_ms": 4000, "retry_max_delay_ms": 64000, "webhook_timeout_ms": 10000, @@ -141,7 +141,7 @@ Flow 生命周期钩子,按数组顺序执行。 |------|--------|------| | `max_in_memory_deliveries` | `4096` | 活跃内存工作集;其余持久 delivery 留在 outbox | | `replay_batch_size` | `4096` | 每轮从 engine event log 补偿 live queue 断档的最大事件数 | -| `max_retry_attempts` | `3` | 首次投递失败后最多重试次数 | +| `max_retry_attempts` | `10` | 首次投递后的重试阈值;达到后应用耗尽策略,默认仍继续重试 | | `retry_initial_delay_ms` | `4000` | 首次退避 | | `retry_max_delay_ms` | `64000` | 指数退避上限 | | `webhook_timeout_ms` | `10000` | 单次 Webhook 请求超时 | @@ -149,7 +149,7 @@ Flow 生命周期钩子,按数组顺序执行。 | `outbox_min_free_percent` | `5` | outbox 所在文件系统必须保留的可用空间比例 | | `exhausted_delivery_policy` | `retry_forever` | `retry_forever`、`dead_letter` 或 `discard` | -所有数值必须大于零,且初始退避不得大于退避上限;`outbox_min_free_percent` 必须在 1–50 之间。磁盘保护的有效水位取绝对值与文件系统总容量比例中的较大值。达到水位后,dispatcher 暂停新的 outbox PUT,不推进对应事件游标;已有 delivery 的投递、ACK 和压缩可以使用保留空间继续排空,但仍会保留有效水位 25%(至少 64 MiB、且不超过有效水位)的紧急维护空间。`GET /api/v1/sinks` 的 `outbox_storage` 会报告总容量、可用空间、有效保留水位、紧急维护水位和 `write_blocked` 状态。 +`max_in_memory_deliveries` 可为 `0`,表示 outbox-only,必须同时配置 `outbox_path`;其他数值须符合校验要求,初始退避不得大于退避上限;`outbox_min_free_percent` 必须在 1–50 之间。磁盘保护的有效水位取绝对值与文件系统总容量比例中的较大值。达到水位后,dispatcher 暂停新的 outbox PUT,不推进对应事件游标;已有 delivery 的投递、ACK 和压缩可以使用保留空间继续排空,但仍会保留有效水位 25%(至少 64 MiB、且不超过有效水位)的紧急维护空间。`GET /api/v1/sinks` 的 `outbox_storage` 会报告总容量、可用空间、有效保留水位、紧急维护水位和 `write_blocked` 状态。 `dead_letter` 策略要求同时配置 `api.dead_letter_path`。默认 `retry_forever` 会在达到阈值后继续按有界退避重试,不会隐式确认或删除可重试事件。 diff --git a/docs/projects/core/control-plane/connector.md b/docs/projects/core/control-plane/connector.md index a0e3526..faa7237 100644 --- a/docs/projects/core/control-plane/connector.md +++ b/docs/projects/core/control-plane/connector.md @@ -108,3 +108,19 @@ outbox 不使用固定容量上限。每次新增持久记录前,Connector 都 限流、停用、升级、通知等策略和工作流由外部系统决定。需要内核改变运行状态时,外部系统调用已有的 Zero HTTP/IPC/gRPC 通用方法或应用配置;程序升级由部署系统执行。Connector 不接收、不解释这些业务命令,也不维护面板状态。 Connector 只补充节点向已注册接收端可靠推送事件的能力。它的“保活”是节点内投递循环、重试/outbox 恢复和 sink 状态,不是要求中心实现固定心跳端点。外部系统需要活性信号时,可订阅适合的周期事件(例如启用统计采样后的 `stats.sampled`),并自行定义超时判断。 + +## 查看投递调度与恢复状态 + +通过 `GET /api/v1/sinks` 读取每个 sink 的 `pending`、`delivery`、`outbox_storage` 和 `outbox_recovery`。`delivery` 在空闲时可能省略,旧内核也可能没有该字段: + +| 字段 | 说明 | +| --- | --- | +| `delivery.in_flight` | 当前 worker 正持有一次投递请求 | +| `delivery.retry_pending` | 已失败、等待再次投递的数量 | +| `delivery.ack_retry_pending` | 已发布成功、但本地持久 ACK 仍待重试的数量 | +| `delivery.durable_pending` | outbox 持有的未完成数量 | +| `delivery.next_retry_at_unix_ms` | 下一次发布或 ACK 重试期限 | + +这些数量描述不同生命周期阶段,可能重叠,不能相加得到总积压。`ack_retry_pending` 不等于接收端尚未收到;接收端仍必须幂等处理。发生持久文件恢复问题时,结合 `outbox_recovery` 和 `replay_gaps` 对账;后续发送成功不代表历史缺口已经补齐。 + +启用 TUN 时,Webhook 受管连接使用物理出口。排查投递失败应同时检查接收 URL、HTTP 状态、重试时间、磁盘水位和出口网络,不能用“没有业务流量”判断接收端在线状态。 diff --git a/docs/projects/core/control-plane/contract.md b/docs/projects/core/control-plane/contract.md index 84e0699..bafed1d 100644 --- a/docs/projects/core/control-plane/contract.md +++ b/docs/projects/core/control-plane/contract.md @@ -77,6 +77,16 @@ HTTP 和 IPC 响应使用 `zero_api::ApiResponse`。 能力发现是描述性的。它不授予额外权限,也不暴露外部系统特定的业务概念。 +### V1 契约版本 + +当前能力响应增加 `contracts`,分别报告 `capabilities`、`control_api`、`config_schema` 和 `error_codes` 的 `current` 与 `minimum_supported`。客户端支持区间与内核区间相交时才启用对应能力;旧响应没有此字段时视为版本未知,不能默认当作 V1。 + +完整配置顶层 `schema_version` 默认为 `1`,内核导出时显式携带。未知版本在构造运行资源前拒绝,不通过删除字段静默降级。 + +`features` 提供正向能力,`global_limitations` 提供跨协议限制,协议局部限制在 `protocols[].limitations`。未知能力和限制条目可忽略;已知限制消失也应结合正向能力判断。TUN 双栈、系统 DNS 自动发现、Fake-IP 持久化及 DNS 地址族策略均应按实际能力启用。 + +V1 是公开契约版本,与发行编号独立。当前已公开 0.0.1,具体构建与安装验收范围见[实现进度](/progress)。DNS/TUN 的使用及限制见[运行 TUN 与 DNS](../guides/tun-and-dns)。 + ## 错误处理 错误码是 `snake_case` 的稳定机器字符串。 @@ -86,6 +96,7 @@ HTTP 和 IPC 响应使用 `zero_api::ApiResponse`。 | `not_found` | 请求的资源不存在 | | `invalid_argument` | 请求格式或字段值无效 | | `permission_denied` | 调用者缺少所需权限 | +| `insufficient_os_privilege` | 操作系统权限不足,例如创建 TUN 或修改路由 | | `feature_disabled` | 功能在当前构建/运行时中未启用 | | `conflict` | 当前状态拒绝该操作 | | `unsupported` | 操作不在当前控制面范围内 | diff --git a/docs/projects/core/control-plane/http-api.md b/docs/projects/core/control-plane/http-api.md index f1994f7..ffb8873 100644 --- a/docs/projects/core/control-plane/http-api.md +++ b/docs/projects/core/control-plane/http-api.md @@ -69,6 +69,7 @@ HTTP 和 IPC 共享相同的响应信封格式(定义在 `zero_api::ApiRespons | `not_found` | 404 | 资源不存在 | | `invalid_argument` | 400 | 参数无效 | | `permission_denied` | 403 | 权限不足 | +| `insufficient_os_privilege` | 403 | 操作系统权限不足,例如创建 TUN 或修改路由 | | `feature_disabled` | 501 | 功能未编译 | | `conflict` | 409 | 状态冲突 | | `unsupported` | 501 | 不支持的操作 | @@ -80,7 +81,7 @@ HTTP 和 IPC 共享相同的响应信封格式(定义在 `zero_api::ApiRespons ### GET /api/v1/capabilities -API 能力列表。 +API 能力列表。当前响应还包含独立版本范围 `contracts`、稳定 `error_codes` 和 `global_limitations`。按[通用契约](./contract#v1-契约版本)匹配版本与功能,不能仅凭构建版本推断能力;下例只展示部分字段。 ```json { @@ -293,6 +294,22 @@ TUN 虚拟网卡运行状态。 | `addr` | 网卡地址(运行时返回) | | `tag` | 入站 tag(运行时返回) | +当前状态还包含以下运行事实;可选字段及空 CIDR 列表可能省略: + +| 字段 | 说明 | +| --- | --- | +| `addresses`、`mtu` | 实际生效的全部接口地址及 MTU | +| `healthy`、`last_error` | 健康状态与最后错误 | +| `auto_route`、`include_cidrs`、`exclude_cidrs` | 自动路由及捕获范围 | +| `dual_stack`、`strict_route`、`dns_hijack` | 实际启用的接管策略 | +| `egress_interface`、`egress_interface_v4`、`egress_interface_v6` | 物理出口接口 | +| `ipv4_egress`、`ipv6_egress` | 含 `availability`(`unknown` / `available` / `unavailable`)、可选 `interface` 和 `reason` | +| `network_generation` | 网络出口状态代次 | +| `address_family_policy`、`ipv6_to_ipv4_fallbacks` | 地址族策略及 IPv6 到 IPv4 回退计数 | +| `managed_by_config` | 是否由声明式配置管理 | + +查询失败表示无法确认状态,不应构造 `running: false`。缺少新字段的旧响应也不能用于确认新参数已应用。 + 未启动时所有字段为零值 / null: ```json { "running": false, "name": null, "addr": null, "tag": null } @@ -468,7 +485,7 @@ Response: #### tun.start -启动 TUN 虚拟网卡。 +启动 TUN 虚拟网卡。还支持 `secondary_addr`(另一地址族 CIDR,可选)、`include_cidrs` / `exclude_cidrs`(string[],默认 `[]`)和 `auto_route`、`dual_stack`、`strict_route`、`dns_hijack`(bool,默认均为 `true`)。参数约束见[声明式 TUN](../configuration/#声明式-tun)。劫持需要有效 DNS 配置;结束后查询 `tun_status` 核对实际状态,超时不代表命令未执行。 Params:`name` (string, 可选), `addr` (string), `mask` (string, 可选, 默认 `"255.255.255.0"`), `mtu` (number, 可选;省略时使用 `runtime.network.mtu`,其默认值为 1500), `tag` (string) @@ -623,7 +640,7 @@ Response(列表模式): #### diagnostics.fakeip_lookup -查询 Fake IP 映射(`runtime.dns.fake_ip`)。`domain` 与 `ip` 二选一: +查询 Fake-IP 映射(`runtime.dns.answer.type: "fake_ip"`)。`domain` 与 `ip` 二选一;查询已有映射,不分配新地址: - `domain`:前向查询(域名 → 已分配的 Fake IP,**不分配**新 IP)。 - `ip`:反向查询(Fake IP → 真实域名)。 @@ -640,6 +657,10 @@ Response(反向): `fake_ip` / `domain` 为 `null` 表示无映射;`enabled: false` 表示未配置 Fake IP。两者都省略返回 `invalid_argument`。 +#### fakeip.clear + +清理 Fake-IP 映射,同时更新持久状态。权限为 `admin`。`params` 使用 `domain` 或 `ip` 二选一清理指定映射,空对象 `{}` 清空全部,不能同时设置两项。应用可能仍缓存旧合成地址,清理后需要重新解析;不要将它用作普通 DNS 缓存刷新。 + 权限:`admin` #### diagnostics.trace_route diff --git a/docs/projects/core/control-plane/ipc-protocol.md b/docs/projects/core/control-plane/ipc-protocol.md index e75846f..0c18b1f 100644 --- a/docs/projects/core/control-plane/ipc-protocol.md +++ b/docs/projects/core/control-plane/ipc-protocol.md @@ -85,11 +85,14 @@ | `config.apply` | `config` (完整 JSON) | 持久化并等待 proxy 与进程级服务热重建;失败回滚 | | `config.apply_runtime` | `config` (完整 JSON) | 不写回源文件,并等待 proxy 与进程级服务热重建;失败回滚 | | `mode.set` | `mode`, `outbound?` | 设置全局模式 | -| `tun.start` | `name?`, `addr`, `mask?`, `mtu?`, `tag` | 启动 TUN | +| `tun.start` | `addr`, `tag`, `name?`, `mask?`, `secondary_addr?`, `mtu?`, `include_cidrs?`, `exclude_cidrs?`, `auto_route?`, `dual_stack?`, `strict_route?`, `dns_hijack?` | 启动 TUN,约束见 [HTTP 命令](./http-api#tun-start) | | `tun.stop` | — | 停止 TUN | | `diagnostics.probe_target` | `target_tag` | 直连 TCP 可达性(不走代理,仅本机→server:port RTT) | | `diagnostics.probe_outbound` | `target_tag`, `url?` | 同步经代理单节点延迟;全局 `runtime.latency_test_url` 优先 | | `diagnostics.dns_lookup` | `hostname` | DNS 查询 | +| `diagnostics.dns_cache` | `domain?`, `limit?` | 查询普通 DNS 缓存 | +| `diagnostics.fakeip_lookup` | `domain` 或 `ip` | 查询已有 Fake-IP 映射 | +| `fakeip.clear` | `domain?` 或 `ip?`;均省略清空全部 | 清理 Fake-IP 映射与持久状态 | | `diagnostics.trace_route` | `target`, `port`, `protocol?`, `inbound_tag?` | 路由追踪 | > **实现说明:** IPC Command 和 HTTP `POST /api/v1/commands` 共用同一条 serde 反序列化路径(`CommandRequest` 的 `#[serde(tag = "method", content = "params")]`)。新增 command 只需修改 `zero_api::CommandRequest`,传输层无需单独适配。 @@ -170,7 +173,7 @@ IPC 响应使用统一信封格式(`zero_api::ApiResponse`),包含 `api_id | `QueryRequest::Policy` | `"policy"` | `{tag, kind, outbounds, selected, ...}` | | `QueryRequest::Diagnostics` | `"diagnostics"` | `{healthy, active_sessions, ...}` | | `QueryRequest::Sinks` | `"sinks"` | `{sinks: [{name, pending, total_delivered, total_failed, replay_gaps, ...}]}` | -| `QueryRequest::TunStatus` | `"tun_status"` | `{running, name, addr, tag}` | +| `QueryRequest::TunStatus` | `"tun_status"` | 实际参数、地址族出口、健康及配置归属,见 [TUN 状态](./http-api#get-api-v1-tun-status) | > **注意:** 这是 IPC 通道的格式。HTTP 通道的 `result` 字段**不包含**变体名 key——直接就是内部数据。例如 HTTP `GET /api/v1/health` 返回 `result: {"engine_build_id":"build-id",...}`,而 IPC 返回 `result: {"health":{"engine_build_id":"build-id",...}}`。 diff --git a/docs/projects/core/guides/configuration-basics.md b/docs/projects/core/guides/configuration-basics.md index bbcd6a9..b5e0f8e 100644 --- a/docs/projects/core/guides/configuration-basics.md +++ b/docs/projects/core/guides/configuration-basics.md @@ -8,6 +8,7 @@ Zero 使用 JSON 配置。推荐从一个能够通过 `zero validate` 的完整 | 字段 | 用途 | |------|------| +| `schema_version` | 配置契约版本;省略按 `1`,未知版本会拒绝 | | `inbounds` | Zero 在哪里接收连接,以及使用什么入站协议 | | `outbounds` | 直连、阻断或远程代理节点 | | `outbound_groups` | selector、url_test、fallback、relay 和负载均衡 | @@ -108,3 +109,5 @@ zero status --json `reload` 提交完整候选配置,不是局部补丁。成功响应会等待监听器和相关应用服务完成重建;失败时会尝试恢复上一份运行配置。控制接口自身的监听地址和凭证不能在线自替换,需要显式重启。 详细流程见[安全热更新配置](./hot-reload),所有字段见[配置参考](/projects/core/configuration/)。 + +需要 DNS 分流或 Fake-IP 时使用[命名服务器参数](../configuration/dns),不要沿用旧的 `runtime.dns.fake_ip` 形状;应配置 `runtime.dns.answer.type: "fake_ip"`。透明代理的安装、网段接管与验证见[运行 TUN 与 DNS](./tun-and-dns)。 diff --git a/docs/projects/core/guides/control-api.md b/docs/projects/core/guides/control-api.md index e4c99a4..e7a882a 100644 --- a/docs/projects/core/guides/control-api.md +++ b/docs/projects/core/guides/control-api.md @@ -98,6 +98,8 @@ curl \ - `config.validate` - `config.apply` - `config.apply_runtime` +- `tun.start` +- `tun.stop` - `diagnostics.probe_target` - `diagnostics.probe_outbound` @@ -135,6 +137,39 @@ curl \ 不要由多个独立写入者各自基于旧副本修改整份配置。Zero 会串行执行本地 apply 并在重建失败时回滚,但当前命令合同没有对外提供 revision/CAS 字段;写入协调属于控制端职责。 +## 显式管理 TUN + +没有在配置中声明 `runtime.tun` 时,GUI 或守护程序可以使用 `tun.start` 和 `tun.stop` 管理 TUN 生命周期。Zero Core 0.0.1 的 `tun.start` 支持完整的自动路由与双栈参数: + +```json +{ + "method": "tun.start", + "params": { + "addr": "10.66.0.1/24", + "tag": "tun", + "mtu": 1500, + "secondary_addr": "fd66::1/64", + "auto_route": true, + "dual_stack": true, + "strict_route": true, + "dns_hijack": true + } +} +``` + +`name`、`mtu` 和 `secondary_addr` 可以省略;`mask` 默认是 `255.255.255.0`。`auto_route`、`dual_stack`、`strict_route` 和 `dns_hijack` 默认都为 `true`。省略 `mtu` 时继承活动配置中的 `runtime.network.mtu`。 + +停止 TUN 时,命令仍然使用标准的对象参数。不要发送 `null` 或省略 `params`: + +```json +{ + "method": "tun.stop", + "params": {} +} +``` + +这个对象形式同时适用于 HTTP 和 IPC,因为两种传输共用同一套命令反序列化合同。 + ## 使用 CLI 和 IPC 同机操作通常不需要开放 HTTP: diff --git a/docs/projects/core/guides/hot-reload.md b/docs/projects/core/guides/hot-reload.md index 0c0dd9b..adf6b72 100644 --- a/docs/projects/core/guides/hot-reload.md +++ b/docs/projects/core/guides/hot-reload.md @@ -20,6 +20,26 @@ config applied 这表示 Zero 已等待 listener 和相关应用服务完成 reconciliation,不只是接受了请求。 +## 校验与运行状态隔离 + +`zero validate` 检查配置、编译能力、引用资源、DNS 与目标计划,但不构造运行引擎、不获取 Fake-IP 持久化租约、不读取或修复配额状态,也不绑定监听器或启动 TUN。可以在旧内核仍运行时校验候选配置;相对规则文件仍从原配置目录解析。 + +校验通过不保证端口空闲、权限充分、目标可达或旧持久化数据兼容。遇到旧内核校验争用 Fake-IP 租约时,客户端预检可仅为校验子进程使用独立 `ZERO_DNS_STATE_DIR`;不要删除生产进程持有的锁。 + +## 从无入站开始管理 + +`inbounds: []` 且没有 TUN 的配置可以保持管理模式,应用 IPC 继续可用,不会隐式开启 HTTP API 或 TUN: + +```json +{ + "schema_version": 1, + "inbounds": [], + "route": { "final": { "type": "direct" } } +} +``` + +通过 `config.apply` 添加第一个入站后开始提供代理服务;首次绑定失败保留原空配置供重试。删除最后一个入站后回到管理状态。这个状态适合客户端首次启动,不表示已经具备本地代理入口。 + ## HTTP/gRPC 流程 控制端使用同一个完整配置依次调用: diff --git a/docs/projects/core/guides/index.md b/docs/projects/core/guides/index.md index ea763df..31e273a 100644 --- a/docs/projects/core/guides/index.md +++ b/docs/projects/core/guides/index.md @@ -23,3 +23,5 @@ - [GUI 接入](./gui-integration):通过 IPC 或 HTTP 构建本地控制端。 需要查字段时进入[配置参考](/projects/core/configuration/),需要查某个代理协议时进入[协议配置](/projects/core/protocols/)。 + +透明代理场景请阅读 [运行 TUN 与 DNS](./tun-and-dns),配置前核对 [DNS 参数](../configuration/dns)。 diff --git a/docs/projects/core/guides/proxy-and-urltest.md b/docs/projects/core/guides/proxy-and-urltest.md index ca58f66..67f5894 100644 --- a/docs/projects/core/guides/proxy-and-urltest.md +++ b/docs/projects/core/guides/proxy-and-urltest.md @@ -65,6 +65,19 @@ Hysteria2 和 VLESS QUIC 出站的 `server` 可以填写域名。连接时会解 并发上限用于避免大量节点同时建立真实连接造成资源尖峰;它不代表一个组最多只能包含 8 个成员。 +## 自动策略与单节点诊断 + +URLTest 与 `diagnostics.probe_outbound` 共用探测执行器,但不共用结果写入语义: + +- URLTest 遵守已有的流量隔离,并更新该组的成员健康、选择和 `policy.probe.completed`; +- 单节点诊断可以绕过已有隔离进行测试,但不清除或延长流量隔离,也不改变 URLTest 的选择; +- 两种探测不会直接把结果写成通用业务连接的成功或失败; +- 本地 DNS、地址/网络不可用、接口设置失败以及客户端取消,不应作为代理节点故障继续累加隔离。 + +所以手动诊断成功而策略仍显示不可用并不矛盾。排查时同时核对两条路径的 URL、操作类型、策略快照与真实业务连接结果,不能用一次手动成功替代自动健康状态。 + +URLTest 使用 `tolerance_ms` 决定切换:当前成员本轮健康时,只有 `当前延迟 > 最佳延迟 + 容差` 才切换;差值等于容差仍保留当前成员。当前成员不健康时立即选本轮健康候选;全部失败时保留原选择。日志以 `operation_kind=policy_urltest` 和 `diagnostic_outbound` 区分两类探测。 + ## 控制器与 GUI 接入建议 触发策略组测速时,直接请求该 URLTest 组,不要先展开成员并逐一重复测速。一个 URLTest 组作为另一个 selector 的成员时,也应把它视为一个策略目标。 diff --git a/docs/projects/core/guides/troubleshooting.md b/docs/projects/core/guides/troubleshooting.md index fe3ebe6..007ee59 100644 --- a/docs/projects/core/guides/troubleshooting.md +++ b/docs/projects/core/guides/troubleshooting.md @@ -46,6 +46,24 @@ cargo build --release --features connector,grpc-api `config.apply` 失败后先查询状态,确认旧 listener 是否恢复,再提交新的候选配置。 +## TUN 无法启动或启动后断网 + +Zero Core 0.0.1 会自动协调 Windows、Linux 和 macOS 的 TUN 捕获路由,并将代理出站绑定到当前物理 underlay egress。出现问题时先区分“创建 TUN 失败”和“路由已经接管但出口不可用”。 + +依次检查: + +1. 当前进程是否具有创建虚拟网卡和修改系统路由所需的管理员/root 权限; +2. `runtime.tun.addr`、`secondary_addr` 和 MTU 是否有效,双栈主机是否确实需要 `dual_stack: true`; +3. `strict_route: true` 时是否因为任一路由安装失败而主动回滚; +4. 主机物理默认路由是否在 TUN 启动后发生切换,例如 Wi-Fi、有线网络或 VPN 切换; +5. 日志中是否存在 underlay、route reconcile、TUN device 或权限相关错误。 + +Windows 官方发布产物已经携带 Wintun 运行组件。使用官方压缩包时通常不需要另外下载 DLL;如果日志明确提示权限失败,应先以管理员权限运行,而不是把权限错误误判为缺少配置。自行重新打包 Zero 时仍要确认 Wintun 组件被一并分发。 + +macOS 会保留物理出口的 scoped route 语义;Linux/macOS/Windows 都会在默认出口变化后重新协调捕获路由。升级到该版本后不建议继续依赖为每个代理服务器手工添加静态 host route 来避免 TUN 回环。 + +如果通过控制面关闭 TUN,`tun.stop` 必须发送标准空对象参数:`{"method":"tun.stop","params":{}}`。 + ## CLI 找不到运行中的 Zero CLI 默认连接: @@ -91,6 +109,8 @@ zero status --socket /run/zero/control.sock 5. UDP 请求是否使用了当前协议支持的路径; 6. 中继链中的每一跳是否可达。 +如果只有经 HTTP forward proxy 的明文 HTTP 请求异常,而 HTTPS CONNECT 正常,先确认使用 Zero Core 0.0.1 的完整构建,并核对 HTTP 请求解析和转发日志。仍可稳定复现时,保留原始请求边界、构建信息和 flow 日志报告问题。 + 先使用[快速开始](./quickstart)的本地 direct 配置确认入站正常,再逐步加入真实代理出站。 ## Connector 一直积压 diff --git a/docs/projects/core/guides/tun-and-dns.md b/docs/projects/core/guides/tun-and-dns.md new file mode 100644 index 0000000..95172df --- /dev/null +++ b/docs/projects/core/guides/tun-and-dns.md @@ -0,0 +1,89 @@ +# 运行 TUN 与 DNS + +先确认 `zero build-info` 包含所需能力,并具备创建 TUN 和修改路由的权限。Windows 官方发行包包含 Wintun;自行打包时需要保留匹配的运行组件。 + +## 启动一个直连 TUN + +下面是完整配置。它接管流量后直连,用于验证 TUN、路由和 DNS,不包含远程代理节点。 + +```json +{ + "schema_version": 1, + "inbounds": [], + "outbounds": [], + "route": { "final": { "type": "direct" } }, + "runtime": { + "dns": { + "servers": { "system": { "type": "system" } }, + "default_server": "system", + "answer": { "type": "real" }, + "policy": { "address_family": "prefer_ipv4" } + }, + "tun": { + "addr": "10.66.0.1/24", + "tag": "tun", + "auto_route": true, + "dual_stack": true, + "strict_route": true, + "dns_hijack": true + } + } +} +``` + +保存为 `tun.json`,先校验,再以所需权限启动: + +```bash +zero validate tun.json +zero run tun.json +``` + +另一个终端使用同一 IPC 地址读取状态: + +```bash +zero tun status +zero status --json +zero flows +``` + +需要远程代理时,增加协议出站并修改 `route.final`。参数和默认值见[配置参考](../configuration/)与 [DNS 参数](../configuration/dns)。 + +## 确认流量实际进入 TUN + +1. 确认 TUN 状态为运行,查看接口地址、捕获网段及 IPv4/IPv6 出口可用性。 +2. 发起一次新的域名解析和 TCP 请求,并用实际需要的应用验证 UDP。 +3. 在 flow 详情核对 `inbound_tag`、原始目标、域名恢复信息、路由和最终出站。 +4. 如同时开启系统代理,注意请求可能经 Mixed 入站进入内核;用 TUN 入站记录确认本次测试路径。 + +网页打开或节点测速成功,只能证明相应请求成功,不能单独证明 DNS、UDP 和 TUN 都已接管。探测也不替代实际业务连接的流量记录。 + +## 只接管部分网段 + +在 `runtime.tun` 增加以下片段: + +```json +{ + "include_cidrs": ["10.0.0.0/8"], + "exclude_cidrs": ["10.20.0.0/16"] +} +``` + +此例只接管 `10.0.0.0/8` 中除 `10.20.0.0/16` 外的目标;排除网段沿用系统路由。`include_cidrs` 留空表示全量接管,排除列表再从中扣除。两者配置在自动路由范围内,不能在 `auto_route: false` 时依赖其安装路由。 + +启用 Fake-IP 后还必须让合成地址池进入 TUN;只接管一个内网网段的示例不适合直接承载全局 Fake-IP。需要内网域名返回真实地址时配置 `answer.exclude_domains`;DNS 的 `reject_address_cidrs` 是拒绝上游结果,不是 TUN 绕过列表。 + +## 处理地址族与网络变化 + +内核会观察物理默认出口变化,协调 TUN 路由和受管出站。状态中的每个地址族可为 `available`、`unavailable` 或 `unknown`;`unknown` 不能当作已经可用。 + +只有 IPv4 物理出口时,双栈捕获可以处于降级状态;具有可信域名的部分连接可以重新解析到可用地址族。裸 IPv6、缺失映射的合成地址或没有可信域名的目标不会凭空获得 IPv4 地址。直接 UDP 不采用 TCP 的连接失败后猜测换目标逻辑。 + +Windows strict route 包含 DHCP 客户端流量放行,用于地址续租和出口恢复。切换 Wi-Fi、网线或 VPN 后,仍需检查实际地址获取、出口状态、DNS 和 TCP/UDP 恢复。失败时保留首次路由错误及出口诊断,先处理物理网络或权限问题。 + +## 更新与停止 + +修改完整候选配置后,先 `zero validate candidate.json`,再 `zero reload candidate.json`,等待协调完成。网卡和捕获参数变化可能重建 TUN 并中断既有连接;失败时查看错误和当前状态,不反复提交相同命令。 + +省略 `runtime.tun` 的运行实例可用 `zero tun start` / `zero tun stop` 显式管理,命令参数见 [CLI](../control-plane/cli)。停止后用 `zero tun status` 确认,检查系统原路由恢复。不要把 IPC 超时解释为“已经停止”。 + +DNS 劫持只覆盖经过 TUN 的 TCP/UDP 53。应用自带 DoH/DoT/DoQ、ECH 隐藏的主机名以及 NAT64 不因开启 TUN 自动获得支持。 diff --git a/docs/projects/core/index.md b/docs/projects/core/index.md index a309e56..30164aa 100644 --- a/docs/projects/core/index.md +++ b/docs/projects/core/index.md @@ -2,6 +2,10 @@ +::: info 文档对应版本 +本轮使用说明按 2026-09-09 的 [main 提交 50322956](https://github.com/zerodenet/core/tree/503229562ef5854e3be6be3a9c8e7cbc5efffc61)核对。已公开 [0.0.1 正式版](https://github.com/zerodenet/core/releases/tag/v0.0.1);源码、发布与安装验收范围见[实现与文档进度](/progress)。实际能力以所用制品及运行时响应为准。 +::: + Zero Core 是可裁剪的网络代理内核,可作为本地网关、边缘节点或服务器运行,并提供 CLI、HTTP、IPC 等控制接口。 ## 第一次使用 @@ -44,3 +48,7 @@ HTTP、IPC 和 gRPC 调用的是同一组 Zero 查询与命令。Connector 负 - [HTTP API](./control-plane/http-api) - [事件目录](./control-plane/events) - [协议能力矩阵](./reference/protocol-capabilities) + +## DNS 与透明代理 + +先按 [TUN 与 DNS 使用指南](./guides/tun-and-dns)完成启动和验证,再查阅 [DNS 参数](./configuration/dns)、[运行与 TUN 参数](./configuration/)及 [CLI 参数](./control-plane/cli)。 diff --git a/docs/projects/core/protocols/configuration.md b/docs/projects/core/protocols/configuration.md index a73711a..0683dbe 100644 --- a/docs/projects/core/protocols/configuration.md +++ b/docs/projects/core/protocols/configuration.md @@ -361,6 +361,21 @@ Mixed 同时接受 SOCKS5 TCP、SOCKS5 UDP ASSOCIATE 和 HTTP CONNECT。 `direct` 和 `block` 是 Zero 内置动作,不是外部代理协议。 +## Direct 固定目标转发 + +Direct 入站支持原始 TCP,以及具备 `managed-datagram-runtime` 构建能力时的 UDP 转发。它不执行落地代理协议的认证,适合把入口端口转发到既有服务: + +```json +{ + "tag": "entry", + "listen": { "address": "127.0.0.1", "port": 10000 }, + "udp": { "enabled": true }, + "protocol": { "type": "direct", "target": "landing.example.com", "port": 443 } +} +``` + +转发经过既有路由、出站策略和流量生命周期。启用 UDP 时同时绑定该端口的 TCP/UDP;UDP 端口被占用会使绑定失败,不会静默降级。只需 TCP 时显式设置 `udp.enabled: false`。UDP 还受 `runtime.udp.enabled` 全局开关约束;部署前通过 `zero build-info` 确认 `direct.inbound.udp.supported`,仅能解析该字段不代表二进制具备转发能力。 + ## 传输和高级字段 VLESS、VMess 等协议还支持 TLS、REALITY、WebSocket、gRPC、H2、QUIC、HTTP Upgrade、XHTTP、MUX 和 UDP 相关组合。不要仅凭字段存在就任意叠加;组合限制见[完整配置字段](/projects/core/configuration/)和[协议能力矩阵](/projects/core/reference/protocol-capabilities)。 diff --git a/docs/projects/core/reference/index.md b/docs/projects/core/reference/index.md index c7f0749..35932b8 100644 --- a/docs/projects/core/reference/index.md +++ b/docs/projects/core/reference/index.md @@ -8,3 +8,6 @@ - [ZRS Golden Vector](./zrs-0.1-golden) 这些页面描述格式和能力边界,不代表某个具体 Core 构建已经启用所有可选 feature。运行时仍应查询能力信息。 + +- [DNS 与 Fake-IP 参数](../configuration/dns) +- [运行与 TUN 参数](../configuration/) diff --git a/docs/projects/core/reference/protocol-capabilities.md b/docs/projects/core/reference/protocol-capabilities.md index f42cd97..a8ec611 100644 --- a/docs/projects/core/reference/protocol-capabilities.md +++ b/docs/projects/core/reference/protocol-capabilities.md @@ -42,7 +42,7 @@ IPC: | 协议 | 总体状态 | 入站 TCP | 入站 UDP | 出站 TCP | 出站 UDP | MUX | |------|----------|----------|----------|----------|----------|-----| -| `direct` | `supported` | 支持 | 不支持 | 支持 | 支持 | 不适用 | +| `direct` | `supported` | 支持 | 支持(需 UDP 构建能力) | 支持 | 支持 | 不适用 | | `block` | `supported` | 不支持 | 不支持 | 支持 | 支持 | 不适用 | | `socks5` | `supported` | 支持 | 支持 | 支持 | 支持 | 不适用 | | `http` | `supported` | 支持 | 不适用 | 不支持 | 不适用 | 不适用 | diff --git a/docs/projects/index.md b/docs/projects/index.md index bae7699..32ce129 100644 --- a/docs/projects/index.md +++ b/docs/projects/index.md @@ -3,3 +3,5 @@ ZeroDeNet 当前维护以下项目。 + +[查看实现与文档进度](/progress):按三个项目 main 的源码快照核对已实现能力、正式发布与待验收范围。 diff --git a/docs/projects/zboard/guides/announcements-and-email.md b/docs/projects/zboard/guides/announcements-and-email.md new file mode 100644 index 0000000..ea6844f --- /dev/null +++ b/docs/projects/zboard/guides/announcements-and-email.md @@ -0,0 +1,35 @@ +# 公告、注册验证与邮件 + +站点公告用于网页内通知;SMTP 用于验证码和邮件任务。两者分别配置,可以按场景配合使用。 + +## 发布站点公告 + +1. 进入“运营 → 站点公告”,点击“新建公告”。 +2. 填写标题和 Markdown 正文,从用户视角预览检查内容与链接。 +3. 选择级别和受众:所有人、仅访客、登录用户或仅管理员。 +4. 先保存草稿;准备发布时选择“已发布”,设置开始和结束时间。留空分别表示立即生效、长期有效。 +5. 需要首页提醒时勾选弹窗,选择是否允许直接关闭,再点击“保存公告”。 +6. 使用对应受众的页面检查实际展示;尚未到开始时间的公告不会提前显示。 + +正文支持标题、粗体、列表、引用、代码和安全的 HTTP(S) 链接。时间输入以当前浏览器本地时间填写,保存时转换为绝对时间。 + +首页提醒最多加载最新 5 条当前有效公告。登录用户可在“公告中心”查看历史与已读状态;关闭或点击“我知道了”会确认阅读。关闭“允许直接关闭”后仍可通过“我知道了”收起。 + +到期公告退出提醒区,但保留在公告中心。**归档会立即从用户视图和未读统计中移除**;要保留用户可查的历史,设置结束时间即可。草稿或已归档公告可永久删除,已发布公告应先归档。 + +## 开放注册与邮箱验证 + +1. 打开“设置 → 邮件与运营模板”,配置 SMTP 主机、端口、发件人、TLS 和凭证,保存后确认通道状态。 +2. 进入“设置 → 注册与验证”,设置“允许访客注册”。关闭它不会删除已有账号或影响已有用户登录。 +3. 需要验证邮箱时启用“注册时验证邮箱”;SMTP 未就绪时先修复邮件配置。 +4. 在访客注册页确认验证码发送、收取和注册结果。 + +邮箱验证码为六位、10 分钟有效,并受重发冷却、尝试次数和网络频率限制。当前图形验证码入口尚未接入,不能当作已经启用的防护功能。 + +## 欢迎通知与运营邮件 + +“注册与验证”中的“注册成功通知”管理唯一的注册触发模板。启用后,注册成功会创建可重试的欢迎邮件任务;停用欢迎模板不影响注册前的验证码。 + +运营邮件模板在“邮件与运营模板”管理。发送后到“运营 → 运营任务”检查任务和收件人的具体结果,再检查实际收件箱。验证码是注册前同步发送,欢迎通知是注册后排队执行,排查时应先区分哪一条链路失败。 + +SMTP 保存成功只说明配置已接受;任务排队成功也不保证最终送达。失败时核对主机、端口、TLS、凭证、发件地址及任务错误,避免反复创建相同通知。 diff --git a/docs/projects/zboard/guides/daily-operations.md b/docs/projects/zboard/guides/daily-operations.md new file mode 100644 index 0000000..a12227d --- /dev/null +++ b/docs/projects/zboard/guides/daily-operations.md @@ -0,0 +1,41 @@ +# 后台导航与日常运营 + +管理后台按六个业务入口组织。先选左侧业务入口,再选具体页面;手机上先展开菜单,进入具体页面后菜单关闭。 + +| 入口 | 常用页面 | 解决什么问题 | +| --- | --- | --- | +| 概览 | 运营工作台 | 查看业务概况和待处理事项 | +| 用户与订阅 | 用户管理、订阅管理、工单中心、Fair Use 观测 | 查找客户、处理服务问题、观察使用情况 | +| 商品与订单 | 商品与套餐、订单管理、订阅模板、规则集 | 配置可销售商品与客户端交付内容 | +| 节点与协议 | 节点资产、协议服务、节点组、流量与对账、外部供应商、DNS 解析、免费证书 | 管理服务资源与发布状态 | +| 运营 | 站点公告、运营任务、运行日志、审计日志 | 发布通知、跟踪任务和追溯操作 | +| 设置 | 站点与品牌、注册与验证、邮件与运营模板、法务与政策、系统运行、系统维护、关于 ZBoard | 管理站点身份、注册、通知和维护 | + +## 开始营业前 + +1. 完成[安装与初始化](./first-setup),在“设置 → 站点与品牌”确认站点名称、公开地址及品牌图片。 +2. 在“法务与政策”填写适合本站的服务条款、隐私和退款等公开内容,并从访客页面检查显示。 +3. 完成[节点接入](./node-management)、协议服务发布、节点组和订阅模板配置。 +4. 在“商品与套餐”配置商品和规格,按[套餐与订单](./plans-and-orders)检查用户的购买及交付流程。 +5. 开放注册前配置邮件与验证方式;发布维护通知时使用[公告与邮件](./announcements-and-email)。 + +保存表单后检查页面反馈和实际结果。节点发布、邮件等操作可能进入任务队列,应继续到“运营 → 运营任务”查看完成、失败及具体任务项,不能只凭点击按钮判断执行成功。 + +## 处理用户连接问题 + +先通过用户邮箱和具体订阅定位服务,再核对订阅状态、有效期、剩余流量、节点组和协议发布状态。一个账号可以持有多份订阅,不要根据另一份订阅的用量或节点判断当前链接是否可用。 + +需要复现时让用户提供客户端及内核版本、错误和时间,避免在工单中公开订阅令牌。按[订阅与流量](./subscriptions-and-traffic)检查交付;按[故障排查](./troubleshooting)检查节点与控制连接。 + +## 使用 Fair Use 观测 + +1. 进入“用户与订阅 → Fair Use 观测”。 +2. 用邮箱、套餐、SKU 或订阅标识搜索并选择具体订阅。 +3. 选择观测范围,查看最近最多 15 天的行为、覆盖情况和趋势。 +4. 数据未采集或覆盖不足时,先检查观测链路,再解释结果。 + +当前 Fair Use 是只读观测和实验分析,不会自动通知、限速、暂停订阅或处罚用户。实验风险评分不能直接等同于违规,也不能用“未采集”推断用户没有连接。 + +## 升级与恢复 + +在“设置 → 关于 ZBoard”确认当前版本及渠道;当前产品版本统一为 0.0.1;发布渠道用于区分构建来源,不能作为另一套版本编号。升级前备份数据库、配置密钥、规则文件和必要的事件存储,保留原镜像及部署配置。涉及数据库切换时按[系统维护与数据库迁移](./maintenance)逐步完成。 diff --git a/docs/projects/zboard/guides/dns-and-certificates.md b/docs/projects/zboard/guides/dns-and-certificates.md index 28cf2fb..8fe378d 100644 --- a/docs/projects/zboard/guides/dns-and-certificates.md +++ b/docs/projects/zboard/guides/dns-and-certificates.md @@ -19,14 +19,9 @@ Zboard 可以通过供应商账号维护节点域名记录,并在节点上签 ## 删除 DNS 记录 -删除操作会先删除 Zboard 保存的那个 Cloudflare record ID,再移除本地期望状态: +删除仅移除面板管理记录,不向 Cloudflare 发起删除请求;供应商上的真实解析会保留。供应商鉴权失败或不可达不会阻止本地记录删除。同一记录有同步操作正在运行时,仍不允许并发删除。 -- 远端删除成功后,删除面板记录; -- 供应商返回 404 时,视为远端已经不存在,可以继续清理本地记录; -- 鉴权、权限或其他供应商错误会保留面板记录,便于修复后重试; -- 同一记录有同步操作正在运行时,不允许并发删除。 - -Zboard 不会按域名模糊删除其他记录。 +如果要撤销公网解析,应在供应商侧明确删除对应记录,再核对实际解析结果。更改资产身份后重新创建时,也要检查旧远端记录是否仍存在,避免把本地重建当作远端迁移完成。 ## 创建证书 @@ -111,9 +106,11 @@ DNS-01 需要供应商账号提供有效的 Cloudflare API Token。Zboard 在节 某些发行版按 Python 次版本提供 venv 包。自动流程会尝试对应的 `pythonX.Y-venv`,随后还有 pip target 回退。仍失败时检查软件源配置和 Python 安装完整性。 -### DNS 删除后面板记录仍存在 +### 删除后远端 DNS 或证书仍存在 + +当前 main 删除 DNS 记录只移除面板管理记录,保留供应商真实解析;删除托管证书移除面板记录、关联和面板自动续期,但保留节点证书、私钥与 Certbot 续期配置,也不会向 CA 撤销证书。供应商或 SSH 不可达不会阻止本地删除。 -查看供应商返回错误。除远端 404 外,鉴权和权限错误会保留本地记录,这是为了避免面板误认为远端资源已经删除。 +退役时应另外核对供应商解析、节点文件及续期任务。不要把面板列表中消失解释成远端资源已清理。正在执行的同步或签发任务仍需先结束,详见[资源清理边界](https://github.com/zerodenet/zboard/blob/e1b7246cc4ef805bf39b22d634ba209114eb3b14/docs/node-cleanup.md)。 ### 证书无法编辑 diff --git a/docs/projects/zboard/guides/first-setup.md b/docs/projects/zboard/guides/first-setup.md index 1c1a051..abee06a 100644 --- a/docs/projects/zboard/guides/first-setup.md +++ b/docs/projects/zboard/guides/first-setup.md @@ -1,22 +1,66 @@ # 首次初始化 -完成部署后,需要初始化管理员、基础配置和节点环境。 +部署 Zboard 后,首次安装向导负责建立站点基础信息、系统级时间/历史策略和第一个管理员账户。首次初始化分为四步,并在最后一次安装事务中一起提交需要持久化的设置。 ## 初始化流程 -1. 创建管理员账户; -2. 配置站点基础信息; -3. 配置节点连接凭证; -4. 验证数据库、缓存和运行环境; -5. 开始添加节点资源。 +1. **环境检查**:确认后端、数据库和前端运行环境可以完成安装; +2. **站点设置**:填写站点名称、公开访问地址和注册策略; +3. **系统策略**:确认系统时区以及审计/运营历史的保留期限; +4. **首个管理员**:创建第一个管理员账户并完成安装。 + +节点、SSH 和 Zero 接入不再属于首次安装向导本身。站点初始化完成后,再进入[节点与协议服务管理](./node-management)接入 VPS。 + +## 系统时区 + +系统策略中的时区使用 IANA 名称,例如: + +```text +Asia/Shanghai +UTC +America/Los_Angeles +``` + +浏览器能够提供 IANA 时区时,向导会用浏览器时区作为预填值;无法识别时回退到 `UTC`。`UTC+8` 这类固定偏移写法不是有效配置,应改用对应的 IANA 区域名称。 + +Zboard 数据库和 API 继续保存绝对时间,不会因为修改系统时区而重写历史记录。系统时区影响管理界面的时间展示,并作为业务日历型读取的边界:例如 Dashboard 的“今天”、7 天/30 天区间、流量趋势的日期过滤和每日 bucket 都按系统当地日历计算,再转换成 UTC 查询。 + +夏令时地区会按真实日历处理 23/25 小时日;这不会改变底层 UTC 时间事实。 + +## 历史保留策略 + +首次安装可以确认以下默认值: + +| 设置 | 默认值 | 作用 | +|------|--------|------| +| 审计日志保留天数 | `180` | 清理超过期限的审计日志 | +| 运行历史保留天数 | `90` | 清理已结束的节点、协议发布、证书和供应商等运营历史 | +| 运营任务保留天数 | `90` | 清理已完成的任务及任务项 | + +保留天数允许 `0–3650`: + +- `0` 表示永久保留; +- 只有已经结束的任务/操作会进入自动清理; +- 流量计费记录、额度事件、订单、订阅和支付历史等业务/账务事实不受这组运营历史清理策略影响。 + +清理工作会随后端生命周期运行。安装完成后,这些值仍可在系统设置中修改。 + +## 安装事务 + +站点设置、系统策略和首个管理员在同一次安装事务中提交。任一部分校验或写入失败时,不应留下“站点已安装但管理员/策略缺失”的半初始化状态。 + +为兼容旧安装客户端,新增的系统策略字段在 API 层保持可选;未提供时由服务端采用默认值。 ## 安全建议 - 管理员密码使用高强度随机密码; -- SSH 凭证使用最小权限; -- 不在日志中记录明文凭证; -- 定期轮换外部服务密钥。 +- 站点公开地址使用 HTTPS,并在安装后确认反向代理和 Cookie/认证行为正常; +- IANA 时区选择应以实际业务日历语义为准,不要为了“看起来是本地时间”随意修改; +- 历史保留策略需要同时考虑排障周期、审计要求和数据库规模; +- SSH、云厂商和 DNS 凭证在后续节点/基础设施接入时使用最小权限,并避免写入日志。 ## 下一步 -继续阅读[节点与协议服务管理](./node-management)。 +完成初始化后,继续阅读[节点与协议服务管理](./node-management)。 + +熟悉新后台入口请阅读[后台导航与日常运营](./daily-operations)。开放注册、邮箱验证及欢迎通知见[公告、注册验证与邮件](./announcements-and-email)。 diff --git a/docs/projects/zboard/guides/index.md b/docs/projects/zboard/guides/index.md index f8a5232..8f66b17 100644 --- a/docs/projects/zboard/guides/index.md +++ b/docs/projects/zboard/guides/index.md @@ -13,3 +13,10 @@ 7. [故障排查](./troubleshooting) 节点资产、协议服务、订阅模板和证书是独立资源。先完成节点接入,再按实际业务启用协议、订阅和基础设施自动化能力。 + +## 日常运营专题 + +- [后台导航与日常运营](./daily-operations) +- [套餐、订单与用户交付](./plans-and-orders) +- [公告、注册验证与邮件](./announcements-and-email) +- [系统维护与数据库迁移](./maintenance) diff --git a/docs/projects/zboard/guides/installation.md b/docs/projects/zboard/guides/installation.md index 0b8435b..c879a23 100644 --- a/docs/projects/zboard/guides/installation.md +++ b/docs/projects/zboard/guides/installation.md @@ -1,46 +1,75 @@ # 安装与部署 -Zboard 推荐使用 Docker Compose 部署。生产部署需要准备 MySQL 8、Redis 和外部 Docker 网络。 +Zboard 支持 MySQL 和 SQLite。使用仓库中的 Docker Compose 发布配置部署,并固定镜像标签;当前产品版本为 0.0.1,部署时仍需核对制品构建和所需能力。 -具体镜像标签、Compose 文件和环境变量示例以对应版本的 Zboard 发布包为准,不要在生产环境使用浮动的 `latest` 标签。 +当前已提供 [0.0.1 正式发布](https://github.com/zerodenet/zboard/releases/tag/v0.0.1),包含 Linux amd64 二进制、Docker 镜像离线包与 SHA256SUMS;镜像为 `ghcr.io/zerodenet/zboard:v0.0.1`。同名标签重建后需重新拉取镜像并重建容器,仅重启已有容器不会替换镜像。升级前备份数据库、配置与持久目录。 -## 前置条件 +## 准备运行环境 -- Docker Engine -- Docker Compose v2 -- MySQL 8 数据库 -- Redis 服务 +需要 Docker Engine、Compose v2,以及发布配置使用的外部 Docker 网络。MySQL 方案准备可访问的 MySQL 8 数据库;SQLite 方案准备可写的持久目录。当前发布 Compose 不要求部署 Redis。 -## 配置环境变量 +取得与所选发布匹配的部署文件,进入 `deploy/docker`,创建自己的 `.env.release`。此文件包含凭证,不提交到公开仓库。 -至少需要配置: +## 填写部署参数 -- `ZBOARD_DATA_SOURCE`:MySQL 连接地址; -- `ZBOARD_REDIS_ADDR`:Redis 地址; -- `ZBOARD_JWT_SECRET`:登录令牌密钥; -- `ZBOARD_CREDENTIAL_ENCRYPTION_KEY`:凭证加密密钥。 +| 变量 | 默认 / 是否必填 | 如何填写 | +| --- | --- | --- | +| `ZBOARD_IMAGE_TAG` | 必填 | 发布页上的固定标签 | +| `ZBOARD_IMAGE_REPOSITORY` | `ghcr.io/zerodenet/zboard` | 镜像仓库 | +| `ZBOARD_EXTERNAL_NETWORK` | 必填 | 已存在的外部 Docker 网络名称 | +| `ZBOARD_DATABASE_DRIVER` | `mysql` | `mysql` 或 `sqlite` | +| `ZBOARD_DATA_SOURCE` | 必填 | MySQL 完整 DSN 或 SQLite 容器内文件路径 | +| `ZBOARD_JWT_SECRET` | 必填 | 足够强的登录令牌密钥 | +| `ZBOARD_CREDENTIAL_ENCRYPTION_KEY` | 必填 | 符合应用校验要求的凭证加密密钥,需备份 | +| `ZBOARD_HTTP_BIND` | `127.0.0.1` | 对宿主机开放的监听地址 | +| `ZBOARD_HTTP_PORT` | `8080` | 宿主机端口 | +| `ZBOARD_DATABASE_HOST_DIR` | `./data` | SQLite 宿主机持久目录,需配合 SQLite override | +| `ZBOARD_ZERO_ARTIFACT_HOST_DIR` | `./artifacts` | 受信任 Zero 制品,只读挂载 | +| `ZBOARD_MANAGED_RULE_HOST_DIR` | `./managed-rules` | 托管规则与编译产物,可写挂载 | +| `ZBOARD_ZERO_EVENT_SPOOL_HOST_DIR` | `./zero-events` | 节点事件暂存文件,可写持久目录 | +| `ZBOARD_DATABASE_MAX_OPEN_CONNECTIONS` | `8` | MySQL 连接池上限;SQLite 固定为 `1` | +| `ZBOARD_DATABASE_MAX_IDLE_CONNECTIONS` | `2` | MySQL 空闲连接上限;SQLite 固定为 `1` | +| `ZBOARD_DATABASE_CONNECTION_MAX_LIFETIME_SECONDS` | `3600` | 连接最长寿命,秒 | -## 启动服务 +MySQL 的 DSN 形式为 `user:password@tcp(db:3306)/zboard?charset=utf8mb4&parseTime=True&loc=UTC`,替换账号、密码、数据库和地址。SQLite 使用 `/var/lib/zboard/data/zboard.db`,这是容器内路径,不是宿主机目录。 -准备环境变量后启动: +## 准备目录并启动 + +以下命令从 `deploy/docker` 执行,`.env.release` 需使用可被 shell 读取的赋值语法。先准备外部网络和持久目录: ```bash -docker compose up -d +set -a +. ./.env.release +set +a +sh ./prepare-host-dirs.sh ``` -启动后检查健康状态: +MySQL 使用发布文件: -```text -GET /readyz +```bash +docker compose -f docker-compose.release.yml --env-file .env.release up -d ``` -首次访问管理地址时,根据引导完成管理员初始化。 +SQLite 同时加载数据目录 override: + +```bash +docker compose -f docker-compose.release.yml -f docker-compose.sqlite.yml \ + --env-file .env.release up -d +``` + +后续检查、停止和重建时使用相同的 Compose 文件组合及环境文件。通过反向代理提供 HTTPS;默认宿主机 loopback 绑定适合同机反向代理,需要跨容器或跨主机访问时按部署网络调整。 + +## 验证安装 + +1. 使用同一 Compose 组合运行 `ps`,检查 zboard 容器健康。 +2. 请求 `http://127.0.0.1:8080/readyz`,确认就绪和数据库连接;修改端口时同步修改地址。 +3. 访问站点,完成[首次初始化](./first-setup)。 +4. 核对管理员登录、站点公开地址和当前驱动,再接入节点。 + +首次启动由后端建立和检查数据库结构,不手工插入迁移记录。已有数据要改数据库驱动时,使用[系统维护与数据库迁移](./maintenance),不要仅更改连接地址。 -## 部署建议 +## 持久化与升级 -- 使用反向代理处理公网 HTTPS; -- 不直接暴露管理接口到公网; -- 定期备份数据库和凭证加密密钥; -- 升级前保留当前镜像和数据库备份。 +数据库、凭证加密密钥、托管规则和事件存储共同组成恢复所需资料。受信任 Zero 制品目录保持只读,托管规则目录单独可写;不要为解决规则写入问题把所有制品改为可写。 -下一步阅读[首次初始化](./first-setup)。 +SQLite 备份应取得一致快照,或停止应用后备份完整数据目录。升级前保留原镜像和匹配的部署配置,升级后核对 `/readyz`、驱动、业务数据及节点事件恢复。 diff --git a/docs/projects/zboard/guides/maintenance.md b/docs/projects/zboard/guides/maintenance.md new file mode 100644 index 0000000..fc95850 --- /dev/null +++ b/docs/projects/zboard/guides/maintenance.md @@ -0,0 +1,36 @@ +# 系统维护与数据库迁移 + +“设置 → 系统维护”提供整站维护和 MySQL / SQLite 迁移。数据库复制完成后还需要修改部署配置并重启,页面不会自动切换正在使用的数据库。 + +## 开启维护 + +填写维护页标题和说明,勾选“开启整站维护”,点击“保存维护设置”。普通用户、节点上报和业务接口会收到维护响应;管理员控制台、健康检查及状态接口继续可用。 + +维护会影响节点事件接收,应预留维护窗口并观察节点端可靠投递队列。维护结束后检查积压是否恢复,不能只检查首页。 + +## 迁移前准备 + +- 备份源数据库、凭证加密密钥、部署环境配置、托管规则目录及事件存储,保留原镜像。 +- 准备另一种驱动的**空目标库**;不要选用已有业务数据的数据库。 +- SQLite 使用服务器或容器内可写、可持久化的文件路径,例如 `/var/lib/zboard/data/zboard.db`,不是浏览器电脑上的路径。 +- MySQL 使用完整连接 DSN,确认目标库权限;作为源库时还要能执行一致性只读锁操作,具体以连接预检结果为准。 +- 多实例部署应统一安排停写和切换,不要让另一实例继续向源库写入。 + +## 执行与切换 + +1. 打开“系统维护”,检查“当前驱动”。 +2. 选择目标驱动,填写目标连接信息。MySQL DSN 默认隐藏,可按显示按钮核对;切换驱动后要重新填写。 +3. 点击“连接预检”,确认目标可连接且为空。预检不会复制业务数据,也不代表已经切换。 +4. 核实备份后勾选确认,点击“开始迁移”。系统进入维护,复制业务与观测表,并逐表校验数量。 +5. 等待任务完成,查看进度、错误和“下一步”。失败时保留源库并先定位问题,不向未验证目标切换。 +6. 完成后保持维护开启,在部署环境更新 `ZBOARD_DATABASE_DRIVER` 和 `ZBOARD_DATA_SOURCE`;SQLite 同时使用数据目录挂载。按[部署说明](./installation)重启应用。 +7. 确认页面显示目标驱动,检查 `/readyz`、容器健康、管理员登录、订阅、订单、流量和规则产物。 +8. 验证通过后手动关闭维护,检查用户访问及节点上报恢复。 + +迁移运行时不能关闭维护。复制完成也不代表新库已开始服务;必须以重启后的实际驱动和业务读取为准。 + +## SQLite 备份与回滚 + +SQLite 数据目录必须持久化,容器重建不能丢失文件。备份使用一致性备份方式,或停止应用后备份完整数据目录及存在的 WAL/SHM 文件,不只复制仍在写入中的主 `.db`。 + +切换失败时保持维护,停止新实例,恢复原部署配置与匹配的源数据库、规则文件和事件存储,再启动原版本验证。新库已接受业务写入后,不可直接切回旧库丢弃新增数据,应先核对并处理差异。 diff --git a/docs/projects/zboard/guides/node-management.md b/docs/projects/zboard/guides/node-management.md index c5b38c7..c3045a5 100644 --- a/docs/projects/zboard/guides/node-management.md +++ b/docs/projects/zboard/guides/node-management.md @@ -18,24 +18,49 @@ Zboard 将基础设施节点、协议服务和商业订阅分离管理。节点 DNS 记录和托管证书关联到节点与协议服务,但仍是独立资产。 -## 节点接入 +## 新节点接入 -节点接入通常包含: +新 VPS 的受管接入按以下生命周期进行: -1. 配置 VPS 基础信息和 SSH 凭证; -2. 验证 SSH 连接和系统环境; -3. 安装或关联指定版本的 Zero; -4. 检查控制接口和 Connector; -5. 创建协议服务; -6. 发布配置并检查运行状态和事件上报。 +```text +注册 VPS + → 配置 SSH + → 验证 SSH / 提权能力 + → 准备节点身份与上报凭据 + → 提交 Zero 安装 + → 本机/systemd/control 验证 + → 节点就绪 +``` + +BBR 是 SSH 验证后的可选网络优化,不在 Zero 安装成功的关键路径中。保存 SSH 后即可以继续完成 SSH/权限验证和 Zero 初始化,不需要通过“是否启用 BBR”来触发后续流程。 + +Zero 安装、升级和单节点 reconcile 接受后由后端异步执行,不再绑定浏览器请求生命周期。关闭页面或请求被取消,不代表已经接受的节点操作被取消;进度和最终结果应从任务/节点状态查看。 + +## 区分三种运行状态 + +节点运维时不要把下面三类事实合成一个“在线/离线”: + +| 状态 | 表示什么 | +|------|----------| +| **Zero / Kernel** | 目标二进制已安装、systemd 服务 active、控制 socket 健康 | +| **Connector** | 节点事件最近仍能成功送达并由 Zboard 接收 | +| **业务流量** | 当前是否存在用户连接、活跃 flow 或字节事实 | + +一个刚安装、当前没有用户流量的节点可以同时满足:Zero 健康、Connector 在线、业务流量为 0。这是正常空闲状态。 -节点显示“在线”只能证明基础连接或控制面可用。协议服务是否可用还取决于配置验证、端口监听、证书、实际内核能力和最近一次发布结果。 +受管安装完成后的本地健康检查不再因为短时间没有 Connector 事件而回滚一个已经健康的 Zero generation。缺少新事件会记录为 Connector 警告并单独呈现,不应伪装成内核安装失败。 -## Zero 版本选择 +Connector liveness 使用 Zboard 实际接收/持久化事件的时间刷新,而不是直接把 VPS 上事件的 `occurred_at` 当成面板在线时间,避免节点时钟偏差或积压事件导致错误离线判断。 + +## Zero 版本选择与发布 节点可以选择明确的 Zero 发行版本。选择时应区分正式版和预发布版,并按语义版本比较,不要按字符串排序。 -不同协议能力有最低版本要求,例如 Trojan/Hysteria2 托管用户和 Mieru 用户归属。Zboard 会在创建或发布前检查所选节点版本;不满足要求时先升级节点,不应通过共享占位凭据绕过限制。 +VPS 列表会显示节点实际持有的 Zero 版本;较长的 dev/build 版本在列表里可以缩写显示,但详情和版本比较仍使用完整版本号。 + +当前统一使用 Zero Core 0.0.1,支持 Trojan/Hysteria2 托管用户和 Mieru 用户归属。创建和发布时仍需检查所选构建的实际协议能力;缺少能力时先更换兼容构建,不应通过共享占位凭据绕过限制。 + +批量 Zero rollout 会固定目标版本和降级策略,并使用后端受限并发执行,避免不同节点在一次任务中各自解析出不同目标版本。 ## 协议服务 @@ -50,6 +75,19 @@ DNS 记录和托管证书关联到节点与协议服务,但仍是独立资产 协议服务配置支持复用、审计和重新发布,但运行时仍绑定到具体节点。详细字段和版本边界见[协议服务配置](./protocol-services)。 +节点运行时诊断会按该节点实际分配的协议服务解释 listener,而不是把整个平台其他节点的协议端口混进当前节点检查。进入“内核与运维”后可以进行受控的运行状态诊断;主机资源和 SSH 采样仍保持显式操作,不做无界后台 SSH 轮询。 + +## 新节点的 bootstrap inbound + +Zero Core main 已支持无入站的管理模式;当前 Zboard 编译器仍为没有实际协议服务的新节点注入 bootstrap inbound,不能把面板的兼容实现解释为内核仍要求 listener。该入站: + +- 只监听 `127.0.0.1`; +- 使用临时端口 `0`; +- 不持久化为业务 `ProtocolEndpoint`; +- 不会出现在用户订阅中。 + +一旦节点存在真实的启用协议服务,就发布真实 listener,不应继续把 bootstrap inbound 当成节点业务能力。即使真实协议当前还没有订阅用户,也可以以空托管用户集合发布;如果已经存在有效订阅却无法生成对应凭据,则发布应明确失败,而不是静默退回 bootstrap。 + ## 发布流程 一次完整发布应完成: @@ -58,11 +96,42 @@ DNS 记录和托管证书关联到节点与协议服务,但仍是独立资产 2. 在目标节点运行配置校验; 3. 原子替换或激活配置; 4. 检查进程、服务监听和控制接口; -5. 确认 Connector 已接入; +5. 独立观察 Connector 是否恢复事件投递; 6. 更新协议服务的实际发布状态。 任何一步失败都不应把未验证能力提前暴露给订阅。修复首个错误后重新发布,并保留失败任务和审计记录。 +新生成的协议归属 identity 使用不暴露内部数据库 ID 的 opaque principal。它用于 Core flow 归属,不等于协议认证秘密;既有 principal 不会因为升级被强制改写,以保留历史归属连续性。 + +## 自动发布与重试 + +订单确认、订阅到期、流量耗尽、协议端点变更等操作会在业务事务内写入 `node_config_publishes`。请求落库失败时业务事务回滚;后台按节点合并最新配置,不在业务事务中等待 SSH。 + +服务启动会扫描待办,最多四个工作线程执行,空闲时每 5 秒检查。失败按 5、10、20 秒等间隔退避,最长 5 分钟;重启和租约过期后可以接续,不因次数达到上限而丢弃任务。 + +这是至少一次发布:节点已应用配置而数据库尚未确认时可能重复执行。请结合协议发布历史、待办错误与节点运行状态判断;队列为空不等于 Connector 在线。手工发布仍走同步流程。 + +## BBR 与主机操作 + +BBR 是节点级可选操作,不是节点健康前提。SSH 已验证后,进入“内核与运维”会读取一次 VPS 当前的拥塞控制/qdisc 状态,让页面显示真实主机状态;仍可以手动重新检测,但不会周期性轮询。 + +启用或调整 BBR 前应确认目标内核和系统支持。Zboard 只通过已验证的受管 SSH 路径执行操作,并应把任务结果与实际主机状态分开展示。 + +## 删除节点与远端清理 + +删除面板记录与停止远端 Zero 是两个独立操作。当前删除节点只在数据库事务内清理节点、协议、凭据、前置入口、代理池及关联运行记录;不连接 SSH,也不请求供应商 API。历史订单、订阅、流量与审计事实保留。其他存活入口节点需要撤除转发时,任务进入发布队列。 + +因此删除成功不表示远端服务停止或旧凭据即时失效。仍在运行的安装、发布等任务需要先串行完成;数据库清理失败会回滚。 + +若要退役节点,先从“节点资产 → 内核与运维”下载独立清理脚本,在目标 Linux/systemd 节点查看状态并停机,再删除面板记录: + +```sh +sh cleanup-zero-node.sh status +sudo sh cleanup-zero-node.sh stop --yes +``` + +通过新版面板安装或更新过 Zero 的节点,也可使用 `/usr/local/sbin/zboard-zero-cleanup`;既有节点不会自动获得脚本。`stop` 关闭连接并禁用服务,保留配置、二进制和事件数据。确认需要删除托管文件时另行使用 `uninstall --yes`,范围见[节点清理说明](https://github.com/zerodenet/zboard/blob/e1b7246cc4ef805bf39b22d634ba209114eb3b14/docs/node-cleanup.md)。面板已经不可用时仍可离线执行该脚本。 + ## 节点组与运营配置 节点加入并发布协议服务后,可以进一步关联: @@ -77,10 +146,12 @@ DNS 记录和托管证书关联到节点与协议服务,但仍是独立资产 ## 日常检查 -- 节点 Zero 版本与期望版本一致; -- 最近发布状态成功; -- 协议端口和控制接口可达; -- Connector 持续上报事件; +- 节点实际 Zero 版本与期望版本一致; +- Kernel 状态健康,不要用 Connector 状态替代内核健康; +- Connector 最近持续上报事件; +- 当前没有业务流量时,不把 `active_flows=0` 误判为节点离线; +- 最近协议发布状态成功,运行 listener 与该节点分配的协议服务一致; +- SSH 验证和需要的主机操作状态正常; - DNS 记录指向正确节点; - 证书在有效期内且绑定关系正确; - 订阅预览包含预期节点和本地 Mixed 入口; diff --git a/docs/projects/zboard/guides/plans-and-orders.md b/docs/projects/zboard/guides/plans-and-orders.md new file mode 100644 index 0000000..693780e --- /dev/null +++ b/docs/projects/zboard/guides/plans-and-orders.md @@ -0,0 +1,50 @@ +# 套餐、订单与用户交付 + +套餐是商品,SKU 是用户可选择的价格和权益规格,订阅是购买后实际获得的服务。先配置可用节点、节点组及订阅模板,再设置商品与规格。 + +## 管理员准备商品 + +1. 进入“商品与订单 → 商品与套餐”,创建或编辑套餐。 +2. 配置可销售规格,核对价格、流量额度、有效期、计费方式及允许的购买操作。 +3. 确认商品对应的服务范围和客户端交付模板。 +4. 在访客“套餐价格”及登录后的“购买套餐”中检查实际可见商品、规格和结算摘要。 + +商品可见不代表每种规格都适合当前操作。新购、续费、切换套餐和流量加购会按操作及目标订阅筛选规格。 + +## 用户购买与领取配置 + +1. 打开“购买套餐”,选择商品和规格,检查结算页的价格与权益。 +2. 创建订单,进入“我的订单”按站点提供的付款或处理方式完成订单。 +3. 确认订单实际完成并生成订阅后,打开“订阅配置”,选择这份订阅。 +4. 选择适合客户端的输出格式,复制该订阅的链接并导入客户端。 +5. 发起实际连接,随后在“流量明细”核对所选订阅的使用情况。 + +创建订单、订单支付、权益发放和客户端可连接是不同结果。遇到待处理订单先核对原订单,避免重复下单;不要把订单创建成功当作付款或订阅开通成功。 + +## 管理员分配与确认订单 + +当前 main 尚未接入在线支付。管理员可在订单管理中为指定的启用用户选择 SKU,按需指定目标订阅、调整应付金额,并填写分配原因。保存生成待付款订单,不直接发放权益;完成线下核实后,再执行管理员付款确认。 + +分配操作保存管理员、原价、应付金额与原因,并通过操作标识防止重试重复创建。相同标识不能用于不同分配内容。确认后检查订阅权益及节点发布状态;已支付订单的重复确认不会再次发放权益或重复排队发布。 + +在线支付渠道和插件运行时属于后续能力,不能把“待付款 → 管理员确认”的现有流程描述成已完成支付平台集成。 + +## 续费、切换与加购 + +从“订阅配置”中的**具体订阅**发起后续操作,这样结算时会带上正确的目标,不会误操作同账号的其他订阅。 + +| 操作或规格 | 使用时检查 | +| --- | --- | +| 定期订阅续费 | 新的服务周期、价格和额度处理方式 | +| 一次性付费且有有效期 | “一次性付费”不代表永久有效,仍需检查期限 | +| 永久有效规格 | 显示“永久有效 · 流量用完为止”;后续入口可显示“补充额度” | +| 流量加购 | 给选定订阅补充流量,按结算摘要确认额度 | +| 切换套餐 | 目标规格、价格和新权益;确认仍是预期订阅 | + +最终权益以该规格和订单摘要为准,不根据“一次性”一词推断是否重置流量、是否延长期限或是否新建订阅。 + +## 管理订单问题 + +在“商品与订单 → 订单管理”定位用户及原订单,核对状态、商品规格和关联订阅,再处理支持的管理操作。完成后回到订阅页核实权益,并检查客户端配置是否包含已发布的协议服务。 + +订阅链接泄露时,在目标订阅的访问管理中轮换或撤销令牌。每个链接只授权一份订阅,完整输出和流量解释见[订阅交付与流量展示](./subscriptions-and-traffic)。 diff --git a/docs/projects/zboard/guides/protocol-services.md b/docs/projects/zboard/guides/protocol-services.md index 580fa49..02d25c0 100644 --- a/docs/projects/zboard/guides/protocol-services.md +++ b/docs/projects/zboard/guides/protocol-services.md @@ -38,14 +38,14 @@ VLESS REALITY 当前固定使用原始 TCP。VMess 仍要求 TLS,选择传输 VLESS、Trojan、Hysteria2 和 Mieru 等协议可以在订阅发布时注入当前订阅用户的凭据。协议服务模板只保存服务级和传输级默认值,不应保存供所有用户共享的占位凭据。 -内核最低版本要求: +Zero Core 0.0.1 的托管能力: -| 能力 | 最低 Zero 版本 | +| 能力 | 当前基线 | |------|----------------| -| Trojan / Hysteria2 托管订阅用户 | `0.0.15-rc.3` | -| Mieru 用户归属 | `0.0.15-rc.4` | +| Trojan / Hysteria2 托管订阅用户 | 0.0.1 支持,需启用对应协议能力 | +| Mieru 用户归属 | 0.0.1 支持,需启用对应协议能力 | -不满足版本要求时,Zboard 会阻止使用对应托管模式,不会静默退化为共享密码。升级节点内核并重新发布协议服务后再继续。 +节点缺少所需能力时,Zboard 会阻止对应托管模式,不会静默退化为共享密码。选择具备该能力的 0.0.1 内核构建并重新发布协议服务后再继续。 ## 发布状态与订阅交付 @@ -57,6 +57,20 @@ VLESS、Trojan、Hysteria2 和 Mieru 等协议可以在订阅发布时注入当 不要仅根据 Zboard 进程的全局设置判断某个节点是否支持托管用户。 +## 前置端口转发与共享代理池 + +在“协议服务 → 创建协议服务”选择“前置端口转发”,指定入口节点 A、入口端口和落地节点 B 的现有协议。A 只转发原始 TCP/UDP,协议握手、认证与用户计费仍在 B 完成;A 与 B 必须是不同节点。 + +1. 先发布 B 的实际协议,核对对外地址、端口、TLS/SNI 和传输。 +2. 创建 A 的转发服务,选择“仅 TCP”或“TCP 与 UDP”。后者要求 A 和面板校验内核均声明 `direct.inbound.udp.supported=true`;Hysteria2 不能选择仅 TCP。 +3. 默认“直连落地”。需要代理路径时,先在“A 的节点详情 → 共享代理池”创建池,再选择该池;多个入口共用同一份代理图和 URLTest 状态。 +4. 在节点组中分别明确分配 A→B 前置线路和 B 落地协议。仅分配入口不会自动生成 B 的用户凭据,也不会补齐落地权限。 +5. 等待 A、B 配置发布成功且节点在线,再预览订阅。发布排队、停用、离线或凭据缺失的入口不会下发。 + +前置订阅替换连接地址与端口,保留 B 的 TLS、SNI、REALITY 与传输身份。入口 A 不另行认证用户,不能用它禁止已有 B 权限的用户直连 B;流量计费归属 B,A 的网络统计不会形成第二份用户扣费。 + +共享池只供同一 A 上的入口引用,凭据加密保存且不回显、不下发客户端。修改池会排队发布 A;被入口引用的池不能删除。保存通过结构和 TCP/UDP 兼容性校验,不代替实际链路测试。升级后的旧入口需明确关联节点组,不能假定自动授予全部 B 用户入口权限。 + ## 证书绑定 使用 TLS 的协议服务可以绑定已签发且可用的托管证书。证书必须属于目标节点,并覆盖服务使用的域名。证书正在签发、续期、已过期或状态异常时,不应发布新的协议配置。 diff --git a/docs/projects/zboard/guides/subscriptions-and-traffic.md b/docs/projects/zboard/guides/subscriptions-and-traffic.md index c52f3db..9c98a5b 100644 --- a/docs/projects/zboard/guides/subscriptions-and-traffic.md +++ b/docs/projects/zboard/guides/subscriptions-and-traffic.md @@ -37,22 +37,32 @@ Zboard 从协议服务、节点组、订阅模板和用户订阅生成客户端 公开交付只接受明确的订阅客户端 User-Agent。当前内置识别包括: -- 严格的 `ZNet-Sink/<版本>`,例如 `ZNet-Sink/0.0.16-rc.7`; +- 严格的 `ZNet-Sink/<版本>`,例如 `ZNet-Sink/0.0.1`; - Clash / Mihomo; -- sing-box。 +- sing-box; +- Shadowrocket; +- Quantumult X; +- v2rayN。 浏览器、`curl`、空 User-Agent 或仅包含 `ZNet-Sink` 子串的伪造值会在令牌解析前进入订阅伪装跳转,避免公开接口泄露令牌是否存在。 -输出格式使用规范名称: +当前支持两类输出: -| 名称 | 表示 | -|------|------| -| `zero` | Base64 编码的 Zero JSON | -| `clash` | Clash / Mihomo 原生表示 | -| `sing-box` | sing-box 原生表示 | +| 模板 / Renderer | 类型 | 输出 | +|------|------|------| +| `zero` | 完整配置 | Base64 编码的 Zero JSON | +| `clash` | 完整配置 | Clash / Mihomo 原生配置 | +| `sing-box` | 完整配置 | sing-box 原生配置 | +| `shadowrocket` | 节点订阅 | Base64 编码的标准协议分享链接 | +| `quantumult-x` | 节点订阅 | Quantumult X `server_remote` 兼容节点资源 | +| `v2rayn` | 节点订阅 | Base64 编码的标准协议分享链接 | + +Shadowrocket 和 v2rayN 的节点订阅可导出当前支持的 VMess、VLESS、Trojan、Shadowsocks、Hysteria2 等标准分享链接;Quantumult X 只生成当前 renderer 明确支持的节点类型。节点订阅 renderer **不会伪装成完整配置**,因此不导出 Zboard 的策略组或规则集。 `zero-json`、`zero-base64-json`、`znet-sink` 等历史别名会归一化到 `zero`,不能借助旧名称请求明文 Zero JSON。管理端预览可以保持可读,但公开 Zero 交付只输出编码文本。 +内置模板只在缺失时进行一次 seed。管理员之后对模板的编辑或删除是权威状态,升级不会反复覆盖运营侧定制。 + Base64 不是加密。真正的安全边界仍然是随机令牌、HTTPS、令牌轮换与撤销,以及避免在日志、截图和工单中公开完整 URL。 ## 无效订阅链接 @@ -65,7 +75,7 @@ Base64 不是加密。真正的安全边界仍然是随机令牌、HTTPS、令 版本 2 订阅模板包含 `mixed_port`,默认值为 `7890`,允许范围为 `1–65535`。 -Zboard 会为不同客户端生成可直接运行的本地入口: +启用本地 Mixed 时,Zboard 会为不同完整配置客户端生成以下入口;模板也可只启用 TUN,但 Mixed 与 TUN 不能同时关闭: | 输出格式 | 本地入口 | |----------|----------| @@ -73,11 +83,13 @@ Zboard 会为不同客户端生成可直接运行的本地入口: | Clash / Mihomo | `mixed-port` 和 loopback 绑定 | | sing-box | loopback `mixed` 入站 | -因此订阅内容不依赖客户端在导入后临时补建入口。端口已被占用时,应在订阅模板中修改 `mixed_port`,而不是手工编辑每个用户的生成结果。 +因此完整配置订阅不依赖客户端在导入后临时补建入口。Shadowrocket、Quantumult X 和 v2rayN 属于节点订阅输出,不由 Zboard 给它们生成完整本地入站配置。 + +端口已被占用时,应在订阅模板中修改 `mixed_port`,而不是手工编辑每个用户的生成结果。 ## 托管规则与 ZRS -Zboard 托管的规则集由平台维护,而不是由节点内核临时生成: +可交付给 Zero 的网络匹配规则集由平台维护,而不是由节点内核临时生成;含客户端进程条件时适用下方[客户端兼容性](#规则集与客户端兼容性)限制: 1. 管理端写入或导入规则源; 2. Zboard 归一化并校验为 canonical Zero Rule IR; @@ -91,7 +103,13 @@ Zero 客户端拿到的是 ZRS 产物,不是公开的 IR 文本。规则元数 ## 策略组输出 -手动 selector 会保留 `DIRECT` 和 `REJECT` 作为固定选择。URLTest 和 fallback 组不会包含它们,因为它们不是可探测节点。 +完整配置模板中的 selector 可以显式控制是否提供 `DIRECT` 和 `REJECT`。新建或从旧版 v2 customization 迁移的 selector 默认同时启用两项,以保持历史行为;管理员可以分别关闭任意一项。 + +因此 `DIRECT` / `REJECT` 不再是无法配置的隐式固定插入项: + +- selector 只生成模板明确允许的 special targets; +- URLTest 和 fallback 不包含 `DIRECT` / `REJECT`,因为它们不是可探测节点; +- Shadowrocket、Quantumult X、v2rayN 等节点订阅 renderer 不输出策略组,因此也不存在 special-target 配置。 订阅中的节点名称默认沿用协议服务名称,不再附加内部端点或订阅 ID。名称为空时才使用协议名作为回退。协议服务的交付顺序是所有渲染器共享的权威顺序,端点 ID 只作为稳定的最终排序条件。 @@ -103,20 +121,46 @@ http://www.gstatic.com/generate_204 系统只会迁移旧的内置默认值,不会覆盖运营人员自定义的测速 URL。 -## 流量计费与趋势语义 +## 规则集与客户端兼容性 + +托管规则导入接受独立 Provider 规则集,例如 Clash Classical 的域名、IP/CIDR、`PROCESS-NAME` 与 `PROCESS-PATH`。配置片段不能当成独立规则集导入;未知匹配项或空内容会报错,同步失败保留上一份有效内容。 + +进程条件可以导出给 Clash/sing-box,仍取决于实际客户端和平台能否识别进程。Zero 当前不能执行进程规则:含这类条件的来源不生成 ZRS、不出现在 Zero 模板选择器中,显式绑定会拒绝;已被 Zero 模板引用的来源也不能直接更新成含进程规则的内容。不会通过静默删除条件来生成“部分可用”配置。 + +完整配置模板还提供 DNS、TUN、本地入口、控制接口和路由偏好。按目标 renderer 填写,不能把客户端专属字段当成跨客户端合同。sing-box 的非 TUN 配置可选择自动设置系统代理;启用 TUN 时由客户端通过平台 HTTP 代理配置管理开关,不再生成会调用桌面命令的 `set_system_proxy`。 + +## 流量计费与分钟级使用明细 Zboard 以 Zero 上报并成功归属到订阅用户的完成流量事实为来源: 1. Zero 建立并记录真实连接; 2. 完成事实包含连接的上下行字节和用户归属; -3. Zboard 幂等写入流量记录; +3. Zboard 幂等写入原始流量记录; 4. 应用协议服务或套餐配置的计费倍率; 5. 累加该订阅的已用流量; 6. 剩余流量由套餐额度减去已用流量得到。 客户端本地显示一次测速成功,不代表服务端一定建立了可归属连接。Zboard 不会根据客户端报告凭空生成流量费用。 -管理端和个人中心的趋势图从后端按时间范围聚合的结果读取,并使用订阅、用户、节点等业务标签展示关联实体;前端不应拉取全量原始明细后自行聚合。 +系统将**计费事实**和**人类阅读的历史列表**分开:原始 `TrafficRecord` 继续作为计费、审计和对账事实;管理端和账户端的分页使用明细默认由后端聚合为分钟 bucket。 + +聚合维度保留会影响计费解释的语义:分钟、用户、订阅、节点、协议端点和倍率。同一分钟里只有这些维度都一致的记录才会合并,并返回 `record_count` 表示底层原始记录数量。 + +需要排障或审计原始分页记录时可以显式请求: + +```text +?view=raw&paged=true +``` + +非分页历史调用保持既有原始记录语义。前端不需要下载全量明细再自行聚合。 + +## 趋势与活跃连接 + +管理端和个人中心的趋势图从后端按时间范围聚合的结果读取,并使用订阅、用户、节点等业务标签展示关联实体。趋势图支持悬浮 crosshair/tooltip、序列开关和键盘浏览;流量 tooltip 可以同时展示计费量、上行、下行与原始记录数量。 + +连接数使用 Principal flow 的服务观测事实。未采集到 Principal flow 观测时应显示为“未采集”/空值,不应伪造为 0;`active_flows = 0` 只表示当前没有活跃连接,不代表节点或 Connector 离线。 + +系统时区会参与日期型趋势读取:日期 `from` / `to`、每日 bucket 以及 Dashboard 的 today/7d/30d 都按配置的 IANA `system_timezone` 计算本地日历边界,再转换为 UTC 查询。数据库和绝对 API 时间继续使用 UTC;夏令时地区的 23/25 小时日按真实日历处理。 后台存储和计费使用精确字节。界面根据数值自动显示 B、KB、MB 或 GB;单位变化只影响显示,不改变数据库、API 或计费结果。 @@ -129,8 +173,21 @@ Zboard 以 Zero 上报并成功归属到订阅用户的完成流量事实为来 3. HTTP 响应不是伪装跳转; 4. 客户端选择了正确模板或自动检测; 5. `zero` 响应能够完整 Base64 解码,且不是明文 JSON; -6. 生成配置包含 loopback Mixed 入口; +6. 完整配置模板包含预期本地入口;节点订阅模板不要按完整配置解析; 7. 节点组至少包含已启用、可发布的协议服务; 8. 引用的托管规则 ZRS URL 可读取且与当前数据库快照匹配。 流量未增加时,确认节点侧是否存在归属到该订阅用户的完成事件。只有客户端本地探测记录、但节点没有会话和字节事实时,应排查客户端到节点的实际连接路径,而不是修改计费逻辑。 + +分页使用明细和原始账务事实不一致时,先用 `view=raw` 检查底层记录,再确认分钟聚合维度和倍率是否一致;不要把聚合行数量误当成实际连接/计费记录数量。 + +## 在页面中查用量与对账 + +1. 管理员进入“节点与协议 → 流量与对账”;用户进入“流量明细”。 +2. 先选择时间范围,再按用户、具体订阅或节点缩小范围。用户端订阅选择器可搜索历史订阅,不应根据概览中的几条预览判断全部订阅已加载。 +3. 区分统计摘要、趋势图和分页明细:翻页只改变明细页,不能把当前页合计当作整个区间用量。 +4. 管理员核对原始记录与订阅累计值时使用对账结果;存在错误归属、倍率或缺失事实时保留原记录调查,不靠修改页面统计掩盖差异。 + +当前明细支持实时页和游标前后翻页;总条数未提供时不会把未知总数当作零。非法用户或订阅筛选应报错,不会自动退回全站查询。加载失败时先处理错误,不能据此判断“没有流量”。 + +套餐购买及续费操作见[套餐、订单与用户交付](./plans-and-orders)。 diff --git a/docs/projects/zboard/guides/troubleshooting.md b/docs/projects/zboard/guides/troubleshooting.md index 17f5569..4f94d8e 100644 --- a/docs/projects/zboard/guides/troubleshooting.md +++ b/docs/projects/zboard/guides/troubleshooting.md @@ -4,8 +4,8 @@ 检查: -- MySQL 连接是否可用; -- Redis 是否正常运行; +- `ZBOARD_DATABASE_DRIVER` 是否与数据源相符; +- MySQL 连接是否可用,或 SQLite 数据目录是否已持久挂载且可写; - 环境变量是否完整; - JWT 和凭证加密密钥是否满足要求; - 容器磁盘空间和 inode 是否充足; @@ -24,7 +24,7 @@ 5. 证书文件和规则资源是否可访问; 6. 激活后的服务、控制接口和 Connector 是否健康。 -协议服务保存成功不代表发布成功。依赖托管用户能力时,还要确认节点实际内核版本满足最低要求,并完成一次成功发布。 +协议服务保存成功不代表发布成功。依赖托管用户能力时,还要确认节点实际内核为 0.0.1 且具备所需协议能力,并完成一次成功发布。 ## 协议配置校验失败 @@ -38,7 +38,7 @@ VLESS/VMess 常见原因: - VLESS REALITY 使用了非 TCP 传输; - VMess 缺少要求的 TLS 配置。 -Trojan/Hysteria2 托管订阅用户需要 Zero `0.0.15-rc.3` 或更高版本;Mieru 用户归属需要 `0.0.15-rc.4` 或更高版本。详细说明见[协议服务配置](./protocol-services)。 +Zero Core 0.0.1 支持 Trojan/Hysteria2 托管用户和 Mieru 用户归属,实际可用性取决于节点构建是否启用对应协议能力。详细说明见[协议服务配置](./protocol-services)。 ## 订阅配置异常 @@ -71,7 +71,7 @@ Base64 不是加密。不要把完整订阅 URL、令牌或解码后的凭据放 - 确认记录保存的 Zone/record ID 与远端一致; - revision 冲突时刷新后重试; - 同步任务运行期间不要并发删除; -- 远端 404 会按已删除处理,其他供应商错误会保留本地记录。 +- 当前删除只清理面板记录,不调用供应商 API;真实 DNS 记录保留。供应商权限只影响同步,删除失败应核对并发任务与数据库事务。 更改供应商账号、完整域名或记录类型需要删除后重建。 @@ -105,3 +105,11 @@ Zboard 会先写入临时 token 并从域名请求验证。预检失败时先修 - 绑定时确认证书属于同一节点、覆盖协议域名且状态可用。 详细流程见[DNS 与证书管理](./dns-and-certificates)。 + +## 维护后普通用户或节点无法访问 + +先在“设置 → 系统维护”检查维护状态。维护期间业务接口与节点上报会收到维护响应;健康检查仍可用,所以健康正常不代表业务已恢复。迁移复制完成后,仍需切换部署配置、重启验证并手动结束维护,见[维护指南](./maintenance)。 + +## 公告未出现或注册邮件未收到 + +公告先核对受众、发布状态、开始/结束时间和已读状态。邮件先区分注册前验证码与注册后欢迎任务,再检查 SMTP 和“运营任务”的结果,见[公告与邮件](./announcements-and-email)。 diff --git a/docs/projects/zboard/index.md b/docs/projects/zboard/index.md index 18046f6..b4bea71 100644 --- a/docs/projects/zboard/index.md +++ b/docs/projects/zboard/index.md @@ -2,24 +2,34 @@ +::: info 文档对应版本 +本轮使用说明按 2026-09-09 的 [main 提交 e1b7246c](https://github.com/zerodenet/zboard/tree/e1b7246cc4ef805bf39b22d634ba209114eb3b14)核对。已公开 [0.0.1 正式版](https://github.com/zerodenet/zboard/releases/tag/v0.0.1);源码、发布与安装验收范围见[实现与文档进度](/progress)。实际能力以所用制品及运行时响应为准。 +::: + Zboard 是代理服务运营管理平台,用于管理 VPS、协议服务、节点组、商品、订单、订阅、配置交付、流量、DNS 和证书。 ## 开始使用 1. 阅读[部署指南](./guides/installation)。 -2. 完成[首次初始化](./guides/first-setup)。 +2. 完成[首次初始化](./guides/first-setup),确认站点、系统时区和历史保留策略。 3. 接入基础设施并配置[节点与协议服务](./guides/node-management)。 4. 根据客户端和商业模型配置[订阅交付与流量](./guides/subscriptions-and-traffic)。 5. 需要自动维护域名和 TLS 时配置[DNS 与证书](./guides/dns-and-certificates)。 ## 核心能力 -- 管理 VPS 资产、供应商账号、SSH 凭证和节点生命周期; +- 管理 VPS 资产、供应商账号、SSH 凭证、Zero 安装升级和节点生命周期; +- 将 Zero 内核健康、Connector 事件在线和业务流量活跃作为不同运行事实分别观测; +- 管理前置 TCP/UDP 转发与节点共享代理池,分别授权入口线路和落地协议; +- 使用持久化发布队列重试配置交付;本地资源删除与远端停机清理分别执行; +- 为指定用户分配待付款订单,调整应付金额并保留原因,管理员确认后开通权益; - 管理 VLESS、VMess、Shadowsocks、Trojan、Hysteria2、Mieru 等协议服务; - 为 VLESS/VMess 配置 TCP、WebSocket、gRPC 和受支持的 TLS/REALITY 组合; -- 生成面向 ZNet Sink、Clash/Mihomo、sing-box 的可直接运行订阅配置; -- 管理用户、套餐、订单、订阅、流量额度和计费倍率; +- 生成面向 ZNet Sink、Clash/Mihomo、sing-box 的完整配置订阅,以及 Shadowrocket、Quantumult X、v2rayN 节点订阅; +- 管理用户、套餐、订单、订阅、流量额度和计费倍率,并提供后端聚合的流量历史与趋势; +- 通过管理 Dashboard 查看收入/订单、订阅生命周期、活跃连接、当前待处理事件和基础设施健康; - 管理 Cloudflare DNS 记录以及 HTTP-01、DNS-01 证书签发与续期; +- 使用 IANA 系统时区统一运营时间和业务日历读取,并配置审计/运营历史保留周期; - 接收节点运行事件并进行运营审计。 ```text @@ -27,14 +37,43 @@ Zboard 是代理服务运营管理平台,用于管理 VPS、协议服务、节 ↘ DNS 记录 / 托管证书 ↗ ``` -协议服务配置、节点实际发布状态和订阅交付状态分别记录。节点完成配置验证、激活、健康检查和事件接入后,相关订阅配置才进入交付流程。 +协议服务配置、节点实际发布状态和订阅交付状态分别记录。节点完成配置验证、激活和内核健康检查后,可以独立判断 Connector 是否恢复;没有当前用户流量并不等于节点不可用。 + +## 运营面板 + +管理 Dashboard 以 `today`、`7d`、`30d` 三个时间范围提供后端聚合的运营读模型,主要包括: + +- 已支付净收入、订单和新购/续费构成; +- 新订阅、当前有效订阅以及即将到期/额度耗尽状态; +- 当前有活跃 Principal flow 的订阅和活跃连接总数; +- 所选区间的计费流量和业务趋势; +- 当前未解决的 Connector 离线、最新协议发布失败和待管理员处理工单; +- SSH、Connector、流量凭据、协议服务等基础设施准备度。 + +历史失败任务、已经被后续成功覆盖的发布失败和普通待支付订单不会继续被当成当前待处理事故。多币种区间也不会被强行相加成一个虚假的收入值。 + +Dashboard 的日期边界遵循系统设置中的 IANA `system_timezone`。底层记录仍保存为 UTC 绝对时间。 + +## 系统运营 + +管理员可以在系统设置中维护时区和运营历史保留策略。默认审计日志保留 180 天,已结束的运营历史和任务历史默认保留 90 天;`0` 表示永久保留。 + +“设置 → 关于 ZBoard”提供当前 Zboard 版本、发布通道、后端启动时间/运行时长、首次安装时间、MPL-2.0 开源许可和项目资源入口。版本和运行信息来自管理员专用系统信息接口,不通过公开系统信息接口暴露。 ## 文档入口 - [用户指南](./guides/) - [部署指南](./guides/installation) +- [首次初始化](./guides/first-setup) - [节点与协议服务管理](./guides/node-management) - [协议服务配置](./guides/protocol-services) - [订阅交付与流量展示](./guides/subscriptions-and-traffic) - [DNS 与证书管理](./guides/dns-and-certificates) - [参与 Zboard](./contributing/) + +## 日常操作入口 + +- [后台导航与日常运营](./guides/daily-operations) +- [套餐、订单与用户交付](./guides/plans-and-orders) +- [公告、注册验证与邮件](./guides/announcements-and-email) +- [系统维护与数据库迁移](./guides/maintenance) diff --git a/docs/projects/znet-sink/guides/data-and-diagnostics.md b/docs/projects/znet-sink/guides/data-and-diagnostics.md index 4fa30b1..1d305af 100644 --- a/docs/projects/znet-sink/guides/data-and-diagnostics.md +++ b/docs/projects/znet-sink/guides/data-and-diagnostics.md @@ -10,6 +10,11 @@ ZNet Sink 将应用设置、代理配置、订阅、规则和运行记录保存 专业模式的连接页面会先用内核快照建立活动连接基线,再合并后续生命周期事件。实时列表支持暂停刷新、筛选、查看详情和终止连接等操作。 + + + 客户端真实界面,演示数据 · 通过筛选定位连接,再查看详情或终止指定活动连接 + + 连接记录会保留内核返回的结构化字段与原始 wire 元数据。后台协调只用于修复遗漏状态,不应持续制造可见日志,也不会用轮询结果覆盖更新的事件状态。 ## 历史连接 @@ -39,6 +44,16 @@ ZNet Sink 将应用设置、代理配置、订阅、规则和运行记录保存 ## 日志与调试 + + + 客户端真实界面,演示数据 · 可按来源、级别和关键词筛选,并暂停滚动或复制结果 + + + + + 实机截图 · 日志页可按来源、级别和关键词缩小排查范围 + + 专业模式还提供: - 应用日志和内核日志; @@ -48,6 +63,11 @@ ZNet Sink 将应用设置、代理配置、订阅、规则和运行记录保存 日志页用于日常筛选和复制;调试页更接近原始控制面数据,不应把其中未经检查的内容直接公开。 + + + 实机截图 · IPC 调试页适合确认控制请求、响应和实时事件是否连通 + + ## 导出诊断包 “设置 → 关于”可以导出诊断资料,包括应用日志、IPC 调试记录、内核日志和版本清单。导出流程设计为排除: @@ -63,3 +83,16 @@ ZNet Sink 将应用设置、代理配置、订阅、规则和运行记录保存 清理日志不会删除代理配置、订阅、规则、应用设置或内核文件。应用或内核继续运行时会按需生成新的日志。 清理连接历史只删除客户端保存的诊断记录,不会修改内核当前连接,也不会回滚 Zboard 已接收的流量事实。 + +## DNS、出口诊断与设置迁移 + + + + 实机截图 · 诊断工具把 DNS、缓存与路由检查集中在同一页面 + + +在专业模式诊断工具的“解析缓存”中,可按域名或 Fake-IP 查询映射,查看容量、过期、驱逐及 reverse miss 等计数,删除当前映射或清空全部。清空后应用中的旧合成地址可能失效,需要重新解析。 + +连接详情和 TUN 状态提供出口接口、地址族可用性、目标恢复和直连拨号等诊断。无观测或状态未知不能当作零流量、已关闭或可用。 + +要迁移 DNS、TUN、路由和测速偏好,请使用[客户端设置导入导出](./settings-transfer)。诊断包用于排障,不是可恢复的设置备份。 diff --git a/docs/projects/znet-sink/guides/dns.md b/docs/projects/znet-sink/guides/dns.md new file mode 100644 index 0000000..346e973 --- /dev/null +++ b/docs/projects/znet-sink/guides/dns.md @@ -0,0 +1,56 @@ +# DNS 与 Fake-IP + +在“设置 → DNS”中选择解析方式、上游服务器和分流规则。首次使用先选 Real DNS,确认网站和节点都能访问,再按需要启用 Fake-IP。 + +## 选择解析模式 + +| 模式 | 适合的用法 | 需要确认 | +| --- | --- | --- | +| 停用 | 暂时停用客户端 DNS 设置并保留草稿 | 当前配置本身是否已有 DNS 设置 | +| Real DNS | 返回真实 IP,作为日常使用的起点 | 上游可达,地址族与网络相符 | +| Fake-IP | 为域名返回合成地址,连接时由内核恢复域名后分流 | 内核能力、TUN DNS 劫持及合成地址的接管范围 | + +Fake-IP 地址不是网站真实地址,不能把它复制给未连接同一内核的其他设备使用。客户端根据内核声明的能力开放功能;旧内核不支持时,保存到客户端不代表已经应用到运行中的内核。 + +## 设置上游并应用 + +1. 打开“设置 → DNS”,选择 Real DNS 或 Fake-IP。 +2. 选择默认服务器。需要自定义时,在“DNS 服务器”新增或编辑服务器,填写协议、主机、端口以及适用的 Bootstrap 地址、TLS 名称。 +3. 在查询策略中配置超时和回退顺序。给代理节点使用单独的解析链,防止“先连接代理才能解析代理服务器”的循环。 +4. 按当前网络选择 IPv4 only、IPv6 only、Prefer IPv4 或 Prefer IPv6。只有 IPv4 出口时,先用 IPv4 only 验证。 +5. 点击“保存并应用”,等待结果;失败时阅读字段错误,修正后再保存。 + +客户端推荐配置使用 Cloudflare DoH 为默认上游,依次回退 Google 和 system;代理节点先由 system 解析,再使用独立的直连 Bootstrap 上游。AliDNS 和 114DNS 已列为可选服务器,**不会自动成为国内域名分流规则**。网络无法访问推荐上游时,换用当前网络可达的服务器。 + +“跟随默认出站”随目标配置的默认路由解析,不固定绑定上一份配置的节点。DoQ 暂不支持经代理出站;需要经代理传输 DNS 时选择兼容的 DoH、DoT 或 UDP 配置。使用 system 的 TUN DNS 劫持需要内核支持系统 DNS 自动发现;界面阻止保存时,应升级内核或按提示关闭劫持。 + +## 给内网域名单独解析 + +1. 添加能解析公司或家庭内网域名的 DNS 服务器。 +2. 在“DNS 分流”新增域名、域名后缀或已有规则集条件,选择这个服务器;规则按顺序首次命中生效。 +3. 使用 Fake-IP 时,把需要真实地址的内网域名加入“排除域名”。 +4. 如果还需要目标网络保持系统原路由,在“设置 → 网络 → 绕过规则”填写实际内网 CIDR,例如 `192.168.50.0/24`。 +5. 保存后重新解析并访问内网服务,确认返回地址和连接路径。 + +| 设置 | 作用 | +| --- | --- | +| DNS 分流 | 选择由哪台服务器解析域名 | +| Fake-IP 排除域名 | 这些域名返回真实地址 | +| DNS 拒绝地址网段 | 拒绝上游返回的指定地址并尝试回退,不写入缓存 | +| 统一绕过中的 IP/CIDR | 协调 TUN 排除、系统代理例外与内核直连,保留系统路由 | + +后三项不能互相代替。尤其不要把所有私网地址加入“拒绝地址网段”来解决内网绕过问题,否则可能把正确的内网 DNS 结果一起拒绝。 + +## 开启 DNS 劫持 + +先保存有效 DNS 设置,再开启“DNS 劫持”,并确认 TUN 已运行。此功能处理经过 TUN 的 TCP/UDP 53 端口查询;应用自己发出的 DoH、DoT、DoQ 不会被普通 53 端口劫持解密。ECH 隐藏的主机名也不能保证恢复。 + +验证时,先在专业模式连接详情确认 `inbound_tag` 来自 TUN,再查看域名恢复、路由和出站。系统代理与 TUN 同时开启时,浏览器可能实际走 Mixed 入站,单凭网页能打开不能验证 TUN。 + +## 缓存与异常恢复 + +在 DNS 设置中调整普通 DNS 缓存容量与最长 TTL;Fake-IP 的池范围、TTL、映射容量和排除域名单独配置。已有连接使用旧映射时,不要反复切换地址池。 + +遇到旧映射或配置切换后的解析异常,先查看诊断信息和 Fake-IP 缓存状态,再使用界面提供的缓存管理操作。清除映射后,应用缓存中的旧合成地址可能暂时失效,需要重新解析或重新打开连接。 + +继续阅读 [TUN 接管与网络切换](./tun)和[数据与诊断](./data-and-diagnostics)。 diff --git a/docs/projects/znet-sink/guides/features.md b/docs/projects/znet-sink/guides/features.md index a6a6c3d..330cb56 100644 --- a/docs/projects/znet-sink/guides/features.md +++ b/docs/projects/znet-sink/guides/features.md @@ -12,6 +12,23 @@ 第一次使用可按[安装与首次启动](./installation)和[完成第一次连接](./first-connection)顺序操作。本地入口、Windows 系统代理和代理终端的具体语义见[本地代理、系统代理与节点测速](./proxy-and-probes)。 + + + 客户端真实界面,演示数据 · 连接后可在概览确认内核、系统代理、TUN 和流量状态 + + +## 内核与代理开关 + +首次启动没有代理配置时,兼容内核可使用临时最小配置保留 IPC 管理入口。开启系统代理仍需有效配置和已监听的本地端口。“断开”关闭系统代理,受管内核可以继续运行;TUN 状态需单独确认。启动结果会核对健康 IPC 和实际子进程身份,不能仅凭进程存在判断已就绪。 + +## TUN 与 DNS + +在“设置 → DNS”选择 Real DNS 或 Fake-IP,配置命名服务器、回退、节点解析链及域名分流。在“设置 → TUN”设置双栈接管、接管网段和 DNS 劫持;在“设置 → 网络”统一维护[绕过规则](./proxy-and-probes#统一绕过规则)。 + +当前配置显式包含 `runtime.tun`(包括 `null`)时,由配置管理;其他配置使用客户端缺省值。客户端管理的 TUN 运行时可“保存并应用”,内核通过重建 TUN 应用参数,已有连接可能中断。未确认的状态显示为未知;内核启动成功但 TUN 恢复失败会单独提示。 + +按 [DNS 与 Fake-IP](./dns) 和 [TUN 接管与网络切换](./tun)操作。系统代理与 TUN 可同时启用;DNS 劫持只处理经过 TUN 的普通 53 端口查询。 + ## 订阅管理 客户端可以保存远程订阅、手动同步或按周期更新,并将支持的订阅内容转换为本地配置。原生 Zero 内容会优先按原生字段处理;转换和迁移时会保留当前支持的协议字段,并确保订阅配置包含可用的本地代理入口。 @@ -26,6 +43,22 @@ 节点页会处理单节点探测、URLTest 策略快照、嵌套策略组和配置隔离的延迟历史。切换配置后,同名节点不会直接继承上一份配置的历史;大量节点的策略测速会使用自适应等待时间。 +客户端会继续以运行时策略快照校准 URLTest 的当前选中项。手动探测 URLTest 卡片时,客户端按当前实际生效的策略出站刷新结果,避免 UI 选中态和内核运行态长期分离。 + + + + 客户端真实界面,演示数据 · 左侧切换策略组,节点卡片展示协议、传输与最近延迟 + + +## 规则分流 + +专业模式的“规则”页集中管理公共规则注入、规则集更新和分流动作。先确认公共规则是否生效,再按优先级检查各规则集的直连、代理或最终规则动作;远程规则集可以单独更新,也可以统一刷新。 + + + + 客户端真实界面,演示数据 · 每条规则集同时显示构建状态、条目数量、分流动作和顺序 + + ## 桌面代理集成 - Windows 系统代理使用当前 Mixed 地址,并保存接管前的原始代理和绕过设置; @@ -44,10 +77,10 @@ “设置 → 内核”用于安装、选择和查看客户端所需的内核组件。版本管理会区分稳定版、测试版和每日构建;日常使用优先选择稳定版。 -协议、传输、URLTest 和控制接口能力以当前内核返回的能力信息为准。客户端升级不代表已选择的内核也自动升级。 +协议、传输、URLTest、TUN 和控制接口能力以当前内核返回的能力信息为准。客户端升级不代表已选择的内核也自动升级;使用新 DNS/TUN 功能前,确认客户端和内核的契约版本及正向能力相容,详见[迁移设置与管理内核](./settings-transfer)。 ## 日志与诊断 客户端可以查看应用日志、内核日志、能力信息和运行状态,并导出诊断资料。导出前仍应复核是否包含私人信息,具体范围见[数据与诊断](./data-and-diagnostics)。 -出现启动、连接、订阅、系统代理或测速问题时,按[故障排查](./troubleshooting)逐项检查。 +出现启动、连接、订阅、系统代理、TUN 或测速问题时,按[故障排查](./troubleshooting)逐项检查。 diff --git a/docs/projects/znet-sink/guides/first-connection.md b/docs/projects/znet-sink/guides/first-connection.md index f1559f3..5b7ce9c 100644 --- a/docs/projects/znet-sink/guides/first-connection.md +++ b/docs/projects/znet-sink/guides/first-connection.md @@ -33,12 +33,33 @@ 如果内核已经运行但系统代理未开启,按钮会显示“开启系统代理”。 -## 4. 关闭服务 +## 4. 按需启用 TUN + +先在“设置 → DNS”保存有效解析配置,再按需启用 DNS 劫持。在“设置 → TUN”确认来源、地址、MTU 和接管网段,然后开启 TUN 并等待状态确认。首次安装不会因为自动连接就擅自开启 TUN。 + +当前配置显式定义 `runtime.tun`(包括 `null`)时由配置管理;否则使用客户端缺省值。创建网卡和修改路由需要系统权限。详细步骤见 [DNS 与 Fake-IP](./dns)和 [TUN 接管与网络切换](./tun)。 + +系统代理可与 TUN 同时开启。验证 TUN 时检查流量的实际入站来源,不能只看网页是否打开。 + +## 5. 切换配置 + +TUN 运行期间切换配置时,客户端会根据新旧配置的所有权交接运行状态:显式 `runtime.tun` 优先于客户端缺省值;新配置不再需要旧 TUN 时会按新的期望状态协调。交接失败时客户端会尽量恢复切换前状态并记录错误。 + +因此切换后应同时观察: + +- 当前配置名称; +- 系统代理状态; +- TUN 是否运行及其配置来源; +- 节点/URLTest 当前选中项是否已经更新到新配置。 + +不要只根据按钮是否亮起判断切换成功。 + +## 6. 关闭服务 点击“关闭服务”会撤销由 ZNet Sink 管理的系统代理设置。为了保留连接监控和快速恢复能力,普通断开不会以停止内核进程作为前提。 -TUN 与系统代理是两个不同入口。启用 TUN 前,应先确认客户端显示的当前能力支持该模式。 +TUN 与系统代理是两个不同入口。若 TUN 仍在运行,应单独关闭并确认运行状态。运行中的客户端缺省参数也可“保存并应用”,该操作会重建 TUN。 -## 5. 选择节点与模式 +## 7. 选择节点与模式 连接服务运行后,可以在概览或节点页切换策略组选中项,并在全局、规则和直连模式之间切换。策略组的实际成员和可用操作以当前配置及客户端显示状态为准。 diff --git a/docs/projects/znet-sink/guides/index.md b/docs/projects/znet-sink/guides/index.md index 6166125..b9ca9e8 100644 --- a/docs/projects/znet-sink/guides/index.md +++ b/docs/projects/znet-sink/guides/index.md @@ -11,3 +11,9 @@ 7. [故障排查](./troubleshooting) 这些页面描述 ZNet Sink 的安装、界面和用户操作。涉及内核字段和协议能力时,以当前 Zero Core 文档及客户端显示的能力信息为准。 + +## 设置专题 + +- [DNS 与 Fake-IP](./dns) +- [TUN 接管与网络切换](./tun) +- [迁移设置与管理内核](./settings-transfer) diff --git a/docs/projects/znet-sink/guides/installation.md b/docs/projects/znet-sink/guides/installation.md index b37330e..f09d793 100644 --- a/docs/projects/znet-sink/guides/installation.md +++ b/docs/projects/znet-sink/guides/installation.md @@ -4,20 +4,70 @@ ZNet Sink 是桌面代理客户端。安装应用后,还需要在首次引导 ## 下载安装包 -官方下载地址: +打开[客户端下载页](/download),页面会根据浏览器识别 Windows、macOS 或 Linux,并优先显示适合当前设备的安装包。无法确认芯片架构时,可以手动选择。 + +GitHub 发布页: 源码地址: -从 Releases 页面下载与你的平台和架构匹配的安装包,并按系统提示完成安装: +下载与你的平台和架构匹配的安装包,并按系统提示完成安装: | 平台 | 架构 | 安装包 | | --- | --- | --- | | Windows 10/11 | x86_64 | NSIS 或 MSI | | macOS | Intel、Apple Silicon | DMG | -| Linux | x86_64 | deb 或 AppImage | +| Linux | x86_64 | DEB、RPM 或 AppImage | 不要从非项目发布页下载二次打包程序。升级前如需保留诊断或配置快照,请先查看[数据与诊断](./data-and-diagnostics)。 +## macOS:提示应用“已损坏” + +当前 macOS 安装包尚未完成 Apple 开发者签名和公证。即使文件本身下载完整,macOS 也可能提示“ZNet Sink 已损坏,无法打开”或无法验证开发者。 + +请先确认 DMG 来自上方 ZeroDeNet 官方 GitHub Releases,并且架构选择正确:Apple 芯片使用 `aarch64.dmg`,Intel Mac 使用 `x64.dmg`。将 ZNet Sink 拖入“应用程序”后,关闭系统提示并打开“终端”,执行: + +```bash +sudo xattr -rd com.apple.quarantine "/Applications/ZNet Sink.app" +``` + +输入当前 Mac 的登录密码后重新打开 ZNet Sink。终端输入密码时不会显示字符,这是正常现象。如果应用放在其他目录,请把命令中的路径改为实际位置。 + +该命令只移除 ZNet Sink 的下载隔离标记。不要关闭整个系统的 Gatekeeper,也不要对来源不明的应用执行此命令。 + +## Linux:通过终端安装或运行 + +Linux 桌面环境不一定会在双击安装包时自动完成安装,建议先打开终端,再根据下载的文件类型执行命令。以下文件名以 `0.0.1` 为例;下载其他版本时,请替换为实际文件名。 + +### Ubuntu / Debian(DEB) + +```bash +cd ~/Downloads +sudo apt install ./ZNet.Sink_0.0.1_amd64.deb +``` + +`apt install ./文件名.deb` 会同时处理软件包依赖。安装完成后,可以从桌面应用菜单打开 ZNet Sink。 + +### Fedora / RHEL 系(RPM) + +```bash +cd ~/Downloads +sudo dnf install ./ZNet.Sink-0.0.1-1.x86_64.rpm +``` + +安装完成后,从桌面应用菜单启动。如果系统使用 `yum`,可以把 `dnf` 替换为 `yum`。 + +### 通用 AppImage + +AppImage 不写入系统软件包数据库,需要先授予执行权限,再从终端启动: + +```bash +cd ~/Downloads +chmod +x ZNet.Sink_0.0.1_amd64.AppImage +./ZNet.Sink_0.0.1_amd64.AppImage +``` + +以后仍可执行同一个 AppImage 文件启动客户端;如果移动了文件,需要从新位置运行。当前官方 Linux 桌面安装包仅提供 x86_64 版本。 + ## 完成首次引导 首次启动包含三个步骤: @@ -28,6 +78,16 @@ ZNet Sink 是桌面代理客户端。安装应用后,还需要在首次引导 界面模式以后仍可在应用内切换。 + + + 实机截图 · 设置页会集中展示常用网络选项 + + + + + 实机截图 · “关于”页可核对客户端版本、构建标识和项目来源 + + ## 准备内核组件 打开“设置 → 内核”,选择以下任一方式: diff --git a/docs/projects/znet-sink/guides/proxy-and-probes.md b/docs/projects/znet-sink/guides/proxy-and-probes.md index de16f2e..98aa7ee 100644 --- a/docs/projects/znet-sink/guides/proxy-and-probes.md +++ b/docs/projects/znet-sink/guides/proxy-and-probes.md @@ -30,6 +30,26 @@ Windows 上会保存原始 `ProxyServer`、绕过列表和自动配置地址, 系统代理主要覆盖遵循操作系统 HTTP/HTTPS 代理设置的 TCP 应用。它不等同于 TUN,也不会自动接管所有 UDP、WebRTC 或 DNS 流量。 +## 统一绕过规则 + +在“设置 → 网络”编辑“绕过规则”,系统代理与 TUN 共用这一份策略,规则模式和全局模式均生效: + +1. 按需启用“自动绕过局域网”,覆盖本机、常用私有网段、链路本地地址及本地域名,保留系统原有 VPN 路由。 +2. 每行填写一个自定义 IP、CIDR 或域名,例如 `192.168.50.0/24`、`intranet.example.com`、`*.example.com`;留空表示没有自定义规则。 +3. 保存并等待运行配置应用完成。TUN 页的“管理绕过规则”会打开同一编辑入口。 + +客户端把可精确表达的例外写入系统代理,将 IP/CIDR 加入 TUN 排除范围,并通过内核 `route.bypass` 保证模式无关的直连。系统代理无法精确表达的 CIDR 由内核执行,不会扩大成更宽网段;因此“直连”不保证流量完全绕过内核进程。配置自带的 TUN 排除仍叠加保留。 + +域名规则需要代理请求、受管 DNS 映射或支持的嗅探提供主机名。应用自己使用加密 DNS/ECH 且只暴露 IP 时,不能保证域名绕过生效,应使用已知目标网段。 + +首次迁移会合并旧系统代理绕过和 TUN 排除设置,此后以统一策略为准,删除的规则不会从旧字段重新出现。运行内核必须声明 `route_bypass_v1`;网段变更可能重建受管 TUN 并中断连接,失败时按既有配置事务恢复。 + +## TUN 与系统代理 + +系统代理服务遵循操作系统代理设置的应用,TUN 接管进入虚拟网卡的流量,两者可以同时开启。查看连接的入站 tag 可以确认请求实际走了哪条路径。 + +TUN 来源、运行中修改、网络切换和停止确认见 [TUN 接管与网络切换](./tun)。当前客户端已提供 DNS 配置及 DNS 劫持;先保存有效 DNS 设置,再按 [DNS 与 Fake-IP](./dns)启用。 + ## 打开代理终端 Windows 托盘菜单中的“打开终端”会: @@ -53,8 +73,15 @@ Windows 托盘菜单中的“打开终端”会: 节点页会把单节点探测、策略组快照和本地历史合并为当前显示结果: + + + 客户端真实界面,演示数据 · 选择策略组后可查看当前出口、节点能力和探测延迟 + + - URLTest 组使用内核返回的成员快照和当前选中项; +- 客户端会继续用运行时策略快照校准 URLTest 当前选中项,避免 UI 长期保留旧选择; - 当 URLTest 作为另一个组中的节点卡片出现时,单点测速只探测它当前实际生效的出站,不递归重测全部成员; +- 手动刷新 URLTest 卡片时,会通过策略探测路径刷新当前生效结果; - 手动等待期间到达的新鲜定时结果也可以完成本次等待; - 本地先显示的超时可以被随后到达的有效结果替换; - 嵌套 URLTest 卡片使用自身策略组的历史,不沿用父组的旧值; @@ -87,4 +114,4 @@ Windows 不稳定支持区域旗帜 emoji,因此节点卡片使用旗帜图片 5. 避免连续点击父组、子 URLTest 和全部成员; 6. 等待一次完整批次结束后再重试。 -本地代理无法使用时,先在“设置 → 常规”确认代理端口,再检查[故障排查](./troubleshooting)。 +本地代理无法使用时,先在“设置 → 常规”确认代理端口;TUN 异常时同时确认“设置 → TUN”的来源和权限状态,再检查[故障排查](./troubleshooting)。 diff --git a/docs/projects/znet-sink/guides/settings-transfer.md b/docs/projects/znet-sink/guides/settings-transfer.md new file mode 100644 index 0000000..dde6657 --- /dev/null +++ b/docs/projects/znet-sink/guides/settings-transfer.md @@ -0,0 +1,39 @@ +# 迁移设置与管理内核 + +换电脑或复用 DNS/TUN 设置时,使用设置页的“导入 / 导出客户端配置”。这是运行偏好的迁移入口;代理配置、订阅和诊断记录仍分别管理。 + +## 导出并导入 + +1. 在设置页的配置编辑区域找到“导入或导出 DNS、TUN 和客户端运行偏好”,点击“导出”,保存 JSON 文件。 +2. 在目标客户端点击“导入”,选择导出的文件,等待校验结果。 +3. 核对目标电脑的 DNS、TUN 地址、MTU、接管/排除网段以及运行偏好。 +4. 检查目标电脑的内核路径和当前代理配置,在相应设置页应用并确认运行状态。 + +导出使用 `znet.client-kernel-settings.v2`,包含统一 `bypass`;导入支持 v1 并迁移旧绕过字段,旧客户端会拒绝 v2,避免静默丢失域名例外;导入也可读取旧 `gui.app.v1` 配置中的可迁移设置,文件上限为 2 MiB。机器专属路径和当前配置身份不作为可移植设置迁移。导入成功后仍要确认当前配置是否拥有自己的 `runtime.tun`,以免把保存缺省值误认为运行中已经改变。 + +迁移范围包括 DNS、TUN、统一绕过、路由、URLTest,以及自动连接、自动启动、退出清理代理和网络探测地址。内核正在运行时,导入会重启受管内核并按导入设置恢复 TUN,现有连接可能中断;失败会尝试恢复原设置与运行状态。请等待完整结果再继续操作。 + +不要把这个文件当作完整数据备份。迁移订阅、代理配置和规则时,使用各自的管理功能;完整数据目录及诊断材料见[数据与诊断](./data-and-diagnostics)。 + +## 0.0.1 安装与恢复 + +Zero Core、ZNet Sink 和 Zboard 的产品版本统一为 0.0.1。安装客户端与内核时选择对应平台的正式制品,并核对实际能力。 + +需要重新安装或恢复时,先备份应用数据与配置,关闭系统代理和 TUN,再从[正式发布页](https://github.com/zerodenet/znet-sink/releases/tag/v0.0.1)下载安装包。已有安装没有显示更新提示时,可在版本管理中明确选择目标,按应用提示完成安装,不依赖编号重置前的版本比较。 + +四平台安装运行及升级中断恢复的待验证范围见[实现进度](/progress)。 + +## 安装与选择内核 + + + + 实机截图 · 版本管理会标记当前版本,并提供不同发布渠道的安装入口 + + +在“设置 → 内核”查看、安装或选择 Zero。更新客户端后,仍需确认实际选用的内核版本以及能力信息;新界面不意味着旧内核自动具备 DNS、TUN 或 V1 契约能力。 + +当前正式版本为 0.0.1,日常使用选择稳定渠道。开发分支或候选构建不作为另一套产品版本基线;试用其他构建时核对其提交和能力,并保留可恢复的制品。 + +自动版本检查按渠道缓存,正常检查间隔为 6 小时,失败后最短重试间隔为 15 分钟。刚进入设置页没有新的网络请求不代表检查失效;需要立即确认时使用界面的手动刷新。 + +升级后先确认内核健康、本地 Mixed 入口、系统代理,再按需要确认 TUN 和 DNS。收到“TUN 恢复失败”提示时,按 [TUN 状态说明](./tun)处理。 diff --git a/docs/projects/znet-sink/guides/subscriptions.md b/docs/projects/znet-sink/guides/subscriptions.md index 762095c..cc1be55 100644 --- a/docs/projects/znet-sink/guides/subscriptions.md +++ b/docs/projects/znet-sink/guides/subscriptions.md @@ -21,6 +21,11 @@ Clash 内容会转换为 Zero 配置。转换能力不等同于完整兼容所 ## 添加订阅 + + + 实机截图 · 新建订阅时可一次设置格式识别与自动更新周期 + + 1. 打开“订阅”。 2. 点击新增订阅,填写名称和订阅 URL。 3. 通常保留“自动检测”;只有服务端格式固定且检测失败时再手动指定。 @@ -29,6 +34,13 @@ Clash 内容会转换为 Zero 配置。转换能力不等同于完整兼容所 “自动检测”会作为真实源格式保存,不会根据当前本地生成配置被强制改写为 Zero 或 Clash。同步成功后,订阅会创建或更新一份本地代理配置;新生成的配置不会无条件抢占当前配置,需要时请在“配置”页确认并启用。 + + + 客户端真实界面,演示数据 · 保存后可直接查看配额、有效期、节点数量与最近同步时间 + + +订阅卡片右侧依次提供同步、编辑和删除操作。批量更新前先确认需要参与同步的订阅处于启用状态;同步完成后再到“配置”和“节点”页检查转换结果及当前启用配置。 + ## User-Agent User-Agent 留空时,客户端发送: @@ -37,7 +49,7 @@ User-Agent 留空时,客户端发送: ZNet-Sink/<当前版本> ``` -例如 `ZNet-Sink/0.0.16-rc.7`。填写自定义值后,该值会**完全覆盖**默认 User-Agent,不会在末尾追加 ZNet-Sink 标识。 +例如 `ZNet-Sink/0.0.1`。填写自定义值后,该值会**完全覆盖**默认 User-Agent,不会在末尾追加 ZNet-Sink 标识。 Zboard 的公开订阅接口要求严格的 `ZNet-Sink/<版本>` 格式。使用 Zboard 链接时通常应保持留空;只有其他订阅服务明确要求特定 User-Agent 时才覆盖。历史版本曾在自定义值末尾追加客户端标识,现有记录会在迁移时清理该旧格式。 diff --git a/docs/projects/znet-sink/guides/troubleshooting.md b/docs/projects/znet-sink/guides/troubleshooting.md index e160c1c..515fc1f 100644 --- a/docs/projects/znet-sink/guides/troubleshooting.md +++ b/docs/projects/znet-sink/guides/troubleshooting.md @@ -22,6 +22,27 @@ 不要只根据进程存在判断服务可用;健康检查、本地监听和系统代理三者都需要成功。 +## TUN 无法开启或开启后断网 + +TUN 运行需要兼容的 Zero 内核,并需要操作系统允许创建虚拟网卡和修改路由。先检查 TUN 状态中显示的配置来源,再判断应该修改当前配置还是客户端缺省值。 + +常见情况: + +- **权限不足**:Windows 使用管理员权限运行;Linux/macOS 确保当前启动方式具备 TUN 与路由操作权限。客户端会尽量把权限错误直接显示出来; +- **Windows 提示 Wintun 问题**:官方 Zero Core 0.0.1 Windows 发布包已经包含 Wintun。只有自行打包或文件不完整时才应优先检查组件缺失; +- **地址或 MTU 无效**:主地址和第二地址使用 CIDR,MTU 必须在 `576–65535`; +- **网络切换后断流**:新版 Zero 会重新协调物理出口和 TUN 捕获路由。仍失败时保存 underlay/route 相关日志,不要先手工给每个代理服务器添加永久 host route; +- **切换配置后状态不一致**:确认 TUN 的 `configSource` 已切换到新配置或客户端缺省值,并检查切换失败后的恢复日志; +- **内核重启后 TUN 没恢复**:确认客户端保存的期望状态仍为开启,并查看重启后的 TUN replay/reconcile 日志。 + +客户端管理的 TUN 可在运行中“保存并应用”,但会重建网卡;旧内核不能核实参数时采用关闭、保存、开启的流程。状态未知时先刷新确认,不要反复重试。内核启动成功但 TUN 恢复失败时,按独立的恢复错误处理,详见 [TUN 指南](./tun)。 + +## TUN 已开启但 DNS 路径不符合预期 + +在“设置 → DNS”确认模式、上游和保存应用结果,再检查 DNS 劫持及实际 TUN 运行状态。配置本身拥有 TUN 时,还要检查当前配置的 DNS/TUN 参数。 + +普通 53 端口劫持不能解密应用自己的 DoH/DoT/DoQ,也不能保证恢复 ECH 隐藏的主机名。系统代理不会自动接管全部 UDP、DNS 或 WebRTC。按 [DNS 指南](./dns)区分上游分流、Fake-IP 排除域名和 TUN 排除网段。 + ## 已连接但应用没有走代理 - 确认概览中的系统代理状态为“已开启”; @@ -30,14 +51,18 @@ - 如果使用 TUN,确认 TUN 状态和系统权限,不要把 TUN 与系统代理状态混为一谈; - Windows 上检查是否有其他程序同时修改 `ProxyServer`、绕过列表或 PAC。 +Lite 模式允许系统代理和 TUN 同时启用,因此看到两者都处于开启状态本身不是异常。 + 可以从托盘打开代理终端,用 `curl` 或包管理器验证注入的 HTTP/SOCKS5 环境变量。该终端可用而其他应用不可用时,问题通常在应用自身的代理设置。 ## 订阅同步失败 - 检查 URL 是否仍然有效; - 检查网络是否允许访问订阅服务; -- 将格式切换为明确的 Zero JSON、Zero Base64 JSON、Clash YAML 或 Clash Base64 YAML; -- 查看错误是否来自下载、重定向、Base64 解码、YAML/JSON 解析还是 Clash 转换; +- 自动检测只应根据本次订阅响应判断格式,不应由已有本地配置强行决定; +- Zero 订阅使用规范的 `zero` 格式,即 Base64 编码的 Zero JSON;客户端不接受远程明文 Zero JSON; +- Clash 等其他来源按当前支持的规范格式选择; +- 查看错误是否来自下载、重定向、Base64 解码、YAML/JSON 解析还是格式转换; - 如果响应最终跳转到普通网页,检查服务端令牌和订阅模板,不要把网页强制按 Base64 解析。 一次同步失败不会覆盖原有可用配置。 @@ -50,12 +75,26 @@ - 当前页面显示的配置与内核活动配置一致; - 切换配置后没有继续等待旧配置的测速; +- URLTest 当前选中项已经按最新运行时策略快照同步; - 父 selector 中的 URLTest 没有同时被展开为全部成员重复测速; - 成员较多时已经等待自适应超时窗口; - 超时后到达的新鲜结果是否更新了卡片和悬浮历史。 +客户端手动刷新 URLTest 时按当前策略的实际生效出站执行探测。如果 UI 仍显示旧选中项,优先检查策略事件/快照链路,而不是仅重复测速。 + 不要用连续点击或高频轮询代替事件链路排查。完整语义见[本地代理、系统代理与节点测速](./proxy-and-probes)。 +## 实时连接切换配置后异常 + +切换配置会清空旧配置的页面投影,但新的 flow 事件仍应持续进入。客户端会在事件流持续运行时同步活动连接快照,并按实际 flow 变化统计暂停期间的更新。 + +如果切换后只有重启应用才能看到新连接: + +1. 检查 GUI 事件连接是否仍然订阅; +2. 检查新配置是否已经成为内核活动配置; +3. 查看活动 flow reconciliation 是否持续执行; +4. 保存配置切换前后第一批 `flow.snapshot` / lifecycle 事件用于排查。 + ## 打开终端没有反应 Windows 托盘终端依赖 `pwsh.exe` 或 `powershell.exe`。检查应用日志中的 `tray: open terminal`、内核启动、本地代理监听和进程创建记录。终端只有在本地代理端口可用后才会打开。 @@ -68,5 +107,6 @@ Windows 托盘终端依赖 `pwsh.exe` 或 `powershell.exe`。检查应用日志 - 内核版本; - 操作系统与架构; - 当前配置名称以及是否刚发生过配置切换; +- TUN 是否开启、由当前配置还是客户端缺省值管理; - 可以稳定复现的步骤; - 首次出现的错误,而不是只截取最后一条连带错误。 diff --git a/docs/projects/znet-sink/guides/tun.md b/docs/projects/znet-sink/guides/tun.md new file mode 100644 index 0000000..6152fb6 --- /dev/null +++ b/docs/projects/znet-sink/guides/tun.md @@ -0,0 +1,51 @@ +# TUN 接管与网络切换 + +TUN 用于接管不遵循系统代理设置的流量。先完成[第一次连接](./first-connection),再配置 TUN;创建虚拟网卡和修改路由需要操作系统授权。 + +## 确认参数来源 + +打开“设置 → TUN”查看来源: + +| 当前配置 | 使用的参数 | 设置页保存的效果 | +| --- | --- | --- | +| 没有 `runtime.tun` | 客户端缺省值 | TUN 正运行时可“保存并应用” | +| 显式包含 `runtime.tun` | 当前配置拥有 TUN 设置 | “保存缺省值”供其他配置使用,不覆盖当前配置 | +| 显式写了 `runtime.tun: null` | 仍视为配置明确管理 | 不以客户端缺省值擅自启动 TUN | + +## 配置并开启 + +1. 确认“设置 → 内核”已选择兼容内核,并处理权限或 Wintun 错误。 +2. 在 TUN 设置中填写主地址 CIDR、网卡名称、入站 tag 和 MTU。MTU 范围为 `576–65535`,没有特别需要时沿用现有值。 +3. 需要 IPv4/IPv6 接管时启用“双栈接管”;第二地址留空自动选择,也可填写另一地址族的 CIDR。 +4. “TUN 接管网段”留空表示全部目标;填写后只接管这些网段。排除目标在“设置 → 网络 → 绕过规则”维护,每行一个 IP/CIDR;TUN 页通过“管理绕过规则”进入,目标保留系统原路由。 +5. 需要 DNS 劫持时先完成 [DNS 设置](./dns),再开启劫持。 +6. 保存并开启 TUN,等待运行状态确认。 + +双栈接管不代表物理网络自动获得 IPv6 出口。没有 IPv6 出口时,内核只能在具有可信域名信息的适用路径上重新选择地址;裸 IPv6、NAT64 和所有 UDP 的自动跨族转换不在保证范围内。 + +## 运行中修改参数 + +客户端管理的 TUN 运行时可以修改设置,点击“保存并应用”后等待完成。当前内核通过停止并重建 TUN 应用网卡、地址及捕获网段参数,客户端和内核进程保持运行,但已有 TUN 连接可能中断。 + +应用成功后才保存新参数;失败且能确认当前运行状态时,客户端会尝试恢复旧 TUN 和设置。若出现超时、外部状态变化或无法核实结果,会提示未确认状态,避免并发重启和相互覆盖。此时先刷新状态、查看错误,不要连续点击保存。 + +旧内核缺少接管/排除 CIDR 状态字段时,无法核实在线修改结果;升级内核,或采用“关闭 TUN → 保存 → 再开启”的流程。TUN 或内核原本关闭时,保存缺省值不会主动启动它们。 + +## 看懂开关与状态 + +| 显示情况 | 如何处理 | +| --- | --- | +| 已运行 | 确认当前来源和参数,再访问目标应用 | +| 已保存开启,但未运行 | 检查启动或恢复错误,修正后再开启 | +| 未知 / 无法获取状态 | 通信失败不等于已关闭;刷新状态并查看日志 | +| 内核启动成功,但 TUN 恢复失败 | 内核和 TUN 分开排查,按提示处理权限、参数或出口问题 | + +关闭客户端管理的 TUN 会先保存“关闭”的意图,再请求内核停止;只有查询确认停止,才算关闭成功。若停止结果未确认,应继续检查实际网卡和状态。保存的关闭意图可防止后续内核重启重新恢复旧的开启状态。 + +## Wi-Fi、网线或 VPN 切换 + +网络切换后,先查看 TUN 的 IPv4/IPv6 出口诊断和降级原因,再分别验证域名解析及实际 TCP/UDP 流量。最新内核包含 Windows strict routing 下的 DHCP 客户端流量放行修复,仍需在自己的网络环境确认地址续租和连接恢复。 + +如果内网 VPN 不通,检查排除 CIDR 是否为实际目标网段、系统原路由是否存在。系统代理和 TUN 可以同时启用。客户端[统一绕过策略](./proxy-and-probes#统一绕过规则)会协调系统代理、TUN 排除与内核路由;仅手工修改代理配置的 `runtime.tun.exclude_cidrs` 不会同步应用自身的 HTTP/SOCKS5 代理设置。 + +停止接管时分别关闭系统代理和 TUN。完全退出客户端会尝试停止其管理的 TUN 与内核;出现恢复错误时,保留日志并检查系统代理和路由状态。 diff --git a/docs/projects/znet-sink/index.md b/docs/projects/znet-sink/index.md index fba9d71..fcad8f3 100644 --- a/docs/projects/znet-sink/index.md +++ b/docs/projects/znet-sink/index.md @@ -2,11 +2,29 @@ +::: info 文档对应版本 +本轮使用说明按 2026-09-09 的 [main 提交 6d822fb9](https://github.com/zerodenet/znet-sink/tree/6d822fb96140be87cdccdd0bea472ba0b089cf04)核对。已公开 [0.0.1 正式版](https://github.com/zerodenet/znet-sink/releases/tag/v0.0.1);源码、发布与安装验收范围见[实现与文档进度](/progress)。实际能力以所用制品及运行时响应为准。 +::: + ZNet Sink 是跨平台代理客户端,提供配置与订阅管理、节点选择、系统代理、连接状态和诊断。默认集成 Zero Core,并可通过适配接入其他运行时。 +::: tip 关于界面截图 +为避免公开真实订阅、节点和连接信息,部分整页截图由 ZNet Sink 当前 Svelte/Tauri 客户端前端加载脱敏演示数据生成。界面结构、组件和主题来自客户端本体;图中网络状态与测速结果仅用于说明操作。 +::: + + + + 客户端真实界面 · 概览集中展示运行状态、代理模式、TUN 与实时流量 + + + + + 实机截图 · 专业模式的规则集管理 + + ## 第一次使用 -1. [安装并完成首次启动](./guides/installation)。 +1. [下载最新版客户端](/download),并[完成首次启动](./guides/installation)。 2. [导入配置并完成第一次连接](./guides/first-connection)。 3. 如果使用远程订阅,阅读[订阅管理](./guides/subscriptions)。 @@ -14,7 +32,8 @@ ZNet Sink 是跨平台代理客户端,提供配置与订阅管理、节点选 - 管理本地代理配置和远程订阅; - 查看连接状态并切换节点、策略组和运行模式; -- 管理系统代理或 TUN 入口; +- 管理系统代理、[TUN 接管网段](./guides/tun)及 [DNS/Fake-IP](./guides/dns); +- [迁移客户端设置并管理内核版本](./guides/settings-transfer); - 查看实时连接、日志和能力信息; - 导出经过脱敏的诊断资料。 diff --git a/docs/public/brand/.gitkeep b/docs/public/brand/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/public/brand/zerodenet-dark.png b/docs/public/brand/zerodenet-dark.png new file mode 100644 index 0000000..b18f7c5 Binary files /dev/null and b/docs/public/brand/zerodenet-dark.png differ diff --git a/docs/public/brand/zerodenet-light.png b/docs/public/brand/zerodenet-light.png new file mode 100644 index 0000000..0789b9e Binary files /dev/null and b/docs/public/brand/zerodenet-light.png differ diff --git a/docs/public/screenshots/znet-sink-about.png b/docs/public/screenshots/znet-sink-about.png new file mode 100644 index 0000000..53c017e Binary files /dev/null and b/docs/public/screenshots/znet-sink-about.png differ diff --git a/docs/public/screenshots/znet-sink-connections-demo.png b/docs/public/screenshots/znet-sink-connections-demo.png new file mode 100644 index 0000000..d12d620 Binary files /dev/null and b/docs/public/screenshots/znet-sink-connections-demo.png differ diff --git a/docs/public/screenshots/znet-sink-diagnostics.png b/docs/public/screenshots/znet-sink-diagnostics.png new file mode 100644 index 0000000..3cd4d32 Binary files /dev/null and b/docs/public/screenshots/znet-sink-diagnostics.png differ diff --git a/docs/public/screenshots/znet-sink-ipc-debug.png b/docs/public/screenshots/znet-sink-ipc-debug.png new file mode 100644 index 0000000..cab4240 Binary files /dev/null and b/docs/public/screenshots/znet-sink-ipc-debug.png differ diff --git a/docs/public/screenshots/znet-sink-logs-demo.png b/docs/public/screenshots/znet-sink-logs-demo.png new file mode 100644 index 0000000..2be3efa Binary files /dev/null and b/docs/public/screenshots/znet-sink-logs-demo.png differ diff --git a/docs/public/screenshots/znet-sink-logs.png b/docs/public/screenshots/znet-sink-logs.png new file mode 100644 index 0000000..080ba2e Binary files /dev/null and b/docs/public/screenshots/znet-sink-logs.png differ diff --git a/docs/public/screenshots/znet-sink-nodes-demo.png b/docs/public/screenshots/znet-sink-nodes-demo.png new file mode 100644 index 0000000..2ab1954 Binary files /dev/null and b/docs/public/screenshots/znet-sink-nodes-demo.png differ diff --git a/docs/public/screenshots/znet-sink-overview-demo.png b/docs/public/screenshots/znet-sink-overview-demo.png new file mode 100644 index 0000000..736dbf6 Binary files /dev/null and b/docs/public/screenshots/znet-sink-overview-demo.png differ diff --git a/docs/public/screenshots/znet-sink-rules-demo.png b/docs/public/screenshots/znet-sink-rules-demo.png new file mode 100644 index 0000000..2cf68bb Binary files /dev/null and b/docs/public/screenshots/znet-sink-rules-demo.png differ diff --git a/docs/public/screenshots/znet-sink-rules.png b/docs/public/screenshots/znet-sink-rules.png new file mode 100644 index 0000000..bf60132 Binary files /dev/null and b/docs/public/screenshots/znet-sink-rules.png differ diff --git a/docs/public/screenshots/znet-sink-settings.png b/docs/public/screenshots/znet-sink-settings.png new file mode 100644 index 0000000..a1a22ec Binary files /dev/null and b/docs/public/screenshots/znet-sink-settings.png differ diff --git a/docs/public/screenshots/znet-sink-subscription-add.png b/docs/public/screenshots/znet-sink-subscription-add.png new file mode 100644 index 0000000..0c06430 Binary files /dev/null and b/docs/public/screenshots/znet-sink-subscription-add.png differ diff --git a/docs/public/screenshots/znet-sink-subscriptions-demo.png b/docs/public/screenshots/znet-sink-subscriptions-demo.png new file mode 100644 index 0000000..77ab83a Binary files /dev/null and b/docs/public/screenshots/znet-sink-subscriptions-demo.png differ diff --git a/docs/public/screenshots/znet-sink-version-management.png b/docs/public/screenshots/znet-sink-version-management.png new file mode 100644 index 0000000..1136e2c Binary files /dev/null and b/docs/public/screenshots/znet-sink-version-management.png differ diff --git a/scripts/check-docs.mjs b/scripts/check-docs.mjs index 3b78788..8c4dda5 100644 --- a/scripts/check-docs.mjs +++ b/scripts/check-docs.mjs @@ -107,6 +107,9 @@ if (!existsSync(projectsFile)) { errors.push(`docs/.vitepress/projects.json: 项目 ${label} 的 download 必须是 HTTPS URL`) } } + if (project.downloadPage && !resolveLocalTarget(join(docsRoot, 'index.md'), project.downloadPage)) { + errors.push(`docs/.vitepress/projects.json: 项目 ${label} 的 downloadPage 页面不存在`) + } if (project.quickStart && !resolveLocalTarget(join(docsRoot, 'index.md'), project.quickStart)) { errors.push(`docs/.vitepress/projects.json: 项目 ${label} 的 quickStart 页面不存在`) }
SMART DOWNLOAD
页面只判断设备平台与浏览器可提供的架构信息;无法可靠识别时,会把可选安装包全部列出。
+ 安装包由 ZeroDeNet 的 GitHub Releases 提供。 + 查看发布说明 ↗ +
DESKTOP CLIENT
ZNet Sink 把节点、规则、系统代理、TUN 与诊断集中在一个清晰的工作台中。简约模式专注日常连接,专业模式保留完整控制能力。
PROJECTS