• Nginx正向代理


    使用 Nginx 搭建 HTTPS 正向代理服务
    NGINX 搭建 HTTP 正向代理

    最近帮同事搭建一个代理服务器,要求当请求的请求头中包含dest_ip时,就将请求转发到这个目的地址,否则就正常请求。当自己用下面这种方式很快就实现 HTTP 正向代理,信心满满的交给同事使用时,却发现这种配置无法正常代理 HTTPS 请求。

    location / {
        if ($http_dest_ip != "") {
            proxy_pass http://$http_dest_ip/$request_uri;
        }
        proxy_pass https://$http_host$request_uri;
    }
    

    NGINX 代理 HTTPS 请求时 access 日志:

    192.168.73.26 - - [06/Dec/2018:19:42:27 +0800] "CONNECT acs.m.taobao.com:443 HTTP/1.1" 400 179 "-" "-" "-"
    192.168.73.26 - - [06/Dec/2018:19:42:27 +0800] "CONNECT acs.m.taobao.com:443 HTTP/1.1" 400 179 "-" "-" "-"
    192.168.73.26 - - [06/Dec/2018:19:42:27 +0800] "CONNECT acs.m.taobao.com:443 HTTP/1.1" 400 179 "-" "-" "-"
    

    NGINX 的error 日志:

    2018/12/06 19:42:27 [info] 79953#1783043: *16 client sent invalid request while reading client request line, client: 192.168.73.26, server: localhost, request: "CONNECT gw.alicdn.com:443 HTTP/1.1"
    2018/12/06 19:42:27 [info] 79953#1783043: *17 client sent invalid request while reading client request line, client: 192.168.73.26, server: localhost, request: "CONNECT gw.alicdn.com:443 HTTP/1.1"
    2018/12/06 19:42:27 [info] 79953#1783043: *18 client sent invalid request while reading client request line, client: 192.168.73.26, server: localhost, request: "CONNECT acs.m.taobao.com:443 HTTP/1.1"
    

    为什么 NGINX 不能做 HTTPS 正向代理服务器

    HTTPS 现在已经被大范围的使用在网络数据安全传输领域,基于 HTTPS 的浏览器和服务器之间通信都是被加密的。所以,当浏览器通过代理发送一个 HTTPS 请求时,请求的地址和端口也是被加密的,代理服务器也无法知道这些信息。那么代理是如何知道请求是发到哪里呢?为了解决这个问题,浏览器会先发送一个明文的 HTTP 协议的 CONNECT 请求给代理服务器,告诉代理请求的目的地址和端口。CONNECT 请求的内容格式如下:

    CONNECT ***:443 HTTP/1.1
    Host: bayden.com:443
    Connection: keep-alive
    User-Agent: Chrome/47.0.2526.58
    

    收到这个请求后,代理会和目标服务器建立一个 TCP 连接,并返回一个 HTTP 200 的响应给浏览器,告诉浏览器自己和目标服务器的 TCP 连接已建立。响应格式如下:

    HTTP/1.1 200 Connection Established
    Connection: close
    

    之后,代理只会透明的来回传输浏览器和服务器之间经过 SSL 加密的数据包,并不知道也不需要知道传输的实际内容,直接通道关闭。

    出现以上异常的具体原因是 NGINX 本身的设计就是作为一个反向代理服务器,而非正向代理服务器,并且在短期也没有打算支持正向代理,所以现在 NGINX 并不支持 CONNECT 请求方式,因此收到“CONNECT ***:443 HTTP/1.1”请求时会报“client sent invalid request while reading client request line”异常。这种情况并不是说 NGINX 无法处理 SSL,只是作为一个 forward proxy 不行。
    安装扩展模块

    那如何让 NGINX 可以正向代理 HTTPS 请求呢?我们需要借助一个第三方扩展模块 ngx_http_proxy_connect_module 来让 NGINX 支持 CONNECT 请求,建立一个 SSL 请求的通道。

    ngx_http_proxy_connect_module 安装方式:

    $ wget http://Nginx.org/download/Nginx-1.9.2.tar.gz
    $ tar -xzvf Nginx-1.9.2.tar.gz
    $ cd Nginx-1.9.2/
    $ patch -p1 < /path/to/ngx_http_proxy_connect_module/patch/proxy_connect.patch
    $ ./configure --add-module=/path/to/ngx_http_proxy_connect_module
    $ make && make install
    

    其中 “/path/to” 为 proxy_connect.patch 文件在服务器的存放地址。需要注意的是,对于使用 Mac 的同学,我目前还没有找到使用 brew install nginx 的方式安装 ngx_http_proxy_connect_module 扩展的方法。

    编译安装完 ngx_http_proxy_connect_module 扩展模块后,使用如下配置即可以使 NGINX 正常代理 HTTPS 请求。

    NGINX HTTPS 代理完整配置:

    http {
        ...    
        resolver 8.8.8.8; # DNS 服务器可根据实际情况单独配置
        ...
    
        server {
            listen       80;
            server_name  proxy_server;
            ...
    
            proxy_connect;
            proxy_connect_allow all;
            proxy_connect_connect_timeout 10s;
            proxy_connect_read_timeout 10s;
            proxy_connect_send_timeout 10s;
    
            location / {
                proxy_pass http://$host;
                proxy_set_header Host $host;
            }
    

    NGINX proxy for docker

    当然,如果你会使用 docker,那么可以直接使用已经编译了 ngx_http_proxy_connect_module 模块的 NGINX 镜像 Nginx forward proxy 快速搭建一个 HTTPS正向代理服务器。

    wget http://software.yangyijing.cn/software/ngx_http_proxy_connect_module.tar.gz
    

    Dockerfile

    FROM alpine:3.9
    ENV NGINX_VERSION 1.15.12
    
    # https://github.com/chobits/ngx_http_proxy_connect_module下载的主分支包
    #  wget http://software.yangyijing.cn/software/ngx_http_proxy_connect_module.tar.gz
    ADD ngx_http_proxy_connect_module.tar.gz /opt/
    
    RUN GPG_KEYS=B0F4253373F8F6F510D42178520A9993A1C052F8 
    	&& CONFIG="
    		--prefix=/etc/nginx 
    		--sbin-path=/usr/sbin/nginx 
    		--modules-path=/usr/lib/nginx/modules 
    		--conf-path=/etc/nginx/nginx.conf 
    		--error-log-path=/var/log/nginx/error.log 
    		--http-log-path=/var/log/nginx/access.log 
    		--pid-path=/var/run/nginx.pid 
    		--lock-path=/var/run/nginx.lock 
    		--http-client-body-temp-path=/var/cache/nginx/client_temp 
    		--http-proxy-temp-path=/var/cache/nginx/proxy_temp 
    		--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp 
    		--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp 
    		--http-scgi-temp-path=/var/cache/nginx/scgi_temp 
    		--user=nginx 
    		--group=nginx 
    		--with-http_ssl_module 
    		--with-http_realip_module 
    		--with-http_addition_module 
    		--with-http_sub_module 
    		--with-http_dav_module 
    		--with-http_flv_module 
    		--with-http_mp4_module 
    		--with-http_gunzip_module 
    		--with-http_gzip_static_module 
    		--with-http_random_index_module 
    		--with-http_secure_link_module 
    		--with-http_stub_status_module 
    		--with-http_auth_request_module 
    		--with-http_xslt_module=dynamic 
    		--with-http_image_filter_module=dynamic 
    		--with-http_geoip_module=dynamic 
    		--with-threads 
    		--with-stream 
    		--with-stream_ssl_module 
    		--with-stream_ssl_preread_module 
    		--with-stream_realip_module 
    		--with-stream_geoip_module=dynamic 
    		--with-http_slice_module 
    		--with-mail 
    		--with-mail_ssl_module 
    		--with-compat 
    		--with-file-aio 
    		--with-http_v2_module 
    		# 对应上面添加的模块目录
                    --add-module=/opt/ngx_http_proxy_connect_module 
    	" 
    	&& addgroup -S nginx 
    	&& adduser -D -S -h /var/cache/nginx -s /sbin/nologin -G nginx nginx 
    	&& apk add --no-cache --virtual .build-deps 
    		gcc 
    		libc-dev 
    		make 
    		openssl-dev 
    		pcre-dev 
    		zlib-dev 
    		linux-headers 
    		curl 
    		gnupg1 
    		libxslt-dev 
    		gd-dev 
    		geoip-dev 
    		# 编译ngx_http_proxy_connect_module依赖的
                    patch 
                    pcre 
                    zlib 
    	&& curl -fSL https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz -o nginx.tar.gz 
    	&& curl -fSL https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz.asc  -o nginx.tar.gz.asc 
    	&& export GNUPGHOME="$(mktemp -d)" 
    	&& found=''; 
            for server in 
    		ha.pool.sks-keyservers.net 
    		hkp://keyserver.ubuntu.com:80 
    		hkp://p80.pool.sks-keyservers.net:80 
    		pgp.mit.edu 
    	; do 
    		echo "Fetching GPG key $GPG_KEYS from $server"; 
    		gpg --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$GPG_KEYS" && found=yes && break; 
    	done; 
    	test -z "$found" && echo >&2 "error: failed to fetch GPG key $GPG_KEYS" && exit 1; 
    	gpg --batch --verify nginx.tar.gz.asc nginx.tar.gz 
    	&& rm -rf "$GNUPGHOME" nginx.tar.gz.asc 
    	&& mkdir -p /usr/src 
    	&& tar -zxC /usr/src -f nginx.tar.gz 
    	&& rm nginx.tar.gz 
    	&& cd /usr/src/nginx-$NGINX_VERSION 
            # 对应版本的patch文件
            && patch -p1 < /opt/ngx_http_proxy_connect_module/patch/proxy_connect_rewrite_101504.patch 
    	&& ./configure $CONFIG --with-debug 
    	&& make -j$(getconf _NPROCESSORS_ONLN) 
    	&& mv objs/nginx objs/nginx-debug 
    	&& mv objs/ngx_http_xslt_filter_module.so objs/ngx_http_xslt_filter_module-debug.so 
    	&& mv objs/ngx_http_image_filter_module.so objs/ngx_http_image_filter_module-debug.so 
    	&& mv objs/ngx_http_geoip_module.so objs/ngx_http_geoip_module-debug.so 
    	&& mv objs/ngx_stream_geoip_module.so objs/ngx_stream_geoip_module-debug.so 
    	&& ./configure $CONFIG 
    	&& make -j$(getconf _NPROCESSORS_ONLN) 
    	&& make install 
    	&& rm -rf /etc/nginx/html/ 
    	&& mkdir /etc/nginx/conf.d/ 
    	&& mkdir -p /usr/share/nginx/html/ 
    	&& install -m644 html/index.html /usr/share/nginx/html/ 
    	&& install -m644 html/50x.html /usr/share/nginx/html/ 
    	&& install -m755 objs/nginx-debug /usr/sbin/nginx-debug 
    	&& install -m755 objs/ngx_http_xslt_filter_module-debug.so /usr/lib/nginx/modules/ngx_http_xslt_filter_module-debug.so 
    	&& install -m755 objs/ngx_http_image_filter_module-debug.so /usr/lib/nginx/modules/ngx_http_image_filter_module-debug.so 
    	&& install -m755 objs/ngx_http_geoip_module-debug.so /usr/lib/nginx/modules/ngx_http_geoip_module-debug.so 
    	&& install -m755 objs/ngx_stream_geoip_module-debug.so /usr/lib/nginx/modules/ngx_stream_geoip_module-debug.so 
    	&& ln -s ../../usr/lib/nginx/modules /etc/nginx/modules 
    	&& strip /usr/sbin/nginx* 
    	&& strip /usr/lib/nginx/modules/*.so 
    	&& rm -rf /usr/src/nginx-$NGINX_VERSION 
    	
    	# Bring in gettext so we can get `envsubst`, then throw
    	# the rest away. To do this, we need to install `gettext`
    	# then move `envsubst` out of the way so `gettext` can
    	# be deleted completely, then move `envsubst` back.
    	&& apk add --no-cache --virtual .gettext gettext 
    	&& mv /usr/bin/envsubst /tmp/ 
    	
    	&& runDeps="$( 
    		scanelf --needed --nobanner --format '%n#p' /usr/sbin/nginx /usr/lib/nginx/modules/*.so /tmp/envsubst 
    			| tr ',' '
    ' 
    			| sort -u 
    			| awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' 
    	)" 
    	&& apk add --no-cache --virtual .nginx-rundeps $runDeps 
    	&& apk del .build-deps 
    	&& apk del .gettext 
    	&& mv /tmp/envsubst /usr/local/bin/ 
    	
    	# Bring in tzdata so users could set the timezones through the environment
    	# variables
    	&& apk add --no-cache tzdata 
    	
    	# forward request and error logs to docker log collector
    	&& ln -sf /dev/stdout /var/log/nginx/access.log 
    	&& ln -sf /dev/stderr /var/log/nginx/error.log
    EXPOSE 80
    STOPSIGNAL SIGTERM
    CMD ["nginx", "-g", "daemon off;"]
    

    nginx配置文件

    resolver 8.8.8.8;
        server {
            listen       80;
            server_name  185.184.223.120;
            proxy_connect;
            proxy_connect_allow all;
            proxy_connect_connect_timeout 600s;
            proxy_connect_read_timeout 600s;
            proxy_connect_send_timeout 600s;
    
            location / {
                proxy_pass http://$host;
                proxy_set_header Host $host;
            }
    }
    

    原创文章,如需转载,请注明来自:https://bigzuo.github.io/

  • 相关阅读:
    将自己写的经常复用的类封装成dll/lib的方法
    Mat 和 CvMat,IplImage相互转化
    制作VB安装程序问答(Package & Deployment)
    NTDDI_VERSION,_WIN32_WINNT,WINVER,_WIN32_IE定义宏的含义
    解决"cvCreateVideoWriter保存视频帧压缩格式只能用1"的问题
    100条道理,看完后请留下你的感言
    世界上最著名的24幅奇图
    字节对齐
    齐次坐标的理解
    在OpenCV中自适应确定canny算法的分割门限
  • 原文地址:https://www.cnblogs.com/yangtao416/p/14694605.html
Copyright © 2020-2023  润新知