You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在主机上转发Docker容器的出站请求并修改HTTP请求头?

针对你这个Docker二进制应用没法修改源码、需要在主机内给出站请求添加FOO: bar头的场景,我整理了几个实操性强的方案,都是不需要改动应用本身的:

方案1:iptables 流量重定向 + mitmproxy 透明代理

这个方案是最通用的,不管容器有没有配置代理支持,都能拦截流量并修改请求头。

步骤:

  1. 安装并配置mitmproxy脚本
    先在主机上安装mitmproxy(Debian/Ubuntu用apt install mitmproxy,其他系统可以用pip install mitmproxy),然后写一个简单的脚本add_header.py来添加请求头:

    from mitmproxy import http
    
    def request(flow: http.HTTPFlow) -> None:
        # 给所有请求添加FOO头
        flow.request.headers["FOO"] = "bar"
    
  2. 启动透明模式的mitmproxy
    运行命令启动代理,指定刚才的脚本:

    mitmdump --mode transparent --script add_header.py
    

    默认mitmproxy会监听8080端口,用来接收重定向过来的流量。

  3. 配置iptables拦截Docker流量
    Docker默认用docker0网桥,我们需要把容器的出站HTTP/HTTPS流量重定向到mitmproxy的端口:

    # 开启IP转发(必须,否则流量无法正常转发)
    echo 1 > /proc/sys/net/ipv4/ip_forward
    # 永久生效的话,编辑/etc/sysctl.conf,设置net.ipv4.ip_forward=1,然后运行sysctl -p
    
    # 重定向HTTP流量(80端口)
    iptables -t nat -A PREROUTING -i docker0 -p tcp --dport 80 -j REDIRECT --to-port 8080
    # 重定向HTTPS流量(443端口)
    iptables -t nat -A PREROUTING -i docker0 -p tcp --dport 443 -j REDIRECT --to-port 8080
    
  4. 处理HTTPS证书信任问题
    如果你的应用会验证HTTPS证书,必须让容器信任mitmproxy的根证书:

    # 把mitmproxy的证书复制到容器里(替换your-container为你的容器名)
    docker cp ~/.mitmproxy/mitmproxy-ca-cert.pem your-container:/usr/local/share/ca-certificates/mitmproxy.crt
    # 在容器内更新证书缓存
    docker exec your-container update-ca-certificates
    

优点:无需修改容器配置,自动拦截所有Docker容器的出站流量;缺点:需要处理HTTPS证书信任,iptables规则需确保正确。

方案2:利用Docker代理环境变量(更优雅的针对性方案)

如果你的应用遵守标准的HTTP_PROXY/HTTPS_PROXY环境变量,这个方案更灵活,只针对特定容器生效,不用动iptables。

步骤:

  1. 在主机上启动代理服务
    同样可以用mitmproxy(步骤同方案1,不需要开启透明模式,普通模式即可)或者Nginx作为代理。比如用mitmproxy的普通模式:

    mitmdump --script add_header.py --listen-port 8080
    
  2. 启动容器时指定代理环境变量
    启动容器时添加代理变量,指向主机的代理端口(host.docker.internal是Docker内置的主机地址):

    docker run -e HTTP_PROXY=http://host.docker.internal:8080 \
               -e HTTPS_PROXY=http://host.docker.internal:8080 \
               your-app-image
    

    如果用docker-compose,就在environment字段添加:

    services:
      your-app:
        image: your-app-image
        environment:
          - HTTP_PROXY=http://host.docker.internal:8080
          - HTTPS_PROXY=http://host.docker.internal:8080
    
  3. HTTPS证书信任(同方案1)
    同样需要让容器信任mitmproxy的根证书,否则HTTPS请求会失败。

优点:只针对目标容器生效,配置简单;缺点:依赖应用支持代理环境变量,如果应用硬编码了请求逻辑不读这些变量,就没用。

方案3:socat + Nginx 反向代理(适合纯HTTP场景)

如果你的应用只走HTTP,不想用MITM代理,可以用socat转发流量到Nginx,由Nginx添加请求头。

步骤:

  1. 配置Nginx添加请求头
    新建Nginx配置文件/etc/nginx/conf.d/add_header.conf

    server {
        listen 8080;
        resolver 8.8.8.8; # 指定DNS服务器解析目标地址
    
        location / {
            proxy_pass http://$http_host$request_uri;
            proxy_set_header FOO "bar"; # 添加请求头
            proxy_set_header Host $http_host; # 保留原请求的Host头
        }
    }
    

    重启Nginx生效:systemctl restart nginx

  2. 用socat转发Docker的HTTP流量
    运行socat,监听docker0网桥上的80端口,把流量转发到Nginx的8080端口:

    socat TCP-LISTEN:80,bind=docker0,fork,reuseaddr TCP:127.0.0.1:8080
    

优点:不需要处理HTTPS证书问题;缺点:只支持HTTP流量,不如iptables方案灵活。

测试验证

不管用哪个方案,都可以在容器内用curl测试请求头是否添加成功:

docker exec your-container curl -v http://example.com

在输出里找> FOO: bar的字样,确认头已经被添加。

内容的提问来源于stack exchange,提问作者aug2uag

火山引擎 最新活动