本文由 简悦 SimpRead 转码, 原文地址 blog.csdn.net
目录
- 缘起
最近碰到了一个麻烦事情,就是公司的 centos 测试服务器放在内网环境,而且不能直接上外网,导致无法通过 yum 安装软件,非常捉急。
幸好,内网还是有可以可以访问外网的机器,所以就想到应该可以利用 nginx 搭建一个代理服务器,然后 centos 通过这个 nginx 来访问外网。当然,如果只是代理 http 还是很简单的,而要代理 https 还是需要稍费周折,因为 nginx 本身不能部署被代理的网站的证书,不能部署成 https 终结点来,因此与被代理客户端之间不能用 ssl 协议通讯,因此需要通过 http 协议中的 CONNECT 请求打通和外网的连接,然后客户端到 nginx 走明文,nginx 到外网走 https 协议。这里需要用到 ngx_http_proxy_connect_module 模块来实现 CONNECT 的代理功能。
- 部署 nginx
- 步骤 1: 从 nginx 官网下载 nginx 源码包。
- 步骤 2: 因为 nginx 原生是不支持 CONNECT 请求的,需要安装一个扩展插件,即 ngx_http_proxy_connect_module,从 github 下载 ngx_http_proxy_connect_module,另外还要下载一个 nginx 内核补丁。
- 步骤 3: 解压 nginx 源码包,进入 nginx 源码目录,创建 modules 目录(mkdir modules)。
- 步骤 4: 将 ngx_http_proxy_connect_module 源码目录放到 modules 目录中。
- 步骤 5: 将 nginx 内核补丁放到 nginx 源码目录,姑且名字叫 p1.patch
- 步骤 6: 在 nginx 源码目录,执行以下命令给 nginx 内核打上补丁:
patch -p 1 < p1.patch
- 步骤 7:编译 nginx,这里假设 nginx 安装到 / opt/nginx 目录中(在编译前确认 pcre、zlib、openssl 的库是否已经正常安装),编译命令如下:
./configure --prefix=/opt/nginx --with-http_ssl_module -add-module=./modules/ngx_http_proxy_connect_module
make & make install
- 步骤 8:配置 nginx
配置文件如下:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#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;
keepalive_timeout 65;
server {
# 代理端口
listen 8080;
server_name localhost;
# 解析被代理网站域名的dns服务器,根据实际情况自行配置
resolver 114.114.114.114;
# 开启proxy connect功能
proxy_connect;
# 设置允许代理的目标端口为443,即https的默认端口
proxy_connect_allow 443 80;
location / {
# 正向代理配置,根据请求地址自动解析出目标网站地址并进行代理
proxy_pass $scheme://$host$request_uri;
# 发送到被代理网站的请求需要添加host头
proxy_set_header Host $http_host;
proxy_buffers 256 4k;
proxy_max_temp_file_size 0;
proxy_connect_timeout 30;
}
}
}
以上配置完成后,通过 nginx 的 8080 端口,既可以代理普通 http 的请求,也可以代理 https 的请求。
- 步骤 9:启动 nginx
执行 / opt/nginx/sbin/nginx,启动 nginx
- 测试
3.1 http 测试
curl "http://www.baidu.com/" -x 127.0.0.1:8080 -v
响应内容:
* Trying 127.0.0.1:8080...
* Connected to (nil) (127.0.0.1) port 8080 (#0)
> GET http://www.baidu.com/ HTTP/1.1
> Host: www.baidu.com
> User-Agent: curl/7.81.0
> Accept: */*
> Proxy-Connection: Keep-Alive
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.24.0
< Date: Fri, 23 Feb 2024 09:08:01 GMT
< Content-Type: text/html
< Content-Length: 2381
< Connection: keep-alive
< Accept-Ranges: bytes
< Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
< Etag: "588604eb-94d"
< Last-Modified: Mon, 23 Jan 2017 13:28:11 GMT
< Pragma: no-cache
< Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
<
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form ></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" >更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a> <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a> 京ICP证030173号 <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
通过以上的输出可以看到 http 代理是没有通过 CONNECT 请求进行连接的,响应正常。
3.2 https 测试
curl "https://www.baidu.com/" -x 127.0.0.1:8080 -v
* Trying 127.0.0.1:8080...
* Connected to (nil) (127.0.0.1) port 8080 (#0)
* allocate connect buffer!
* Establish HTTP proxy tunnel to www.baidu.com:443
> CONNECT www.baidu.com:443 HTTP/1.1
> Host: www.baidu.com:443
> User-Agent: curl/7.81.0
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 200 Connection Established
< Proxy-agent: nginx
<
* Proxy replied 200 to CONNECT request
* CONNECT phase completed!
* ALPN, offering h2
* ALPN, offering http/1.1
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS header, Finished (20):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS header, Finished (20):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use http/1.1
* Server certificate:
* subject: C=CN; ST=beijing; L=beijing; O=Beijing Baidu Netcom Science Technology Co., Ltd; CN=baidu.com
* start date: Jul 6 01:51:06 2023 GMT
* expire date: Aug 6 01:51:05 2024 GMT
* subjectAltName: host "www.baidu.com" matched cert's "*.baidu.com"
* issuer: C=BE; O=GlobalSign nv-sa; CN=GlobalSign RSA OV SSL CA 2018
* SSL certificate verify ok.
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
> GET / HTTP/1.1
> Host: www.baidu.com
> User-Agent: curl/7.81.0
> Accept: */*
>
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
< Connection: keep-alive
< Content-Length: 2443
< Content-Type: text/html
< Date: Fri, 23 Feb 2024 09:11:25 GMT
< Etag: "58860410-98b"
< Last-Modified: Mon, 23 Jan 2017 13:24:32 GMT
< Pragma: no-cache
< Server: bfe/1.0.8.18
< Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
<
<!DOCTYPE html>
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" >登录</a>');
</script> <a href=//www.baidu.com/more/ >更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a> <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a> 京ICP证030173号 <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
通过以上的输出可以看到 https 代理是通过 CONNECT 请求进行连接的,中间有发生 ssl 的握手过程,也已经正常进行了响应。
4 给 centos 设置代理访问外网
给 centos 服务器设置两个 http_proxy 和 https_proxy 环境变量,假设 nginx 服务器的 ip 为 192.168.0.1,那么在命令行执行以下两条命令,即:
export http_proxy="http://192.168.0.1:8080"
export https_proxy="https://192.168.0.1:8080"
然后就可以顺畅地进行 yum 了。当然,如果可以的话,就将以上两条命令配置到 bash.rc 中,这样子免得每次登录都需要敲命令。