nginx反代cloudflare加速网站访问

这篇文章不涉及重写url的部分,即反代使用的域名和源站使用的域名相同,只有国内会解析到反代服务器上,国外访问网站依旧直接走cloudflare->源站。dnspod使得我们可以使用相同的域名分别连接反代服务器与cloudflare服务器,所以不会有下一篇文章中的host不匹配问题。

前言

最近看见一台配置相当不错的欧洲服务器,于是买了下来并把网站迁移了上去,没想到配置确实是不错,但是到大陆的网络连接就一言难尽了,四处绕路、环球旅行都是常见的情况,并且丢包率相当惊人。不过配合cloudflare自选节点还是勉强可以一用的,甚至某些地区的访问还挺不错,关于cloudflare如何自选节点请查看这篇文章

但是cloudflare自选节点只能指定一个大概的方向,可能一个ip对于某些地方的运营商是不错的线路,但是到了另外一些地方,依旧是绕路的,并且到了晚上依旧十分爆炸。这两天,校园网突然变成了移动出口,我算是体验到了移动用户的痛苦,到了晚上,虽然经过自选节点网站走的是香港cloudflare节点,但是打开速度依旧缓慢,有时候光是握手都要花费很长的时间,忍无可忍!于是我想着有没有什么办法能够加速一下大陆地区的访问呢?经过挂上香港的代理测试,香港打开这个网站的速度还是挺快的,说明源站在欧洲并不是什么大问题,主要还是cloudflare到大陆太堵了。于是我想着能不能通过反向代理的方式来加速一下大陆地区的访问呢?这样,用一个亚太地区的低配置(高配置机器太贵了,所以买了欧洲的)好线路的vps就可以极大的提升大陆地区用户访问我的网站的体验了。
由于最近太穷了,也找不到什么好线路的机器,所以我暂时先使用了吃灰中的谷歌云。

贴一张图,看看反代后的效果(不过gcp最近挺炸的,真要用的话还是建议找一个三网cn2的香港机器来反代):
image1e3f946afb1aa3b4.png

思路介绍

先大致说一下我的操作思路,使用dnspod智能解析,境外依旧走cloudflare的cdn,而对于大陆地区则解析到香港的谷歌云上,谷歌云再反向代理cloudflare的ip,并带上主机名(host)即可(当然也可以直接反向代理到源站)。

实际操作

默认你已经使用dnspod之类的智能解析并用了cname接入cloudflare,不过即使你没用cdn也可以继续看下去,到时候反代的时候直接用源站ip即可。

配置证书

首先我们要为用于反代的香港gcp配置证书,我们要在dnspod里面添加一条A记录,并把境外的请求都解析到香港gcp上(应为let's encrypt的验证服务器在国外),等待一会,当你看见境外的服务器解析此ip能解析到你的反代机器上时就可以了。

/etc/nginx/sites-enable/下新建一个站点文件,就叫reverse吧,注意修改成你的站点域名。

server {
    if ($host = notesail.com) {
        return 301 https://$host$request_uri;
    }
        listen 80;
        listen [::]:80;
        root /var/www/html;
        index index.html index.htm index.nginx-debian.html;
        server_name notesail.com;
        location / {
                try_files $uri $uri/ =404;
        }
}

server {

        root /var/www/html;
        index index.html index.htm index.nginx-debian.html;
        server_name notesail.com;

        location / {
           proxy_ssl_name notesail.com;
           proxy_ssl_server_name on;
           proxy_set_header  Host  notesail.com;
           proxy_set_header  X-real-ip $remote_addr;
           proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_redirect off;
           proxy_pass https://1.0.0.1;
           proxy_set_header Upgrade $http_upgrade;
           proxy_set_header Connection "upgrade";

        }
    listen [::]:443 ssl;
    listen 443 ssl;
}

这里先解释一下里面几个关键的点,把反代部分单独拿出来看。

        location / {
           proxy_ssl_name notesail.com;
           proxy_ssl_server_name on;
           proxy_set_header  Host  $http_host;
           proxy_set_header  X-real-ip $remote_addr;
           proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_redirect off;
           proxy_pass https://1.0.0.1;
           proxy_set_header Upgrade $http_upgrade;
           proxy_set_header Connection "upgrade";

        }

首先看几个重要的设置:

proxy_set_header  Host  $http_host;
proxy_set_header  X-real-ip $remote_addr;
proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_ssl_name notesail.com;
proxy_ssl_server_name on;
  1. 首先设置了Host,指明了我们要访问的是服务器上的哪个网站,因为我们反代使用的是相同的域名,所以直接用$http_host即可,如果你用了不同的域名,那就需要手动修改成你的源站域名了。
  2. 接着设置了$remote_addr,这个用于告诉我们的服务器访客的真实ip,而不是反代服务器的ip。(如果你是通过cloudflare访问的,要想获得访客ip那么还需要额外设置一下,查看此文
    补充,后来发现,上文方法只能显示反代服务器的ip(如果什么都不做,显示的是cloudflare的ip),因为typecho显示的ip默认直接使用的是请求者的ip,所以我们还需要设置一下,修改typecho目录下的config.inc.php,加入

    //防止 CDN 造成无法获取客户真实 IP 地址
    if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
    {
        $list = explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']);
        $_SERVER['REMOTE_ADDR'] = $list[0];
    }

    我们使用了转发链的第一个ip,即真正的请求者的ip,这样就可以正常显示访客ip了。

  3. $proxy_add_x_forwarded_for代表的是http请求经过的服务器的ip,包括请求者ip,还有中间的代理服务器(如果提供)的ip,如果想要像第二点中那样查看真实的ip,这个也得加上。

执行nginx -t 看看还报错不报错,接着使用certbot申请证书。

  1. **proxy_ssl_name和proxy_ssl_server_name

这个比较重要,如果你对cloudflare设置的反向代理出现了502的错误,大概就是没有设置这个参数 参考关于反代CloudFlare节点时返回502错误码的解决方案因为在https握手的过程中不包含host信息,所以cloudflare都不知道我们要访问哪个网站,所以我们要设置sni来指明我们要访问的是哪个网站** 采用如下写法也是可以的:

proxy_ssl_name $host;
proxy_ssl_server_name on;

补充阅读:

在过去的 HTTP 时代,解决基于名称的主机同一 ip 地址上托管多个网站的问题并不难。当一个客户端请求某特定网站时,把请求的域名作为主机头(host)放在 http header 中,从而服务器根据域名可以知道把该请求引向哪个域名服务,并把匹配的网站传送给客户端。但是此方式到 https 就失效了,因为 SSL 在握手的过程中,不会有 host 信息,所以服务端通常返回配置中的第一个可用证书,这就导致不同虚拟主机上的服务不能使用不同证书(但在实际中,证书通常是与服务对应。)。
为了解决此问题,产生了 SNI,SNI 中文名为服务器名称指示,是对 SSL/TLS 协议的扩展,允许在单个 IP 地址上承载多个 SSL 证书。SNI 的实现方式是将 HTTP 头插入到 SSL 的握手中,提交请求的 Host 信息,使得服务器能够切换到正确的域并返回相应的正确证书。
  1. 最后记得 proxy_pass https://1.0.0.1; 随便找个cloudflare的ip来反代即可。
sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository universe
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx
#最后输入
sudo certbot --nginx
#选择你刚才输入的域名

申请证书
自动配置好证书之后,我们就可以前往dnspod把境外的解析改回cloudflare了(如果之前默认是cname指向cloudflare,那么直接停用境外指向反代服务器的A记录即可),境内的保持不动。
停用境外A记录,使用默认指向cloudflare的记录
我们可以看看我们的电脑解析到的ip是不是gcp的,我心急所以直接修改了host文件,不过多等一下其实也可以。然后再次访问我们的域名,有没有感觉快了很多呢?再在域名后面输入/cdn-cgi/trace,看看我们走的什么节点,可以看到,即使我们不是移动显示的也是hkg(电信和联通本来应该走欧洲或者美国节点的)。

最后我们还可以在dnspod里面设置d监控,检测到如果反代服务器挂掉了,那么境内也解析到cloudflare哦。

文章目录