nginx反代google

一键部署xx之类的脚本使用有风险,试想一下脚本弄出异常的'sudo rm -rf /'就让VPS挂掉的情形。。因为已经有前车之鉴,不敢再偷懒,自己实践下反代过程也不错哦!

提示:此文于2016年撰写,信息已过时,博主不再更新,请不要过度参考。

nginx

目的是编译带有以下模块的nginx,实现正则表达式匹配谷歌的地址

模块 功能
ngx_http_google_filter_module google反代
ngx_http_substitutions_filter_module 正则表达式

获取module

cd /root && mkdir ng && cd ng
git clone https://github.com/cuber/ngx_http_google_filter_module
git clone https://github.com/yaoweibin/ngx_http_substitutions_filter_module

安装module依赖

apt install libpcre3-dev libssl-dev zlib1g-dev libxslt1-dev libgd-dev libgeoip-dev

编译nginx

nginx download page下载需要的版本,以1.10.1为例

wget http://nginx.org/download/nginx-1.10.1.tar.gz
tar xf nginx-1.10.1.tar.gz
cd nginx-1.10.1

configure参数填入,再加上两个Module,生成Makefile

./configure \
--with-cc-opt='-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2' \
--with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro' \
--prefix=/usr/share/nginx \
--conf-path=/etc/nginx/nginx.conf \
--with-debug \
--with-pcre-jit \
--with-ipv6 \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-http_auth_request_module \
--with-http_addition_module \
--with-http_dav_module \
--with-http_geoip_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_image_filter_module \
--with-http_v2_module \
--with-http_sub_module \
--with-http_xslt_module \
--with-stream \
--with-stream_ssl_module \
--with-threads \
--add-module=../ngx_http_google_filter_module \
--add-module=../ngx_http_substitutions_filter_module

若外置openssl,使用这个参数

--with-openssl=../openssl-1.1.0c

*PS:*这个configure参数是从apt install nginx后执行nginx -V得到的,根据个人需要编译模块

没有问题就编译安装吧

make -j2
make install

看看nginx模块是否正确,方法是看configure末尾是否有ngx_http_google_filter_module

nginx -V
# 若command not found可以创建符号链接
# ln -s /usr/share/nginx/sbin/nginx /usr/sbin/nginx

然后配置一下网站,看看是否能从外网打开本机网站

vi /etc/nginx/nginx.conf
# 修改server_name为自己的域名
nginx -s reload

最后,记得添加开机启动,写入.bashrc脚本或者rc.local脚本

/usr/sbin/nginx

Let's Encrypt证书

生成私鈅

挑选一个合适的letsencrypt客户端(网上大约有十多种),我以这个acme-tiny为例

cd /root/ng
git clone https://github.com/diafygi/acme-tiny
cd acme-tiny	

生成自己用于续证书有效期的私钥,用于let's Encrypt识别你的个人身份,需要妥善保管,不能与下面的domain.key混用。

openssl genrsa 4096 > account.key

生成 CSR(Certificate Signing Request,证书签名请求)

1.先生成RSA私钥,用于生成CSR(实际中可以选用ECC私钥)

openssl genrsa 4096 > domain.key

2.接下来生成CSR文件

# 单域名
openssl req -new -sha256 -key domain.key -subj "/CN=MY_DOMAIN.COM" > domain.csr

# 多域名(use this one if you want both MY_DOMAIN.COM and WWW.MY_DOMAIN.COM)
openssl req -new -sha256 -key domain.key -subj "/" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:MY_DOMAIN.COM,DNS:WWW.MY_DOMAIN.COM")) > domain.csr

签发证书

Let's Encrypt 在你的服务器上生成一个随机验证文件,再通过创建 CSR 时指定的域名访问,如果可以访问则表明你对这个域名有控制权。验证通过才允许下一步签证书。

创建用于存放验证文件的目录,不能用root权限的目录,建议使用nginx的www目录下(貌似权限是www-data?)

mkdir /var/www/challenges/

往nginx配置一个HTTP服务器,用于验证let's Encrypt域名所有权, 添加前请注释掉之前已经存在的监听80端口的服务器

vi /etc/nginx/nginx.conf
# http标签内
server {
    server_name MY_DOMAIN.COM;
    listen 80;
    # ipv6
    # listen [::]:80;

    location ^~ /.well-known/acme-challenge/ {
        alias /var/www/challenges/;
        try_files $uri =404;
    }
}

重载服务

nginx -s reload

这个验证服务以后(比如三个月后)更新证书还要用到,建议一直保留。

有了验证服务器,就可以验证域名并签发证书了。

cd /root/ng/acme-tiny
# 注意验证目录是/var/www/challenges,与上面mkdir一致
python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir /var/www/challenges/ > ./signed.crt

提示*Certificate signed!*就可以生成一个singed.crt网站证书。

接下来还要下载 Let's Encrypt 的中间证书,配置 HTTPS 证书时既不要漏掉中间证书,也不要包含根证书。在 Nginx 配置中,需要把中间证书和网站证书合在一起

wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > intermediate.pem
cat signed.crt intermediate.pem > chained.pem

续证书脚本

创建 renew_cert.sh 并通过 chmod a+x renew_cert.sh 赋予执行权限

#! /bin/bash

export ACME_TINY_DIR=/root/ng/acme-tiny

cd $ACME_TINY_DIR && python acme_tiny.py --account-key account.key --csr domain.csr --acme-dir /var/www/challenges/ > signed.crt || exit
cd $ACME_TINY_DIR && wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > intermediate.pem
cd $ACME_TINY_DIR && cat signed.crt intermediate.pem > chained.pem
cd $ACME_TINY_DIR && wget -O - https://letsencrypt.org/certs/isrgrootx1.pem > root.pem
cd $ACME_TINY_DIR && cat intermediate.pem root.pem > full_chained.pem

nginx -s reload || echo "renew fail"

写入crontab,定期执行续证书脚本(比如每个月20号续一次)

反代google

vi /etc/nginx/nginx.conf
# http标签内加入一个HTTPS服务器
server {
    server_name MY_DOMAIN.COM;
    listen 443;
    # ipv6
    # listen [::]:443;

    ssl on;
    # specify your cert location
    ssl_certificate /root/ng/acme-tiny/chained.pem;
    ssl_certificate_key /root/ng/acme-tiny/domain.key;

    resolver 8.8.8.8;
    location / {
        google on;
        google_scholar on;
        google_language "en";
    }
    
    # forbid search engine spider
    if ($http_user_agent ~* "qihoobot|Baiduspider|Googlebot|Googlebot-Mobile|Googlebot-Image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo! Slurp|Yahoo! Slurp China|YoudaoBot|Sosospider|Sogou spider|Sogou web spider|MSNBot|ia_archiver|Tomato Bot"){
        return 403;
    }
    
    # not allow robots
    location /robots.txt {
        add_header Content-Type text/plain;
        return 200 "User-agent: *\nDisallow: /\n";
    }
    
    # forbid illegal domain request
    if ( $host != $server_name ) {
        return 403;
    }
}

这样可以实现反代了,重载nginx看看效果

nginx -s reload

其它设置

nginx权限

默认是nobody权限执行nginx,建议指定nginx的执行者为www-data

vi /etc/nginx/nginx.conf
user=www-data

因为用到的proxy模块,需要更改proxy module的拥有者为www-data

chown -R www-data:www-data /var/lib/nginx/proxy

ssl安全设置

这个设置不是必要的,但是我看到SSL Lab对我的网站https评分仅有B等级,安全性不足,需要设定更好的密钥交换机制。

当然,尽量使用最新的Nginx,保证安全性,编译nginx也尽量使用指定模块最新源码的方式进行编译,堵住0day。

以下ssl设置均在http-server(HTTPS)标签内进行修改

在其listen 443改为

listen 443 ssl http2 fastopen=2 reuseport;

开启OCSP

先把根证书和中间证书合在一起

cd /root/ng/acme-tiny
wget -O - https://letsencrypt.org/certs/isrgrootx1.pem > root.pem
cat intermediate.pem root.pem > full_chained.pem

在nginx配置中指定ssl_stapling

ssl_stapling               on;
ssl_stapling_verify        on;
ssl_trusted_certificate    /root/ng/acme-tiny/full_chained.pem;

指定加密算法

ssl_ciphers                EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers  on;
ssl_protocols              TLSv1 TLSv1.1 TLSv1.2;

超时等

ssl_session_cache          shared:SSL:50m;
ssl_session_timeout        1d;
ssl_session_tickets        on;

# openssl rand 48 > session_ticket.key
# 单机(standalone)部署可以不指定 ssl_session_ticket_key
# ssl_session_ticket_key     /root/ng/acme-tiny/session_ticket.key;

经过以上ssl设置,我的网站安全等级上升到A级,有些许提升。

设置上游ip

防止谷歌认为你是机器人,要求输入验证码

在vps上面多次执行以下命令获得不同的ip(至少能获取3个吧,多一些比较好)

dig google.com +short @8.8.8.8
dig google.com +short @208.67.222.222

对每一个dns结果进行ping测试,选择延迟低的dns结果,按权重放入upstream标签内

vi /etc/nginx/nginx.conf
# http标签内加入upstream上游
upstream www.google.com{
    server 216.58.217.206:443 weight=34;
    server 172.217.4.142:443 weight=33;
    server 216.58.193.206:443 weight=33;
}

限制连接数

设置同一个ip访问本站频率,防止滥用,具体数值根据服务负荷设置

这里设置某个ip频率每秒10次请求,并发burst最多允许50:效果可以从打开“谷歌图片”搜索一个关键词,看加载图片速度中体会得到。被限制的请求将返回503错误

# http标签内加入setlimit
limit_req_zone $binary_remote_addr zone=setfreq:10m rate=10r/s;
limit_req zone=setfreq burst=50 nodelay;

http重定向

设置http访问后重定向为baidu.com(纯属恶搞,专门对付那些不开https的人)

# http-server(HTTP)标签内加入rewrite
location / {
    # change to your target website
    rewrite ^/(.*)$ http://www.baidu.com permanent;
}

如果不恶搞,同理可以rewrite为https,达到http跳转https目的

rewrite ^/(.*)$ https://$host/$1 permanent;

TCP优化设置

vi /etc/nginx/nginx.conf
# http标签内修改
sendfile           on;
tcp_nopush         on;
tcp_nodelay        on;
keepalive_timeout  60;

# gzip压缩(可选)
gzip               on;
gzip_vary          on;
gzip_comp_level    6;
gzip_buffers       16 8k;
gzip_min_length    1000;
gzip_proxied       any;
gzip_disable       "msie6";
gzip_http_version  1.0;
gzip_types         text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;

nginx缓存

参考ngx_http_proxy_module官方手册有关缓存的设置。

首先mkdir几个文件夹/etc/nginx/cache/one、two、three。

vi /etc/nginx/nginx.conf
# http标签内,这里定义了三个zone,后面google实际上只用到一个zone(two)
proxy_cache_path  /etc/nginx/cache/one    levels=1      keys_zone=one:10m;
proxy_cache_path  /etc/nginx/cache/two    levels=2:2    keys_zone=two:10m;
proxy_cache_path  /etc/nginx/cache/three  levels=1:1:2  keys_zone=three:10m;

# 缓存有效时间
proxy_cache_valid  200 302 10m;
proxy_cache_valid  301 30m;
proxy_cache_valid  any 1m;

# http->server标签内,加入允许缓存,zone名字为two
location / {
    proxy_cache two;
    google on;
}

这样每次请求谷歌的结果都缓存在nginx服务器内,减少VPS与谷歌的通信次数。

需要定期清理缓存,nginx没有自动清理缓存的功能,可以向crontab写入定时任务清理缓存。

find /etc/nginx/cache/ -type f -delete

后记

设置到这里就可以使用反代了,建议搭建后域名不要公开使用,亲友几个人使用还是没问题的,人多了你的ip或者域名容易被GFW认证,最后只能更换VPS或者域名。

谷歌反代教程来源于项目ngx_http_google_filter_module的wiki,证书的获取方法参考了Let's Encrypt,免费好用的 HTTPS 证书,至于nginx的HTTPS安全部份则参考了Nginx 配置之完整篇。经过本人实践记录下来而成。附上自己的配置文件nginx.conf,可以参考一下。

另外有个不依赖http_google_filter_module的纯nginx配置文件nginx.conf,实际上这个conf更具有一般性,读懂它配置,理论上可以代理任意网站,例如草榴。

文中的MY_DOMAIN.COM即自己的域名,注意替换