Linode利用Nginx搭建透明代理

首先感谢小雨,在多年前帮我的博客捉虫之后,又给我带来了新玩法。如果以后定期来看看就更好了(当然,I don’t mind if you couldn’t do it)

其次,我们仅限讨论纯技术圈的内容,对于科学上网,相信大家都懂,本篇文章仅当抛砖引玉。

本篇文章是按照实验顺序写的,我是一边实验一边写这篇文章的,感觉这样学到的东西更多一些。

之前在网络上有很多人搭建代理,其实代理无非就那几种,当然随着技术手段的多样化,加密方式也同样迭代很多。之前接到这个题目做过一些research,但国外鬼佬网站多是关于反向代理的讨论,我在这里插一句,反向代理其实表面不多,其实行业内经常使用,例如澳大利亚很多政府网站(移民部的签证提交页面就是我当时注意到的第一个反向代理),另外很多云加速更是如此(例如大名鼎鼎的CloudFlare云加速,其实很多云加速归根结底宣传的优势都是反向代理与生俱来就拥有的,不足以过多炫耀……),原理也不比这篇文章介绍的复杂太多。

首先拿到一个VPS,假设已经安装好Nginx环境(我在这里省略这些步骤,具体安装方法请翻阅之前的文章),我的试验并不是搭建在Linode上的(这里有赚点击的嫌疑?),Anyway,是搭建在一个128M OpenVZ的VPS上(就靠Nginx如此高性能的服务器程序在这类VPS上发挥余热了,谁知道我这个服务商超售多少呢)。

言归正传,首先根据前辈的代码,进入 /etc/nginx/sites-available ,在default文件的合适位置粘贴以下代码,这里调试的端口是HTTP 8080 端口。我在中间注释了4行,原因是我暂时不需要考虑出错页面,这是代理嘛,暂时不考虑本地放置内容。

server {
listen 8080;

location / {
resolver 8.8.8.8;
proxy_pass http://$http_host$uri$is_args$args;
}

#error_page 500 502 503 504 /50x.html;
#location = /50x.html {
#root html;
#}
}

然后我们 sudo service nginx restart 重启nginx服务器,一般不会出错就对了。我们直接可以浏览器访问VPS的8080端口看效果,会提示 504 Gateway Time-out 错误,这证明端口已经打开。我们可以直接设置浏览器的代理登录IP查询网站查看IP是否有变化。

如果有问题,还可以用命令: netstat -an | egrep ‘Proto|LISTEN’ 查看开放端口,注意防火墙响应设置应当放行。

Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN
tcp 0 0 198.IP地址隐藏:53 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.2:53 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:53 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:953 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:3389 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:587 0.0.0.0:* LISTEN
tcp6 0 0 :::80 :::* LISTEN
tcp6 0 0 :::53 :::* LISTEN
tcp6 0 0 :::22 :::* LISTEN
tcp6 0 0 ::1:953 :::* LISTEN
tcp6 0 0 :::3389 :::* LISTEN
tcp6 0 0 :::445 :::* LISTEN
tcp6 0 0 :::139 :::* LISTEN
Proto RefCnt Flags Type State I-Node Path
unix 2 [ ACC ] STREAM LISTENING 3626180 /var/run/sendmail/mta/smcontrol
unix 2 [ ACC ] STREAM LISTENING 3623127 /var/run/saslauthd/mux

上面的设置有明显问题,其一是没有限制,很容易被监听公开到代理网站上,并导致VPS超高流量。其二,没有SSL协议,一切都是浮云啊。

我们先解决SSL的问题,为了图方便,我们直接用服务器生成自签名证书吧!(直接搬运的现成代码,原谅我吧,非root记得前面加sudo)

cd /etc/nginx/
mkdir SSL
cd SSL
openssl genrsa -des3 -out server.key 1024
openssl req -new -key server.key -out server.csr
cp server.key server.key.org
openssl rsa -in server.key.org -out server.key
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

然后代码就变成了这样拼凑的结果:

server {
listen 这里填服务器独立IP:443;
ssl on;
ssl_certificate /etc/nginx/SSL/server.crt;
ssl_certificate_key /etc/nginx/SSL/server.key;
server_name proxy.bjdch.org;
location / {
resolver 8.8.8.8;
proxy_pass https://$http_host$uri$is_args$args;
}
}

以上这段代码MARK备用,貌似不是很管用,暂时先考虑443明文吧,突破局域网封锁。

明文代码443突破封锁就比较简单了:

server {
listen 443;

location / {
resolver 8.8.8.8;
proxy_pass http://$http_host$uri$is_args$args;
}

#error_page 500 502 503 504 /50x.html;
#location = /50x.html {
#root html;
#}
}

至此,客户端已经完全可以访问到,IE稍微设置下就可以实现内外网分离,唯一开放的443端口可以用于标准HTTP代理,SSL直接通过原生端口使用,不走代理。

当然,自己开的代理当然不希望被其他网站嗅探到变成对公众开放的服务器(不是我没有共享精神,资源流量伤不起啊),可以添加IP地址列表过滤,简单暴力。同时再增加点资源方面的限制。

server {
allow 这里填写真实IP1;
allow 这里填写真实IP2;
deny all;
listen 0.0.0.0:443;
proxy_set_header HOST $http_host;
proxy_buffers 256 4k;
proxy_max_temp_file_size 0k;
proxy_connect_timeout 30;
proxy_send_timeout 60;
location / {
resolver 8.8.8.8;
access_log /var/log/nginx/proxy.log;
proxy_pass $scheme://$http_host$uri$is_args$args;
}
}

第一阶段任务完成了,VPS终于通过Nginx变成了专属代理。

References:

https://ef.gy/using-nginx-as-a-proxy-server

https://blog.akendo.eu/debiannginx-with-ssl/