Files

363 lines
9.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Ubuntu Xray 透明代理容器
这个目录构造的是一个基于 `ubuntu:24.04` 的测试/编译容器。容器启动后由 `s6-overlay` 管理 Xray,并用 `iptables` 把容器内部 IPv4 TCP 出站流量透明转发到 Xray。
推荐使用 `.env` + Docker Compose 测试:
```bat
docker compose --env-file .env -f compose.yml run --rm proxy-on
```
## 总览
```mermaid
flowchart LR
Env[.env: XRAY_URL] --> Compose[Docker Compose]
Compose --> Container[Ubuntu 容器]
Container --> S6[s6-overlay /init]
S6 --> Init[cont-init.d 初始化]
Init --> Config[生成或读取 Xray 配置]
Init --> IPv6[默认关闭 IPv6]
Init --> Iptables[设置 IPv4 iptables 透明代理]
Init --> Service[按需创建 xray 服务]
S6 --> Xray[监督 xray longrun]
App[容器内命令 / 编译任务 / curl] --> Iptables
Iptables --> Xray
Xray --> Remote[VLESS 节点]
```
核心目标是:你只在 `.env` 里提供 `XRAY_URL=vless://...`,容器自己完成配置生成、透明代理设置、Xray 启动和进程维护。
## 镜像构造
```mermaid
flowchart TD
Base[ubuntu:24.04] --> Mirror[替换 apt 源为中科大镜像]
Mirror --> Packages[安装 curl / iptables / jq / unzip / xz-utils]
Packages --> S6Install[安装 s6-overlay]
S6Install --> XrayInstall[下载并安装 Xray-core]
XrayInstall --> User[创建 xray 系统用户]
User --> CopyScripts[复制运行时 scripts/]
CopyScripts --> CopyRootfs[复制 rootfs/]
CopyRootfs --> Entry[ENTRYPOINT /init]
```
## 文件职责
```mermaid
flowchart TD
Ubuntu[Ubuntu/] --> EnvFile[.env]
Ubuntu --> ComposeFile[compose.yml]
Ubuntu --> Dockerfile[Dockerfile]
Ubuntu --> EnvExample[.env.example]
Ubuntu --> Test[test.bat]
Ubuntu --> Scripts[scripts/]
Ubuntu --> Rootfs[rootfs/]
Scripts --> Resolve[resolve-xray-config.sh]
Scripts --> Convert[xray-url-to-config.sh]
Scripts --> Transparent[transparent-proxy.sh]
Scripts --> IPv6[ipv6-mode.sh]
Scripts --> Enable[enable-xray-service.sh]
Scripts --> Run[xray-service-run.sh]
Rootfs --> Init[etc/cont-init.d/]
Rootfs --> Finish[etc/cont-finish.d/]
Init --> InitIPv6[05-ipv6-mode]
Init --> InitConfig[10-xray-config]
Init --> InitProxy[20-transparent-proxy]
Init --> InitService[30-enable-xray-service]
Finish --> Cleanup[90-transparent-proxy-cleanup]
```
`.env`
运行时配置文件。默认包含 `IMAGE``XRAY_URL``XRAY_IPV6_ENABLED``XRAY_DEBUG_CONFIG`。真实 `.env` 不入库,使用 `.env.example` 复制后填写真实节点。
`.env.example`
可提交的配置模板,不包含真实节点密钥。
`compose.yml`
定义测试服务和运行时环境。测试命令由 `test.bat` 传入,不再维护额外的测试 runner 文件。
`Dockerfile`
构建镜像,安装依赖、s6-overlay、Xray,并设置 `ENTRYPOINT ["/init"]`
`test.bat`
本地测试脚本。调用 Docker Compose 构建镜像,并依次运行 IPv6 与代理开关测试。
`scripts/xray-url-to-config.sh`
把受支持的 `vless://...` 转换成 Xray JSON 配置,写到 `/tmp/xray.generated.json`。配置由 `jq` 生成,并先写入临时文件,成功后再原子替换目标文件。当前不是通用转换器,只支持下面两类链接:
```text
vless + tcp + reality + flow=xtls-rprx-vision + headerType=none
vless + ws + security=none + host + path
```
其他组合会直接报错,不会尝试生成可能错误的配置。
`scripts/resolve-xray-config.sh`
决定使用哪个配置。如果 `/etc/xray/config.json` 存在,就使用它;否则尝试从 `XRAY_URL` 自动生成。
`scripts/transparent-proxy.sh`
负责 `iptables` 透明代理规则的 `setup``cleanup`
`scripts/ipv6-mode.sh`
默认关闭容器内 IPv6。设置 `XRAY_IPV6_ENABLED=1` 时保留 IPv6。
`scripts/enable-xray-service.sh`
根据 `XRAY_ENABLED` 决定是否创建 `/etc/services.d/xray/run`。关闭代理时不会创建空跑的 xray 服务。
`scripts/xray-service-run.sh`
真正的 Xray s6 longrun 服务脚本。
## 启动生命周期
```mermaid
sequenceDiagram
participant Docker
participant S6 as s6-overlay /init
participant Init as cont-init.d
participant Scripts as scripts/
participant Xray as xray service
participant Cmd as CMD
participant Finish as cont-finish.d
Docker->>S6: 启动 /init
S6->>Init: 05-ipv6-mode
Init->>Scripts: ipv6-mode.sh
S6->>Init: 10-xray-config
Init->>Scripts: resolve-xray-config.sh
S6->>Init: 20-transparent-proxy
Init->>Scripts: transparent-proxy.sh setup
S6->>Init: 30-enable-xray-service
Init->>Scripts: enable-xray-service.sh
S6->>Xray: 启动动态创建的 xray/run
S6->>Cmd: 执行 Docker CMD
Xray-->>S6: 如果崩溃,s6 自动重启
Cmd-->>S6: CMD 结束
S6->>Finish: 执行 cleanup
Finish->>Scripts: transparent-proxy.sh cleanup
```
## 配置选择逻辑
```mermaid
flowchart TD
Start[启动 Xray 配置解析] --> HasFile{XRAY_CONFIG 文件存在?}
HasFile -->|是| UseFile[使用 /etc/xray/config.json]
HasFile -->|否| HasUrl{XRAY_URL 是否存在?}
HasUrl -->|是| Generate[从 vless URL 生成临时 JSON]
HasUrl -->|否| Fail[启动失败: 缺少配置]
Generate --> Supported{链接类型受支持?}
Supported -->|是| Service[创建并启动 xray 服务]
Supported -->|否| FailType[启动失败: 不支持的链接类型]
UseFile --> Service
```
推荐方式是在 `.env` 里配置:
```env
XRAY_URL=vless://...
```
高级方式是挂载完整 JSON
```bat
-v D:\path\config.json:/etc/xray/config.json:ro
```
如果挂载了 `/etc/xray/config.json`,它会优先于 `XRAY_URL`
## 透明代理数据路径
```mermaid
flowchart LR
App[容器内普通进程] -->|访问外部 IPv4 TCP| Output[iptables nat OUTPUT]
Output -->|REDIRECT| Door[dokodemo-door 127.0.0.1:12345]
Door --> Xray[Xray]
Xray -->|VLESS| Server[远端代理节点]
Server --> Internet[目标网站]
Xray -. xray 用户流量排除 .-> Output
```
关键点:
1. 默认只处理 IPv4 TCP。
2. 使用 `nat OUTPUT`,影响容器内部进程发起的出站连接。
3. `xray` 用户自己的流量会被 `RETURN` 排除,避免代理流量再次进入代理导致死循环。
4. 默认关闭 IPv6,设置 `XRAY_IPV6_ENABLED=1` 才保留 IPv6。
5. UDP 透明代理没有实现;如果需要 UDP,要改成 TPROXY + 策略路由。
## 环境变量
```mermaid
flowchart TD
Env[.env / compose environment] --> Enabled[XRAY_ENABLED]
Env --> Url[XRAY_URL]
Env --> Config[XRAY_CONFIG]
Env --> Transparent[XRAY_TRANSPARENT]
Env --> Port[XRAY_REDIRECT_PORT]
Env --> IPv6[XRAY_IPV6_ENABLED]
Env --> Debug[XRAY_DEBUG_CONFIG]
Enabled --> EnabledDesc[1 启动代理 / 0 完全关闭]
Url --> UrlDesc[vless:// 链接]
Config --> ConfigDesc[默认 /etc/xray/config.json]
Transparent --> TransparentDesc[1 设置 iptables / 0 不设置]
Port --> PortDesc[默认 12345]
IPv6 --> IPv6Desc[0 默认关闭 IPv6 / 1 保留 IPv6]
Debug --> DebugDesc[1 打印生成配置]
```
`XRAY_ENABLED`
```text
1 启动 Xray 和透明代理,默认值
0 不启动 Xray,用于 proxy-off 对比测试
```
`XRAY_URL`
传入受支持的 `vless://...`,容器自动生成 Xray JSON 配置。
`XRAY_IPV6_ENABLED`
```text
0 默认值,启动时尽量关闭容器 IPv6
1 保留 IPv6
```
`XRAY_DEBUG_CONFIG`
```text
0 默认值,不打印生成的 Xray JSON
1 打印生成的 Xray JSON,仅用于调试
```
`XRAY_CONFIG`
默认:
```text
/etc/xray/config.json
```
`XRAY_TRANSPARENT`
```text
1 设置 iptables 透明代理,默认值
0 只启动 Xray,不设置透明转发
```
`XRAY_REDIRECT_PORT`
默认:
```text
12345
```
## 测试
运行:
```bat
Ubuntu\test.bat
```
测试脚本流程:
```mermaid
flowchart TD
Build[docker compose build] --> On[proxy-on]
On --> OnRun[读取 .env 并启用透明代理]
OnRun --> OnCurl[curl google.com]
OnCurl --> Off[proxy-off]
Off --> OffRun[XRAY_ENABLED=0]
OffRun --> OffCurl[curl google.com]
OffCurl --> Compare[对比结果]
```
也可以手动运行:
```bat
docker compose --env-file .env -f compose.yml build
docker compose --env-file .env -f compose.yml run --rm --no-deps proxy-on bash
docker compose --env-file .env -f compose.yml run --rm --no-deps proxy-off bash
```
`proxy-on` 日志里应该出现:
```text
[transparent >> proxy]
```
这说明流量经过 Xray。
`proxy-off` 应该看到:
```text
Xray disabled by XRAY_ENABLED=0.
```
如果当前网络允许直连,`proxy-off` 会输出:
```text
[INFO] HTTP request without xray succeeded directly
```
如果当前网络不允许直连,`proxy-off` 会输出:
```text
[PASS] HTTP request without xray is blocked
```
测试脚本内部使用:
```sh
curl --noproxy '*' -I -L http://google.com
```
这是为了避免 `HTTP_PROXY``HTTPS_PROXY`、Docker Desktop 代理设置污染测试。
## 注意事项
运行透明代理必须加:
```text
--cap-add NET_ADMIN
```
否则容器内没有权限设置 `iptables`
Windows 开启系统代理时,Docker Desktop/WSL 可能继承代理设置。可以用这些命令只读检查:
```powershell
docker info
netsh winhttp show proxy
Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' |
Select-Object ProxyEnable,ProxyServer,AutoConfigURL
```
如果 `docker info` 里出现类似:
```text
HTTP Proxy: http.docker.internal:3128
HTTPS Proxy: http.docker.internal:3128
```
说明 Docker Desktop 自己也配置了代理,测试直连/代理效果时要特别注意。