Ubuntu Xray 透明代理容器
这个目录构造的是一个基于 ubuntu:24.04 的测试/编译容器。容器启动后由 s6-overlay 管理 Xray,并用 iptables 把容器内部 IPv4 TCP 出站流量透明转发到 Xray。
推荐使用 .env + Docker Compose 测试:
docker compose --env-file .env -f compose.yml run --rm proxy-on
总览
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 启动和进程维护。
镜像构造
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]
文件职责
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 生成,并先写入临时文件,成功后再原子替换目标文件。当前不是通用转换器,只支持下面两类链接:
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 服务脚本。
启动生命周期
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
配置选择逻辑
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 里配置:
XRAY_URL=vless://...
高级方式是挂载完整 JSON:
-v D:\path\config.json:/etc/xray/config.json:ro
如果挂载了 /etc/xray/config.json,它会优先于 XRAY_URL。
透明代理数据路径
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
关键点:
- 默认只处理 IPv4 TCP。
- 使用
nat OUTPUT,影响容器内部进程发起的出站连接。 xray用户自己的流量会被RETURN排除,避免代理流量再次进入代理导致死循环。- 默认关闭 IPv6,设置
XRAY_IPV6_ENABLED=1才保留 IPv6。 - UDP 透明代理没有实现;如果需要 UDP,要改成 TPROXY + 策略路由。
环境变量
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
1 启动 Xray 和透明代理,默认值
0 不启动 Xray,用于 proxy-off 对比测试
XRAY_URL
传入受支持的 vless://...,容器自动生成 Xray JSON 配置。
XRAY_IPV6_ENABLED
0 默认值,启动时尽量关闭容器 IPv6
1 保留 IPv6
XRAY_DEBUG_CONFIG
0 默认值,不打印生成的 Xray JSON
1 打印生成的 Xray JSON,仅用于调试
XRAY_CONFIG
默认:
/etc/xray/config.json
XRAY_TRANSPARENT
1 设置 iptables 透明代理,默认值
0 只启动 Xray,不设置透明转发
XRAY_REDIRECT_PORT
默认:
12345
测试
运行:
Ubuntu\test.bat
测试脚本流程:
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[对比结果]
也可以手动运行:
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 日志里应该出现:
[transparent >> proxy]
这说明流量经过 Xray。
proxy-off 应该看到:
Xray disabled by XRAY_ENABLED=0.
如果当前网络允许直连,proxy-off 会输出:
[INFO] HTTP request without xray succeeded directly
如果当前网络不允许直连,proxy-off 会输出:
[PASS] HTTP request without xray is blocked
测试脚本内部使用:
curl --noproxy '*' -I -L http://google.com
这是为了避免 HTTP_PROXY、HTTPS_PROXY、Docker Desktop 代理设置污染测试。
注意事项
运行透明代理必须加:
--cap-add NET_ADMIN
否则容器内没有权限设置 iptables。
Windows 开启系统代理时,Docker Desktop/WSL 可能继承代理设置。可以用这些命令只读检查:
docker info
netsh winhttp show proxy
Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' |
Select-Object ProxyEnable,ProxyServer,AutoConfigURL
如果 docker info 里出现类似:
HTTP Proxy: http.docker.internal:3128
HTTPS Proxy: http.docker.internal:3128
说明 Docker Desktop 自己也配置了代理,测试直连/代理效果时要特别注意。