需求
内网的机器无法访问互联网,但是有些业务服务必须要上网,这个时候就需要一个正向代理,将正向代理部署在一台可以上网的机器,业务应用通过正向代理去访问互联网,同时使用正向代理控制上网策略和权限。
什么是正向代理?
正向代理就是客户端client知道服务器server的地址,也知道proxy的地址,但是client通过proxy,并且告诉proxy,我要访问server的地址,proxy将请求直接转发到server。正向代理最常见的应用是VPN,用来突破client到server的网络限制。
与之对应的就是反向代理,反向代理是client不知道server的地址,但知道proxy的地址,client请求proxy,proxy根据配置的规则转发给server,这里client是不知道具体server的地址,都是通过proxy里的规则进行转发。反向代理最常见的工具就是Nginx。
我现在需要在linux服务器上做正向代理,查了下可以用的工具Squid,Nginx。作为研发来说,Squid比较陌生,nginx那是经常打交道,那就用nginx来搭建了。(nginx是反向代理的代表,其实也可以用来做正向代理)
nginx搭建正向代理
简单介绍下nginx做正向代理的原理,在nginx的配置中加上 resolver 8.8.8.8,其他配置通用,就可以做正向代理了,而这个配置的作用是:指定固定的DNS服务器,而8.8.8.8是Google提供的全球DNS服务器。这样就可以把请求直接转到Google的DNS服务器,然后DNS直接转发出去。完整配置如下:
ini
worker_processes 3;
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 $request_body "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" "$request_time"';
access_log /etc/nginx/logs/access.log main;
sendfile on;
server {
listen 10080; # 代理监听的端口
proxy_connect;
server_name *.com;
proxy_max_temp_file_size 0;
resolver 8.8.8.8; # DNS 解析器,使用 Google 的公共 DNS
# 处理所有 HTTP 请求
location / {
proxy_pass http://$http_host;
proxy_set_header Host $http_host;
proxy_ssl_server_name on;
proxy_ssl_session_reuse off;
proxy_next_upstream error timeout invalid_header http_502;
proxy_buffer_size 4k; # 调整缓冲区大小
proxy_buffers 4 8k;
proxy_busy_buffers_size 16k;
}
}
}
将nginx运行起来之后,可以直接用curl进行测试代理是否正常,脚本如下:
rust
curl --proxy "http://xx.xx.xx.xx:xx" 'http://www.baidu.com'
如无意外的情况下,可以得到正常返回了。但是我把http改成https之后,立马就返回400 bad request了。这时候可能以为是配置出问题了,其实是nginx代理并不支持https的正向代理转发,搞了半天,不支持https,有点扎心,那么nginx能否支持https的正向代理呢?答案是可以的。
github上有个大神,写了个ngx_http_proxy_connect_module(github.com/chobits/ngx...),用来解决nginx代理无法转发https的问题。可以参照文档内容将模块编译到nginx中。当然如果你觉得这样比较麻烦的话,有更简单的方法。我现在运维部署一些开源软件时,基本都是用docker去部署的,使用docker部署的好处我就不在这里赘述了。那现在我就介绍一下使用docker部署nginx的方式。
首先我们就是找一个已经编译了ngx_http_proxy_connect_module的nginx打包好的镜像,我用的是这个:github.com/reiz/nginx_...。部署就简单了,docker-compose文件如下
yaml
version: '2'
services:
nginx:
image: reiz/nginx_proxy:0.0.5
container_name: proxy_nginx
restart: always
ports:
- '10080:10080'
environment:
- TZ=Asia/Shanghai
volumes:
- ./nginx.conf:/usr/local/nginx/conf/nginx.conf
- ./logs:/etc/nginx/logs
接下来是nginx.conf:
ini
daemon off;
worker_processes auto;
events {
worker_connections 1024;
}
http {
server_names_hash_bucket_size 128;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent $request_body "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" "$request_time"';
access_log /etc/nginx/logs/access.log;
error_log /etc/nginx/logs/error.log;
sendfile on;
keepalive_timeout 65;
server {
listen 10080;
#server_name *.com;
proxy_connect;
resolver 8.8.8.8 ipv6=off;
location / {
proxy_pass http://$http_host;
proxy_set_header Host $http_host;
}
}
}
nginx.conf可以配置访问的地址和禁止访问的地址,及其他的配置,可以看作者的使用文档。
问题
Cannot assign requested address
在连续请求的时候,有一半的请求会报无法分配地址,这个问题还挺棘手,最后发现是ipv6的问题,要关闭ipv6才行,resolver 8.8.8.8 ipv6=off; 关闭了之后就没有出现这个问题。