Nginx https代理在阿里云SDK中的应用

背景

在国内访问海外阿里云SDK时,经常超时,而且丢包严重;现象如下:


image.png

为了解决这个问题,尝试在香港搭建Nginx代理,通过代理来访问海外地址

Nginx代理

HTTP代理

首先是搭建Nginx代理,为了快速验证代理的可行性,先以代理HTTP为例进行验证;

Nginx的部署我这里是直接容器部署的,然后给他挂载一个简单的配置文件来负载默认的配置文件

user  root;
worker_processes  auto;

#error_log  logs/error.log notice;
#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    gzip  on;

        upstream ap_southeast_5 {
                server 149.129.204.7:443 weight=1;
                server 147.139.128.4:443 weight=1;
        }


          server {
        listen 32880;
        proxy_connect;
        proxy_connect_allow            443 563;
        proxy_connect_connect_timeout  10s;
        proxy_connect_read_timeout     10s;
        proxy_connect_send_timeout     10s;

        # forward proxy for non-CONNECT request
        location / {
            proxy_set_header Host $http_host;
            proxy_pass http://ap_southeast_5;
        }
    }

}

在这份配置文件中,Nginx监听的是32880端口,然后将收到的所有请求直接转到阿里云雅加达的SDK站点地址

然后写个简单的单元测试验证下代理的可行性

@Test
    public void testListRegions() throws Exception {
        Config config = new Config();
        config.setAccessKeyId(accessKey);
        config.setAccessKeySecret(secretKey);
        config.setRegionId("ap-southeast-5");
        config.setProtocol("http");
        config.setHttpProxy("http://ng-ip:28089");

        com.aliyun.ecs20140526.Client client = new com.aliyun.ecs20140526.Client(config);

        com.aliyun.ecs20140526.models.DescribeRegionsRequest request = new DescribeRegionsRequest();
        request.setResourceType("instance");

        DescribeRegionsResponse response = client.describeRegionsWithOptions(request, new RuntimeOptions());

        log.info("Done");
    }

示例中的ng-ip替换为实际的Nginx运行IP即可,上述单元测试是可以正常跑通的。

这里吐槽下,最初我还以为是需要设置服务端点为代理地址即可,可是这样是不行的,因为阿里云SDK会把Header中的host作为鉴权签名内容的一部分,直接设置端点的话会引起签名错误

config.setEndpoint("http://ng-ip:28089");
image.png
image.png

抓包后可以看到Nginx代理上收到的包和发出去的包host变了,因此会引起签名错误;阿里云文档上没有找到相关的使用说明。

HTTPS代理

HTTP跑通之后,再来看看代理HTTPS请求,添加Nginx配置文件

        server {
                listen       28444 ssl;
                 proxy_connect;
            proxy_connect_allow            443 563;
            proxy_connect_connect_timeout  10s;
            proxy_connect_read_timeout     10s;
            proxy_connect_send_timeout     10s;                 
         
                #ssl on;
                ssl_certificate      /data/nginx/cert/xx.com/xx.com.crt;
                ssl_certificate_key  /data/nginx/cert/xx.com/xx.com.key;
              ssl_protocols        SSLv3 TLSv1.1 TLSv1.2 TLSv1.3;
             ssl_ciphers          HIGH:!aNULL:!MD5;


                location / {
                   proxy_set_header Host $http_host;
                   proxy_pass https://slb.ap-southeast-5.aliyuncs.com;
                }

        }

添加的配置让Nginx通过https方式监听在28444 端口

然后修改示例代码:

@Test
    public void testListRegions() throws Exception {
        Config config = new Config();
        config.setAccessKeyId(accessKey);
        config.setAccessKeySecret(secretKey);
        config.setRegionId("ap-southeast-5");
        config.setHttpsProxy("https://ng-ip:28444");

        com.aliyun.ecs20140526.Client client = new com.aliyun.ecs20140526.Client(config);

        com.aliyun.ecs20140526.models.DescribeRegionsRequest request = new DescribeRegionsRequest();
        request.setResourceType("instance");

        // size: 30
        DescribeRegionsResponse response = client.describeRegionsWithOptions(request, new RuntimeOptions());

        log.info("Done");
    }

这次却怎么都不成功,一直报错CONNECT 400,抓包之后可以看到客户端发出的请求仍然是HTTP类型的,正常来讲应该是TLS才对

image.png

看了下SDK代码后,发现他们使用的是okhttp作为客户端发送代理请求的,于是乎,搜了下okhttp proxy https,找了一圈后,在okhttp的 issue里找到这个问题:https://github.com/square/okhttp/issues/6561

发现使用okhttp代理https时需要设置socketFactory,而阿里云SDK里没有入口可以设置这个参数,重写SDK的部分代码后,并引入这个类:https://github.com/square/okhttp/blob/480c20e46bb1745e280e42607bbcc73b2c953d97/okhttp/src/test/java/okhttp3/DelegatingSocketFactory.java

设置上了socketFactory后,确实没有报错CONNECT 400了,但是这次又开始报错CONNECT 502

一番折腾后,发现示例代码里的配置需要调整

Config config = new Config();
        config.setAccessKeyId(accessKey);
        config.setAccessKeySecret(secretKey);
        config.setRegionId("ap-southeast-5");
        config.setProtocol("http");
        config.setHttpsProxy("https://ng-ip:28444");

需要设置协议为HTTP,这次终于不报错了,虽然这里设置了协议是http,但是抓包你会发现协议是TLS,至此才终于解决了这个问题。

Nginx forward https

上述为了简化问题,没有特别说明Nginx也是需要重新编译的,参考文档的说明:
https://stackoverflow.com/questions/46330313/nginx-ssl-forward-proxy-config

Nginx默认不支持转发HTTPS,因为不支持CONNECT方法;

为此需要添加ngx_http_proxy_connect_module模块,参考地址为:

https://github.com/chobits/ngx_http_proxy_connect_module?tab=readme-ov-file#install

如果是容器版本的,可以参考:
https://docs.getconvoy.io/product-manual/forward-proxies/nginx

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,376评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,126评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,966评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,432评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,519评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,792评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,933评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,701评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,143评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,488评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,626评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,292评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,896评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,324评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,494评论 2 348

推荐阅读更多精彩内容

  • 默认nginx是不支持https的正向代理的,要想通过nginx的正向代理,作为https服务器,需要增加一个模块...
    chnmagnus阅读 10,496评论 0 4
  • 首先大家应该会用到过nginx做http的代理,这种情况网络上搜一下大把大把的文章都按照步骤都能做出http的代理...
    Sheeper丶阅读 17,273评论 3 4
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,629评论 18 139
  • 正向代理:局域网中的客户端不能直接访问Internet,则需要通过代理服务器来访问,这种代理服务就称为正向代理。N...
    andycheng阅读 9,684评论 1 3
  • 安装代理模块 nginx 官方没有支持正向代理的模块,只能通过加载第三方模块[https://github.com...
    薄荷盐阅读 1,785评论 0 1