From 6ef19d5be91691cee2d86432def1a4ea81e53428 Mon Sep 17 00:00:00 2001 From: salmonstill Date: Fri, 24 Apr 2026 00:42:59 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=B8=80=E6=AC=A1=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VPS流量转发架构说明.md | 86 +++++ beijing-vps-stream.conf | 27 ++ subscribe-7891-only.yaml | 49 +++ subscribe.yaml | 307 ++++++++++++++++++ tokyo-vps-config.json | 44 +++ xray-北京vps-config.json | 290 +++++++++++++++++ xray-旁路由-config.json | 183 +++++++++++ 东京-vps-stream.conf | 18 + 我的世界udp转发.md | 245 ++++++++++++++ .../backup-ImmortalWrt-2026-04-17.tar.gz | Bin 0 -> 9716 bytes .../backup-ImmortalWrt-2026-04-18.tar.gz | Bin 0 -> 10126 bytes 11 files changed, 1249 insertions(+) create mode 100644 VPS流量转发架构说明.md create mode 100644 beijing-vps-stream.conf create mode 100644 subscribe-7891-only.yaml create mode 100644 subscribe.yaml create mode 100644 tokyo-vps-config.json create mode 100644 xray-北京vps-config.json create mode 100644 xray-旁路由-config.json create mode 100644 东京-vps-stream.conf create mode 100644 我的世界udp转发.md create mode 100644 旁路由备份/backup-ImmortalWrt-2026-04-17.tar.gz create mode 100644 旁路由备份/backup-ImmortalWrt-2026-04-18.tar.gz diff --git a/VPS流量转发架构说明.md b/VPS流量转发架构说明.md new file mode 100644 index 0000000..3bb731f --- /dev/null +++ b/VPS流量转发架构说明.md @@ -0,0 +1,86 @@ +# VPS流量转发架构说明 +## 总览 +这套架构基于Xray+Nginx SNI分流实现,完全基于443端口HTTPS流量伪装,实现三个核心功能: +1. 反向代理内网服务到公网(无需公网IPv6/端口映射) +2. 异地多VPS链路中转代理(mihomo客户端接入) +3. 统一公网入口流量管理(所有流量走443端口,无额外端口暴露) + +--- +## 设备清单说明 +| 设备 | IP/域名 | 说明 | +|---|---|---| +| 北京VPS | `salmonstill.cn` | 公网入口节点,Nginx+Xray服务部署在这里 | +| 东京VPS | `tokyo.salmonstill.cn` | 代理出口节点,Xray服务部署在这里 | +| 旁路由 | `192.168.1.199` | 内网反向代理节点,Xray桥接服务部署在这里 | +| NAS | `192.168.1.188` | 内网存储服务,部署了思源笔记、绿联云管理界面 | +| Windows台式机 | `192.168.1.177` | 内网办公设备,提供WSL SSH服务 | + +--- +## 核心组件说明 +### 1. 北京VPS(公网入口节点) +#### Nginx Stream SNI分流层 +配置文件:`beijing-vps-stream.conf` +根据SSL握手阶段的ServerName字段,将不同域名的流量转发到不同后端服务: +| 域名 | 后端服务 | 作用 | +|---|---|---| +| `www.apple.com` | Xray 9443端口 | 旁路由反向代理隧道 | +| `www.microsoft.com` | Xray 9444端口 | Mihomo客户端代理入口 | +| `drive.salmonstill.cn` | 38653端口 | 绿联云NAS服务直接转发 | +| 其他域名 | Nginx Proxy Manager 8443端口 | 常规Web服务管理 | + +#### Xray服务层 +配置文件:`beijing-vps-config.json` +包含两个核心入站和一个出站: +- **interconn入站(9443端口)**:VLESS+Reality协议,接收旁路由的反向代理桥接连接 +- **mihomo_in入站(9444端口)**:VLESS+Reality协议,接收外部Mihomo客户端的代理连接 +- **to_tokyo出站**:VLESS+Reality协议,将代理流量转发到东京VPS出口 + +--- +### 2. 旁路由(内网反向代理节点) +配置文件:`旁路由-config.json` +基于Xray反向代理桥接模式实现内网服务穿透: +- **bridge桥接组件**:和北京VPS的portal组件建立永久隧道,将公网过来的反向代理流量转发到内网 +- 路由规则根据端口自动转发到对应内网服务: + | 端口 | 内网目标 | 服务 | + |---|---|---| + | 38653 | 192.168.1.188:9443 | NAS管理界面 | + | 38654 | 192.168.1.188:5005 | 思源笔记 | + | 38655 | 192.168.1.177:22 | WSL SSH服务 | + | 39132 | 127.0.0.1:39132 | Minecraft游戏服务 | + +--- +### 3. 东京VPS(代理出口节点) +配置文件:`tokyo-vps-config.json` +极简配置的Xray出口节点: +- 入站:VLESS+Reality协议,接收北京VPS转发的代理请求 +- 出站:直接freedom出口访问国际网络 + +--- +## 流量路径说明 +### 1. 内网服务反向代理访问路径(比如访问drive.salmonstill.cn) +``` +用户 → 北京VPS 443端口 → Nginx匹配SNI `drive.salmonstill.cn` → 转发到38653端口 dokodemo-door入站 +→ Xray路由转发到portal反向代理组件 → 走已经建立的隧道到旁路由bridge组件 +→ 旁路由路由匹配端口38653 → 转发到内网NAS 192.168.1.188:9443 → 响应原路返回 +``` + +### 2. Mihomo代理访问路径 +``` +Mihomo客户端 → 北京VPS 443端口 → Nginx匹配SNI `www.microsoft.com` → 转发到9444端口 mihomo_in入站 +→ Xray路由转发到to_tokyo出站 → 加密传输到东京VPS 443端口 → 东京Xray入站接收请求 +→ 直接访问国际网络 → 响应原路返回 +``` + +--- +## 架构优势 +1. **极致伪装**:所有流量都走443端口HTTPS,不同流量通过SNI区分,完全和正常网站访问一致,无特征被封 +2. **零额外端口暴露**:除了443端口没有任何公网开放端口,安全性拉满 +3. **高可用性**:反向代理隧道永久在线,内网服务无需公网IP/端口映射即可访问 +4. **性能损耗低**:Xray Reality协议性能优异,中转延迟增加<10ms +5. **易扩展**:新增内网服务只需要在旁路由添加对应的路由规则即可,无需修改公网配置 + +--- +## 配置要点 +1. Reality公私钥配对:客户端的publicKey必须和对应服务端的privateKey严格匹配 +2. SNI一致性:客户端请求的ServerName必须和Nginx分流规则以及Xray Reality配置的serverNames完全一致 +3. 端口映射:Nginx分流的后端端口必须和Xray入站监听端口严格对应 diff --git a/beijing-vps-stream.conf b/beijing-vps-stream.conf new file mode 100644 index 0000000..a53fbf6 --- /dev/null +++ b/beijing-vps-stream.conf @@ -0,0 +1,27 @@ +stream { + map $ssl_preread_server_name $backend { + www.apple.com xray; # 旁路由反向代理隧道 + www.microsoft.com mihomo; # 新增:mihomo出站流量 + drive.salmonstill.cn nas; # 绿联云服务 + default npm; # Nginx Proxy Manager + } + upstream xray { + server 127.0.0.1:9443; + } + # 新增mihomo upstream + upstream mihomo { + server 127.0.0.1:9444; + } + upstream nas { + server 127.0.0.1:38653; + } + upstream npm { + server 127.0.0.1:8443; + } + server { + listen 443 reuseport; + listen [::]:443 reuseport; + ssl_preread on; + proxy_pass $backend; + } +} \ No newline at end of file diff --git a/subscribe-7891-only.yaml b/subscribe-7891-only.yaml new file mode 100644 index 0000000..9f5a7f4 --- /dev/null +++ b/subscribe-7891-only.yaml @@ -0,0 +1,49 @@ +mixed-port: 7890 +allow-lan: true +bind-address: '*' +mode: rule +log-level: info +external-controller: '127.0.0.1:9090' + +find-process-mode: off + +dns: + enable: true + ipv6: false + enhanced-mode: fake-ip + fake-ip-range: 198.18.0.1/16 + default-nameserver: + - tls://223.5.5.5 + - tls://223.6.6.6 + nameserver: + - https://dns.alidns.com/dns-query + - https://doh.pub/dns-query + respect-rules: false + +proxies: + - name: Xray-Real + type: vless + server: salmonstill.cn + port: 443 + uuid: "113e167a-a2be-4b46-9010-60020108626c" + udp: true + flow: xtls-rprx-vision + packet-encoding: xudp + tls: true + servername: www.microsoft.com + client-fingerprint: chrome + reality-opts: + public-key: "62y5gDjPrdeuePGl-D2IW4Cw9Kb8_bSBBTmArvL7Nhs" + short-id: "7c947a71b94f369e" + network: tcp + +listeners: + - name: global-mixed + type: mixed + port: 7891 + listen: 0.0.0.0 + udp: true + proxy: Xray-Real + +rules: + - MATCH,DIRECT \ No newline at end of file diff --git a/subscribe.yaml b/subscribe.yaml new file mode 100644 index 0000000..f13bb9a --- /dev/null +++ b/subscribe.yaml @@ -0,0 +1,307 @@ +# ======================== +# Clash-ALL 思路(单上游 Xray Reality 精简版) + 额外端口:7891 全局代理 + 7892 强制直连 +# ======================== + +mixed-port: 7890 +allow-lan: true +bind-address: '*' +mode: rule +log-level: info +external-controller: '127.0.0.1:9090' + +find-process-mode: off + +dns: + enable: true + ipv6: false + prefer-h3: false + use-hosts: false + use-system-hosts: true + enhanced-mode: fake-ip + fake-ip-range: 198.18.0.1/16 + fake-ip-filter: + - geosite:private + - geosite:tracker + - geosite:cn + - geosite:apple@cn + - geosite:microsoft@cn + - geosite:microsoft + - '+.lan' + - '+.local' + default-nameserver: + - tls://223.5.5.5 + - tls://223.6.6.6 + nameserver: + - https://9.9.9.9/dns-query + - https://149.112.112.112/dns-query + - https://94.140.14.14/dns-query + - https://94.140.15.15/dns-query + proxy-server-nameserver: + - https://dns.alidns.com/dns-query + - https://doh.pub/dns-query + direct-nameserver: + - https://dns.alidns.com/dns-query + - https://doh.pub/dns-query + respect-rules: true + +# ======================== +# 代理定义 +# ======================== +proxies: + - name: 直连 + type: direct + - name: 拒绝 + type: reject + + - name: Xray-Real + type: vless + server: salmonstill.cn + port: 443 + uuid: "113e167a-a2be-4b46-9010-60020108626c" + udp: true + flow: xtls-rprx-vision + packet-encoding: xudp + tls: true + servername: www.microsoft.com + client-fingerprint: chrome + reality-opts: + public-key: "62y5gDjPrdeuePGl-D2IW4Cw9Kb8_bSBBTmArvL7Nhs" + short-id: "7c947a71b94f369e" + network: tcp + +# ======================== +# 策略组 +# ======================== +proxy-groups: + - name: 国内 + type: select + proxies: [直连] + + - name: 国外 + type: select + proxies: [Xray-Real, 直连] + + - name: Steam-rule + type: select + proxies: [国内, 国外, 直连] + + - name: Microsoft-rule + type: select + proxies: [国内, 国外, 直连] + + - name: AI + type: select + proxies: [国外, 国内, 直连] + + - name: Stream Media + type: select + proxies: [国外, 国内, 直连] + + - name: GitHub + type: select + proxies: [国外, 国内, 直连] + + - name: Crypto + type: select + proxies: [国外, 国内, 直连] + + - name: Block + type: select + proxies: [拒绝, 直连] + + - name: 其他 + type: select + proxies: [国内, 国外, 直连, 拒绝] + +# ======================== +# rule-providers +# ======================== +rule-providers: + Ads: + type: http + behavior: domain + format: mrs + interval: 86400 + url: https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/category-ads-all.mrs + path: ./rule-providers/ads.mrs + proxy: 国外 + + Private_Domain: + type: http + behavior: domain + format: mrs + interval: 86400 + url: https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/private.mrs + path: ./rule-providers/private_domain.mrs + proxy: 国外 + + Private_IP: + type: http + behavior: ipcidr + format: mrs + interval: 86400 + url: https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geoip/private.mrs + path: ./rule-providers/private_ip.mrs + proxy: 国外 + + China_Domain: + type: http + behavior: domain + format: mrs + interval: 86400 + url: https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/cn.mrs + path: ./rule-providers/cn_domain.mrs + proxy: 国外 + + China_IP: + type: http + behavior: ipcidr + format: mrs + interval: 86400 + url: https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geoip/cn.mrs + path: ./rule-providers/cn_ip.mrs + proxy: 国外 + + Oracle: + type: http + behavior: domain + format: mrs + interval: 86400 + url: https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/oracle.mrs + path: ./rule-providers/oracle.mrs + proxy: 国外 + + OpenAI: + type: http + behavior: domain + format: mrs + interval: 86400 + url: https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/openai.mrs + path: ./rule-providers/openai.mrs + proxy: 国外 + + GitHub_Domain: + type: http + behavior: domain + format: mrs + interval: 86400 + url: https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/github.mrs + path: ./rule-providers/github.mrs + proxy: 国外 + + Netflix_Domain: + type: http + behavior: domain + format: mrs + interval: 86400 + url: https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/netflix.mrs + path: ./rule-providers/netflix_domain.mrs + proxy: 国外 + + Netflix_IP: + type: http + behavior: ipcidr + format: mrs + interval: 86400 + url: https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geoip/netflix.mrs + path: ./rule-providers/netflix_ip.mrs + proxy: 国外 + + Steam_CN: + type: http + behavior: domain + format: mrs + interval: 86400 + url: https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/steam@cn.mrs + path: ./rule-providers/steam_cn.mrs + proxy: 国外 + + Steam: + type: http + behavior: domain + format: mrs + interval: 86400 + url: https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/steam.mrs + path: ./rule-providers/steam.mrs + proxy: 国外 + + GFW: + type: http + behavior: domain + format: mrs + interval: 86400 + url: https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/gfw.mrs + path: ./rule-providers/gfw.mrs + proxy: 国外 + + Geo_NoCN: + type: http + behavior: domain + format: mrs + interval: 86400 + url: https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/geolocation-!cn.mrs + path: ./rule-providers/geo_nocn.mrs + proxy: 国外 + + Microsoft: + type: http + behavior: domain + format: mrs + interval: 86400 + url: https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/microsoft.mrs + path: ./rule-providers/microsoft.mrs + proxy: 国外 + + Crypto: + type: http + behavior: domain + format: mrs + interval: 86400 + url: https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/category-cryptocurrency.mrs + path: ./rule-providers/crypto.mrs + proxy: 国外 + +# ======================== +# 多监听器部分 +# ======================== +listeners: + - name: global-mixed + type: mixed + port: 7891 + listen: 127.0.0.1 + udp: true + proxy: Xray-Real + + - name: direct-mixed + type: mixed + port: 7892 + listen: 127.0.0.1 + udp: true + proxy: 直连 + +# ======================== +# rules +# ======================== +rules: + - DOMAIN,vs18.bj2cu.u3.ucweb.com,拒绝 + - DOMAIN-SUFFIX,salmonstill.cn,直连 + - DOMAIN-KEYWORD,raylink,直连 + - IP-CIDR,49.232.242.90/32,直连 + - IP-CIDR,43.165.178.10/32,直连 + - RULE-SET,Ads,Block + - RULE-SET,Private_Domain,国内 + - RULE-SET,Private_IP,国内,no-resolve + - RULE-SET,China_Domain,国内 + - RULE-SET,Oracle,国内 + - RULE-SET,China_IP,国内,no-resolve + - RULE-SET,OpenAI,AI + - RULE-SET,GitHub_Domain,GitHub + - RULE-SET,Netflix_Domain,Stream Media + - RULE-SET,Netflix_IP,Stream Media,no-resolve + - RULE-SET,Steam_CN,国内 + - RULE-SET,Steam,Steam-rule + - RULE-SET,Microsoft,Microsoft-rule + - RULE-SET,Crypto,Crypto + - RULE-SET,GFW,国外 + - RULE-SET,Geo_NoCN,国外 + - MATCH,其他 \ No newline at end of file diff --git a/tokyo-vps-config.json b/tokyo-vps-config.json new file mode 100644 index 0000000..f50017b --- /dev/null +++ b/tokyo-vps-config.json @@ -0,0 +1,44 @@ +{ + "log": { + "loglevel": "warning" + }, + "inbounds": [ + { + "listen": "127.0.0.1", + "port": 9443, + "protocol": "vless", + "settings": { + "clients": [ + { + "id": "4d222c16-53bb-4402-814e-c8188cebcea6", + "level": 0, + "flow": "xtls-rprx-vision" + } + ], + "decryption": "none" + }, + "streamSettings": { + "network": "raw", + "security": "reality", + "realitySettings": { + "show": false, + "dest": "www.microsoft.com:443", + "xver": 0, + "serverNames": [ + "www.microsoft.com" + ], + "privateKey": "iBlu3eH1VLf1S5Qw87m_1w0TGYUktDwHAzgpQ2aKuGI", + "shortIds": [ + "a1b2c3d4" + ] + } + } + } + ], + "outbounds": [ + { + "protocol": "freedom", + "tag": "direct" + } + ] +} diff --git a/xray-北京vps-config.json b/xray-北京vps-config.json new file mode 100644 index 0000000..42e422c --- /dev/null +++ b/xray-北京vps-config.json @@ -0,0 +1,290 @@ +{ + "log": { + "loglevel": "warning" + }, + "reverse": { + "portals": [ + { + "tag": "portal", + "domain": "reverse-proxy.xray.internal" + } + ] + }, + "inbounds": [ + { + "tag": "external", + "listen": "0.0.0.0", + "port": 38653, + "protocol": "dokodemo-door", + "settings": { + "address": "127.0.0.1", + "port": 38653, + "network": "tcp" + } + }, + { + "tag": "external_siyuan", + "listen": "0.0.0.0", + "port": 38654, + "protocol": "dokodemo-door", + "settings": { + "address": "127.0.0.1", + "port": 38654, + "network": "tcp" + } + }, + { + "tag": "external_minecraft", + "listen": "0.0.0.0", + "port": 39132, + "protocol": "dokodemo-door", + "settings": { + "address": "127.0.0.1", + "port": 39132, + "network": "tcp" + } + }, + { + "tag": "external_wsl", + "listen": "0.0.0.0", + "port": 38655, + "protocol": "dokodemo-door", + "settings": { + "address": "127.0.0.1", + "port": 38655, + "network": "tcp" + } + }, + { + "tag": "external_nas_ssh", + "listen": "0.0.0.0", + "port": 38656, + "protocol": "dokodemo-door", + "settings": { + "address": "127.0.0.1", + "port": 38656, + "network": "tcp" + } + }, + { + "tag": "external_router_ssh", + "listen": "0.0.0.0", + "port": 38657, + "protocol": "dokodemo-door", + "settings": { + "address": "127.0.0.1", + "port": 38657, + "network": "tcp" + } + }, + { + "tag": "proxy_in", + "listen": "127.0.0.1", + "port": 10809, + "protocol": "mixed", + "settings": { + "udp": true + } + }, + { + "tag": "external_router_web", + "listen": "0.0.0.0", + "port": 39766, + "protocol": "dokodemo-door", + "settings": { + "address": "127.0.0.1", + "port": 39766, + "network": "tcp" + } + }, + { + "tag": "external_tmp", + "listen": "0.0.0.0", + "port": 8501, + "protocol": "dokodemo-door", + "settings": { + "address": "127.0.0.1", + "port": 8501, + "network": "tcp" + } + }, + { + "tag": "interconn", + "listen": "127.0.0.1", + "port": 9443, + "protocol": "vless", + "settings": { + "clients": [ + { + "id": "113e167a-a2be-4b46-9010-60020108626c", + "flow": "xtls-rprx-vision" + } + ], + "decryption": "none" + }, + "streamSettings": { + "network": "raw", + "security": "reality", + "realitySettings": { + "show": false, + "target": "www.apple.com:443", + "serverNames": [ + "www.apple.com" + ], + "privateKey": "GGT9LfN_2JdQG68cwrULgUK-adfT6wIokLzWjaB0fXs", + "shortIds": [ + "7c947a71b94f369e" + ] + } + } + }, + { + "tag": "mihomo_in", + "listen": "127.0.0.1", + "port": 9444, + "protocol": "vless", + "settings": { + "clients": [ + { + "id": "113e167a-a2be-4b46-9010-60020108626c", + "flow": "xtls-rprx-vision" + } + ], + "decryption": "none" + }, + "streamSettings": { + "network": "raw", + "security": "reality", + "realitySettings": { + "show": false, + "target": "www.microsoft.com:443", + "serverNames": [ + "www.microsoft.com" + ], + "privateKey": "GGT9LfN_2JdQG68cwrULgUK-adfT6wIokLzWjaB0fXs", + "shortIds": [ + "7c947a71b94f369e" + ] + } + } + } + ], + "outbounds": [ + { + "tag": "direct", + "protocol": "freedom" + }, + { + "tag": "to_tokyo", + "protocol": "vless", + "settings": { + "vnext": [ + { + "address": "tokyo.salmonstill.cn", + "port": 443, + "users": [ + { + "id": "4d222c16-53bb-4402-814e-c8188cebcea6", + "encryption": "none", + "flow": "xtls-rprx-vision" + } + ] + } + ] + }, + "streamSettings": { + "network": "raw", + "security": "reality", + "realitySettings": { + "show": false, + "fingerprint": "chrome", + "serverName": "www.microsoft.com", + "password": "jr_zQjC4mvlQITuG5Ap5Mxqe5EBbGyyvwbVLDEi8OCA", + "shortId": "a1b2c3d4", + "spiderX": "/" + } + } + } + ], + "routing": { + "rules": [ + { + "type": "field", + "inboundTag": [ + "external" + ], + "outboundTag": "portal" + }, + { + "type": "field", + "inboundTag": [ + "external_siyuan" + ], + "outboundTag": "portal" + }, + { + "type": "field", + "inboundTag": [ + "external_minecraft" + ], + "outboundTag": "portal" + }, + { + "type": "field", + "inboundTag": [ + "external_wsl" + ], + "outboundTag": "portal" + }, + { + "type": "field", + "inboundTag": [ + "external_nas_ssh" + ], + "outboundTag": "portal" + }, + { + "type": "field", + "inboundTag": [ + "external_router_ssh" + ], + "outboundTag": "portal" + }, + { + "type": "field", + "inboundTag": [ + "external_tmp" + ], + "outboundTag": "portal" + }, + { + "type": "field", + "inboundTag": [ + "external_router_web" + ], + "outboundTag": "portal" + }, + { + "type": "field", + "inboundTag": [ + "proxy_in" + ], + "outboundTag": "to_tokyo" + }, + { + "type": "field", + "inboundTag": [ + "interconn" + ], + "outboundTag": "portal" + }, + { + "type": "field", + "inboundTag": [ + "mihomo_in" + ], + "outboundTag": "to_tokyo" + } + ] + } +} \ No newline at end of file diff --git a/xray-旁路由-config.json b/xray-旁路由-config.json new file mode 100644 index 0000000..9d4e2e2 --- /dev/null +++ b/xray-旁路由-config.json @@ -0,0 +1,183 @@ +{ + "log": { + "loglevel": "info" + }, + "reverse": { + "bridges": [ + { + "tag": "bridge", + "domain": "reverse-proxy.xray.internal" + } + ] + }, + "outbounds": [ + { + "tag": "to_nas", + "protocol": "freedom", + "settings": { + "redirect": "192.168.1.188:9443" + } + }, + { + "tag": "to_siyuan", + "protocol": "freedom", + "settings": { + "redirect": "192.168.1.188:5005" + } + }, + { + "tag": "to_wsl", + "protocol": "freedom", + "settings": { + "redirect": "192.168.1.177:22" + } + }, + { + "tag": "to_nas_ssh", + "protocol": "freedom", + "settings": { + "redirect": "192.168.1.188:22" + } + }, + { + "tag": "to_router_ssh", + "protocol": "freedom", + "settings": { + "redirect": "192.168.1.199:22" + } + }, + { + "tag": "to_router_web", + "protocol": "freedom", + "settings": { + "redirect": "192.168.1.199:80" + } + }, + { + "tag": "to_minecraft", + "protocol": "freedom", + "settings": { + "redirect": "127.0.0.1:39132" + } + }, + { + "tag": "to_tmp", + "protocol": "freedom", + "settings": { + "redirect": "192.168.1.177:8501" + } + }, + { + "tag": "interconn", + "protocol": "vless", + "settings": { + "vnext": [ + { + "address": "salmonstill.cn", + "port": 443, + "users": [ + { + "id": "113e167a-a2be-4b46-9010-60020108626c", + "encryption": "none", + "flow": "xtls-rprx-vision" + } + ] + } + ] + }, + "streamSettings": { + "network": "raw", + "security": "reality", + "realitySettings": { + "show": false, + "fingerprint": "chrome", + "serverName": "www.apple.com", + "password": "62y5gDjPrdeuePGl-D2IW4Cw9Kb8_bSBBTmArvL7Nhs", + "shortId": "7c947a71b94f369e", + "spiderX": "/search?q=xray" + } + } + }, + { + "tag": "direct", + "protocol": "freedom" + } + ], + "routing": { + "rules": [ + { + "type": "field", + "inboundTag": [ + "bridge" + ], + "domain": [ + "full:reverse-proxy.xray.internal" + ], + "outboundTag": "interconn" + }, + { + "type": "field", + "inboundTag": [ + "bridge" + ], + "port": "38654", + "outboundTag": "to_siyuan" + }, + { + "type": "field", + "inboundTag": [ + "bridge" + ], + "port": "38655", + "outboundTag": "to_wsl" + }, + { + "type": "field", + "inboundTag": [ + "bridge" + ], + "port": "38656", + "outboundTag": "to_nas_ssh" + }, + { + "type": "field", + "inboundTag": [ + "bridge" + ], + "port": "38657", + "outboundTag": "to_router_ssh" + }, + { + "type": "field", + "inboundTag": [ + "bridge" + ], + "port": "8501", + "outboundTag": "to_tmp" + }, + { + "type": "field", + "inboundTag": [ + "bridge" + ], + "port": "39766", + "outboundTag": "to_router_web" + }, + { + "type": "field", + "inboundTag": [ + "bridge" + ], + "port": "39132", + "outboundTag": "to_minecraft" + }, + { + "type": "field", + "inboundTag": [ + "bridge" + ], + "outboundTag": "to_nas" + } + ] + } +} \ No newline at end of file diff --git a/东京-vps-stream.conf b/东京-vps-stream.conf new file mode 100644 index 0000000..6cdccc7 --- /dev/null +++ b/东京-vps-stream.conf @@ -0,0 +1,18 @@ +stream { + map $ssl_preread_server_name $backend { + www.microsoft.com xray; + default npm; + } + upstream xray { + server 127.0.0.1:9443; + } + upstream npm { + server 127.0.0.1:8443; + } + server { + listen 443 reuseport; + listen [::]:443 reuseport; + ssl_preread on; + proxy_pass $backend; + } +} diff --git a/我的世界udp转发.md b/我的世界udp转发.md new file mode 100644 index 0000000..9efd361 --- /dev/null +++ b/我的世界udp转发.md @@ -0,0 +1,245 @@ +# Minecraft 基岩版 UDP 转发配置文档 + +## 架构 + +``` +公网玩家 (UDP 19132) + ↓ +北京VPS (salmonstill.cn) +socat 监听 19132 → 转发到 10.0.0.2:19132 + ↓ WireGuard 隧道 +旁路由 ImmortalWrt (192.168.1.199 / 10.0.0.2) +nftables 端口转发 + SNAT + ↓ +NAS (192.168.1.188:19132) + ↓ +Minecraft 基岩版 Docker 容器 +``` + +--- + +## 设备信息 + +| 设备 | IP | 系统 | +|---|---|---| +| 北京VPS | `salmonstill.cn` / `49.232.242.90` | Ubuntu 22.04 | +| 旁路由 | `192.168.1.199` / WG隧道: `10.0.0.2` | ImmortalWrt 24.10 (GL-MT2500) | +| NAS | `192.168.1.188` | 绿联云 UGOS | + +--- + +## 第一部分:北京VPS 配置 + +### WireGuard 配置 `/etc/wireguard/wg0.conf` + +```ini +[Interface] +Address = 10.0.0.1/24 +ListenPort = 51820 +PrivateKey = <北京VPS私钥> +MTU = 1420 + +# 回包源地址转换(必须,否则公网玩家收不到回包) +PostUp = iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE +PostDown = iptables -t nat -D POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE + +[Peer] +# 旁路由 +PublicKey = 9jPlaUhx2Dc+C5ZqJx6Iu8GtNMig3cFIoqfHg8PZbCA= +AllowedIPs = 10.0.0.2/32 +PersistentKeepalive = 25 +``` + +> ⚠️ 不使用 iptables DNAT 转发,改用 socat 处理 UDP 转发,避免 conntrack 连接跟踪问题导致回包丢失。 + +### 开启内核转发 + +```bash +echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf +sysctl -p +``` + +### 开放防火墙端口 + +```bash +ufw allow 51820/udp # WireGuard +ufw allow 19132/udp # Minecraft 基岩版 +``` + +### 启动 WireGuard + +```bash +systemctl enable wg-quick@wg0 +systemctl start wg-quick@wg0 +``` + +### socat UDP 转发 + +socat 监听公网 19132 端口,收到包后转发给旁路由隧道 IP,并维护连接状态确保回包正确返回。 + +创建 systemd service: + +```bash +nano /etc/systemd/system/mc-forward.service +``` + +```ini +[Unit] +Description=Minecraft UDP Forward +After=network.target + +[Service] +ExecStart=/usr/bin/socat UDP4-LISTEN:19132,fork,reuseaddr UDP4:10.0.0.2:19132 +Restart=always + +[Install] +WantedBy=multi-user.target +``` + +启动并设置开机自启: + +```bash +systemctl daemon-reload +systemctl enable mc-forward +systemctl start mc-forward +``` + +--- + +## 第二部分:旁路由 ImmortalWrt 配置 + +### WireGuard 接口配置 + +路径:**网络 → 接口 → 添加新接口** + +**常规设置:** + +| 字段 | 值 | +|---|---| +| 接口名称 | `WireGuard` | +| 协议 | `WireGuard VPN` | +| 私钥 | `<旁路由私钥>` | +| IP 地址 | `10.0.0.2/24` | +| 监听端口 | 不填 | + +**防火墙设置:** 加入 `wan` 区域 + +**Peers → 添加对端:** + +| 字段 | 值 | +|---|---| +| 公钥 | `n159R7bNB+tW3Br0cok2zA27Pzg2WSPTI9uQ9odOFyU=` | +| 端点主机 | `salmonstill.cn` | +| 端点端口 | `51820` | +| 允许的 IP | `0.0.0.0/0` | +| 路由允许的 IP | ✅ 勾选 | +| 持续 Keep-Alive | `25` | + +> ⚠️ 允许的 IP 必须设为 `0.0.0.0/0`,否则 WireGuard 会丢弃来自公网玩家 IP 的包。 + +### 端口转发配置 + +路径:**网络 → 防火墙 → 端口转发 → 添加** + +| 字段 | 值 | +|---|---| +| 名称 | `Minecraft-udp` | +| 协议 | `UDP` | +| 源区域 | `wan` | +| 外部端口 | `19132` | +| 目标区域 | `lan` | +| 内部 IP 地址 | `192.168.1.188` | +| 内部端口 | `19132` | + +### SNAT 配置 + +路径:**网络 → 防火墙 → NAT 规则 → 添加** + +| 字段 | 值 | +|---|---| +| 名称 | `minecraft-snat` | +| 地址族限制 | `仅 IPv4` | +| 协议 | `UDP` | +| 出站区域 | `lan` | +| 目标地址 | `192.168.1.188` | +| 目标端口 | `19132` | +| 操作 | `SNAT - 重写为特定的源 IP 或端口` | +| 重写 IP 地址 | `192.168.1.199` | + +> SNAT 的作用:将转发给 NAS 的包源 IP 改为旁路由 IP,确保 NAS 的回包发回给旁路由而不是直接走主路由,避免回包路径不对称。 + +--- + +## 第三部分:NAS Docker 配置 + +使用 `network_mode: host` 避免 Docker NAT 导致的 IP 映射问题。 + +```yaml +services: + bedrock: + image: itzg/minecraft-bedrock-server:2026.2.1 + container_name: mc-bedrock + network_mode: host + stdin_open: true + tty: true + environment: + EULA: "TRUE" + VERSION: "1.26.14.1" + TZ: "Asia/Shanghai" + OPS: "2535472561115036" + volumes: + - /volume2/ProgramsV2/minecraft:/data + restart: unless-stopped +``` + +--- + +## 第四部分:验证 + +### 检查 WireGuard 隧道 + +```bash +# 旁路由 +wg show +# 正常应有 latest handshake 和双向 transfer +``` + +### 检查 socat 运行状态 + +```bash +systemctl status mc-forward +``` + +### 抓包验证完整链路 + +```bash +# VPS 上抓 wg0,确认双向流量 +tcpdump -i wg0 udp port 19132 -n + +# 旁路由抓 br-lan,确认转发到 NAS +tcpdump -i br-lan udp port 19132 -n + +# NAS 上抓包,确认收到并回包 +sudo tcpdump -i bridge0 udp port 19132 -n +``` + +--- + +## 故障排查 + +| 现象 | 排查方法 | +|---|---| +| WireGuard 无握手 | 检查 VPS 防火墙 51820/udp 是否开放 | +| socat 收不到包 | 检查 ufw 19132/udp 是否开放 | +| 旁路由收不到包 | 检查 WireGuard AllowedIPs 是否为 `0.0.0.0/0` | +| NAS 收不到包 | 检查端口转发内部端口是否填写正确 | +| NAS 有回包但玩家连不上 | 检查 SNAT 规则是否生效,确认 NAS 用 host 网络模式 | +| 游戏内延迟不显示 | 检查 socat 是否正常运行,DNAT 规则是否已删除 | + +--- + +## 扩展:新增其他 UDP 服务 + +1. VPS 新建一个 socat service,修改端口号 +2. 旁路由 LuCI 端口转发新增一条规则 +3. `ufw allow <新端口>/udp` diff --git a/旁路由备份/backup-ImmortalWrt-2026-04-17.tar.gz b/旁路由备份/backup-ImmortalWrt-2026-04-17.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..00323c447d13f7cb3585178f566e5db34c090f40 GIT binary patch literal 9716 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 CE0cvq6DSeTLf`uJKmAxIWDpVp~W^$ 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�S(SV1rFp)sc%NEHmjQX zZ&k+3?|{An%DTKEXiit1$YkF=2&%B?^b8D{{e2uA>3_oP$a^sNzl+cRGxk5l%JTmA zqw?JY?ikYsbm25sRThfRj{WJdDb@h`>d0 z>g0w4Fy&Qh0nodRUC+Z3Y#5HfC8tF~>h`Vfuk?=Wzd6lw$9~^!ApKXXx6yx<)4n+W zm&>KHiT3~H>T>^ol=Mv_;BdFAH~7{DA3Qpu9{;Ahekah$%{mkS#dpXk6hf80-VR-- zOBv7jAawll0X~c@04K}n>&XM*FB+anfH}VRUQY~IfCff>_bpGCHR z82V1qsA^I*7zLkvi^UD<7%iU57VxYSQp%f89x@t%qiYuT33FA{8mMB{i-uX2;K1T+{P_MYzlZHx>aTv%G%bvxv(nhV7?DTr?hp0E)AQ z%mZ|Nm1$(QAuQ@TI2vY&n$?<>vx;q+E4RzlT)kixa#eUeW)?Q8#j2fY9cxqH4ks8G z1)%tWPv@2Dc)=K+Uq>Fxg@f=qH*y)&$rQbr`hKa+d!ll0l5vhgYW16QM_a0Pk>^|E z=@n}a;fkr)4lHn#o_;K|=0b(qJ?s&hQ>8nsb2+w4c^COo0mybQ4Eob!qKha7CsrRe zG<`fC8`eO&s-G^X-U36hYH?EO?tVTC9Xh0EFTLDu@$g-FXIy{X-uTpRZg02xTjA)a zcG6>+)_Q!A93qUGT`$+Hn%Sk=bXjxaZ2`cyvBFSZax{{IH3pp^bEN^?#C@``-9r%t9+kWCfQ|j(k*MB{gxc4$h&%);wYyPC zZRHOQwg&~^dbiCK70pUmb_}7 zp2#SC>msm~ygJ0o3?bc&WE|u9oimtLEuAe4gWi~LLVf%bp?4{o(hDVmsaqoqMFscDKL)b+t2~$QY0C8CVJPE{edw97iLL2?vubY&7L?yB)M0!=O;0C5Dq5D35)@ z`9WC>kJ{+?@u!fC!r>W_=d(;(D&kf^bQ!EzpDF>qCsc4PWX%-VGbyH{4~&_CSEG=U56dtlb8V?zClxIcZFm4iO0RnERuzvXNfDb(w=yS=0`r<7GMdGk6o|m`| zN!ndkOE2Y@i?6?fRtsZjiDTb3}2zf@qLK;hC&wjc5{}GA_u(UdCYLRUOgBGsb(` zf4y_|d>sJ*LjxySZiF_nd`0=3cfigC1S|qRLMX+N>%b-^X*wTIxq)EyxaDN9d1L2d z6wz%?7nc^DOL)~0~Zp6><8G&!7zc2VVWcy{XVQn2(@Loamz zvnl}C*`!`twcY1L!GGe%Q96Sa{ZCx6;gNAJC zu5(9fX-GbFdmsANX9zRsuirs#~JRIAq^+6TKO`-9>kCn7K(Kn@dKrDg9{mb z+u-}L;#-2Ar{ZPCqtm0_0OMwQyuUsyJctfC2wZ+#fr1=6XvTwg$~!$?!bm_KB5%N( zZ5%?%Zy`f&CiVjnK@{I?!`=W_qM$!~-DZ0d3!KoCfz_q444T#-s?uZk${kS0wTvL_ zs=h;JKhDfn5$4#q)2m9<<4iQW?ICi` wNn+8{rWnb%>*F;!zLZh1fU+;ZL!n2zS(^DQ(=sj7GX0$NzlXKvVF20y0F2r)djJ3c literal 0 HcmV?d00001