# 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 自己也配置了代理,测试直连/代理效果时要特别注意。