Nginx做正向代理

近日,朋友在公司摸鱼时发现笔记本在使用公司的WI-FI后无法进入B站。于是乎在群里“拍了拍”我。本着科技服务生活的精神,我欣然地接受了这个请求 😀

“请求中…“

使用Nginx在我的云服务器(国内节点)上搭了个正向代理服务器,笔记本的浏览器只需将代理服务器IP和代理端口设置为云服务器外网IP和Nginx里配置的监听端口即可。详细过程如下:

登陆云服务器(我的是CentOS 7.x),下载Nginx的tar包:

# 进入登陆账号的home目录下,我的是/home/robin
cd ~
# 下载Nginx tar包
wget http://nginx.org/download/nginx-1.18.0.tar.gz
# 解压tar包
tar -zxvf nginx-1.18.0.tar.gz && cd nginx-1.18.0

安装预编译环境:

#升级所有包同时也升级软件和系统内核
sudo yum update
# 安装依赖环境
sudo yum -y install gcc pcre pcre-devel zlib zlib-devel openssl openssl-devel

Nginx作为反向代理服务器,官方一直没有支持HTTP CONNECT方法。但是基于Nginx的模块化、可扩展性好的特性,阿里的@chobits提供了ngx_http_proxy_connect_module模块,来支持HTTP CONNECT方法,从而让Nginx可以扩展为正向代理。使用此模块需要pcre环境,如果没安装pcre,在后面的make命令执行后,会有缺少pcre的报错信息。

ngx_http_proxy_connect_module克隆至服务器上:

# 进入登陆账号的home目录下,我的是/home/robin
cd ~
# 克隆项目至本地
git clone https://github.com/chobits/ngx_http_proxy_connect_module.git

模块克隆好后,需要根据Nginx的版本给最初的文件(最初的文件是:/home/robin/ngx_http_proxy_connect_module/ngx_http_proxy_connect_module.c)打补丁,我的Nginx是1.19.0,所以打的补丁版本如下红框:

Nginx版本对应的补丁

先安装打补丁的工具:

sudo yum install patch

再打补丁:

# 进入Nginx目录下
cd ~/nginx-1.18.0
# 打补丁
patch -p1 < /home/robin/ngx_http_proxy_connect_module/patch/proxy_connect_rewrite_1018.patch

在Nginx目录下执行如下命令:

# 进入Nginx目录下
cd ~/nginx-1.18.0
# 配置Nginx的目录和模块
./configure \
--user=www \
--group=www \
--prefix=/usr/local/nginx \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-threads \
--add-module=/home/robin/ngx_http_proxy_connect_module
# 编译
sudo make
# 安装
sudo make install

在/usr/local/nginx/conf/nginx.conf的http块中加入下面一段server块:

http块中的server块

代码如下:

server {
listen 443;
  # dns resolver used by forward proxying
  resolver 8.8.8.8;
 
  # forward proxy for CONNECT request
  proxy_connect; 
  proxy_connect_allow 443;
  proxy_connect_connect_timeout 10s;
  proxy_connect_read_timeout 10s;
  proxy_connect_send_timeout 10s;
  # forward proxy for non-CONNECT request
  location / {
  proxy_pass http://$host;
  proxy_set_header Host $host;
  }
}

启动Nginx:

# 保存退出
:wq
# 启动Nginx
cd /usr/local/nginx/sbin/ && sudo ./nginx

在我的macbook终端做测试(*.*.*.*为我的云服务器外网IP):

curl https://www.baidu.com -svo /dev/null -x *.*.*.*:443
About to connect() to proxy *.*.*.* port 443 (#0)
Trying *.*.*.*…
Connected to *.*.*.* (*.*.*.*) port 443 (#0)
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.29.0
Proxy-Connection: Keep-Alive
< HTTP/1.1 200 Connection Established
< Proxy-agent: nginx
<
Proxy replied OK to CONNECT request
Initializing NSS with certpath: sql:/etc/pki/nssdb
CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
Server certificate:
subject: CN=baidu.com,O="Beijing Baidu Netcom Science Technology Co., Ltd",OU=service operation department,L=beijing,ST=beijing,C=CN

GET / HTTP/1.1
User-Agent: curl/7.29.0
Host: www.baidu.com
Accept: /
< HTTP/1.1 200 OK

{ [data not shown]

从上面-v参数打印出的细节,可以看到客户端先往代理服务器*.*.*.*建立了HTTP CONNECT隧道,代理回复HTTP/1.1 200 Connection Established后就开始交互TLS/SSL握手和流量了。

下面以谷歌浏览器插件配置代理服务器为例,其他浏览器请读者自行查找配置代理服务器的方法。

代理服务器为我的云服务器外网IP
启动代理

至此,我的朋友已经可以在他的笔记本通过我搭的正向代理服务器访问各种墙内的网站了。至此,读者可能以为问题被解决了,但,B站依旧访问不到。所以B站网址应该在更底层的网络层被限制了。所以看到这的读者就当作增加一些奇怪的知识吧 😀

文章参考来源「使用NGINX作为HTTPS正向代理服务器」