nginx反向代理typecho加速访问

本文记录了nginx分别采用直接反代源站与反代cloudflare两种形式的操作,但是因为在反代cloudflare的过程中遇到了一些目前无法解决的问题,所以这篇文章目前只记录直接反代源站的形式。 最后在朋友的帮助下,解决了这个问题,所以一起记录下来吧。
不过我还是认为,使用上一篇文章的dnspod+cloudflare的方案,仅让境内流量使用反代是更加合适的选择。反代cloudflare还有一点问题就是如果开启了https,tls握手花费的时间要多不少,所以还是要做出选择。

推荐阅读nginx反代加速网站访问,这篇文章的方案更具可行性,效果也更好。

前言

之前写了一篇文章记录了如何使用dnspod在cname接入dnspod的情况下,境内走反代服务器,境外继续走cloudflare,不过考虑到cname接入+dnspod分流比较麻烦,而我们的站点又基本上都是大陆的访客,所以直接反代源站或者所有地点都通过反代服务器访问cloudflare也是个不错的选择。另外注意一点,不要直接使用iptables之类的软件直接转cloudflare的ip,因为他们呢不会验证域名,一不小心你的反代服务器就变成公共节点啦!正好昨天我看见有人发了这么一条信息,贴出来分享一下吧。

很多人喜欢直接拿iptables之类的直接转cf自选的ip来加速访问一些垃圾线路的节点。
这就导致了别人知道了你的ip和端口以后就可以直接用在自己的套了cf的节点上,然后你就会发现你的流量慢慢的消失了。
解决办法就是使用nginx的反代,让那些host不是你域名的请求都返回403,当然直接访问ip的也给他拦截了,返回403。

设置服务器

dns设置

本文我们针对全面反代cloudflare来说,直接反代源站也是类似的操作,我们当前采取的是ns接入cloudflare的方式,即域名服务器已经修改成了cloudflare的服务器,在cloudflare上设置dns记录,添加两条记录。

  1. cf.example.com 解析到你的源站ip,并开启cdn(如果你是直接反代源站,那么这一步关闭cdn,仅作为dns使用即可)
  2. blog.example.com 解析到你的反代服务器ip,仅作为dns使用。
  3. dir.example.com 直接解析到服务器,用于直接代理源站使用(其实不用这个域名直接用ip也是可以的。)

证书设置

之前我一直很喜欢使用let's encrypt的证书,因为免费,并且还有自动部署脚本,结果今年上旬,let的证书的ocsp验证服务器居然被墙了,这就导致部分需要验证ocsp的浏览器访问使用letsencrypt证书的网站会等待相当长的时间,所以我们还是另外找个替代品吧,这里我用的是freessl.cn的免费证书。
申请亚洲诚信免费证书
另外,如果你不想下载一个密钥管理软件的话,直接使用浏览器生成csr也是可以的。

生成证书之后,会先要你添加一条txt dns记录来验证一下域名所有权,添加记录等上几十秒或者几分钟再点击验证即可,然后选择下载证书。
压缩包中的证书

nginx设置

源站nginx设置

考虑到国外服务器到服务器之间的连接环境没有大陆那么恶劣,并且我们也不需要传输什么机密文件,直接使用http通信问题也不大,那么源站我就只配置80端口监听了。
安装好nginx:
nginx

反代服务器设置

反代源站的写法
# 如果反代的是源站就这样写
        location / {
           proxy_set_header Host  blog.example.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 http://dir.example.com;
           proxy_set_header Upgrade $http_upgrade;
           proxy_set_header Connection "upgrade";
        }

直接反代源站的写法还是比较简单的。

反代cloudflare的写法
# 如果反代的是cloudflare
        location / {
        # 由于我们反代的cloudflare使用的是 https,所以我们需要指明sni,不然是无法握手的,另外还需要设置host,这两个都要设置成接入cloudflare的域名。
        proxy_ssl_name cdn.example.com;
        proxy_ssl_server_name on;
        proxy_set_header Host cdn.example.com;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_redirect off;
        # 重点!由于我们接入cloudflare的域名和我们反代服务器的域名不一样,typecho的数据库里面记录的链接都是cdn.example.com的形式,所以我们要做内容替换。我们还需要通过设置Accept-Encoding "";来告诉服务器不要对内容进行压缩,不然返回的数据没办法使用sub_filter替换。 
        proxy_set_header Accept-Encoding "";
        sub_filter "https://cdn.example.com" "https://blog.example.com";
        # 开启内容多次替换
        sub_filter_once off;
        # 禁用缓存 (这个应该会影响到cloudfalre的缓存,不建议设置)
        add_header Cache-Control no-cache;
        expires 12h;
        # 这里随便找个cloudflare的ip即可
        proxy_pass https://1.0.0.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        }

里面有几点非常的重要,我都在注释里面写出来了,这里再补充一下:
proxy_ssl_name 以及 proxy_ssl_name_on 用来设置sni,以及后面在header中设置host都是必不可少的,都需要设置成接入cloudflare的域名。

之前我设置的sub_filter一直没生效,经过查询,因为服务器返回的数据使用了gzip压缩,所以无法正确的应用替换规则,所以要告诉服务器不要再压缩内容传递了。另外我们开启了内容的多次替换,详情可以查看nginx替换网站响应内容,默认只替换第一个匹配的串,我们关闭之后便会替换所有匹配的串了。后面那个禁用缓存的,目前我还没发现起了什么效果,大概是因为我被反代的服务端本来就没开启缓存吧。

设置好反代之后,systemctl restart nginx重启一下nginx,我们再访问blog.example.com即可成功访问了。

cloudflare回源设置

(如果你是直接反代源站,那么可以跳过这部分)
如果是反代cloudflare的话,我们还要进行一些设置,由于我们源站只监听了80端口,所以需要修改一下cloudflare加密模式,改成灵活,只强制加密浏览器到cloudflare的连接(这个应该是默认模式,不过考虑到反代服务器也要设置https,其实这里设置成不加密也没问题的),然后开启始终使用https/自动重写https等选项。
加密模式改成灵活

配置typecho

注意,站点文件中除了要配置php之外,一定记得加上下面这些重写指令,不然可能你后面只有主页可以访问,其他的都会报404错误。(也可以先不加这部分,先安装试试,遇到问题再加上,不过如果你要做伪静态的话,这部分迟早要加)

if (-f $request_filename/index.html){
    rewrite (.*) $1/index.html break;
}
if (-f $request_filename/index.php){
    rewrite (.*) $1/index.php;
}
if (!-f $request_filename){
    rewrite (.*) /index.php;
}

一些问题的解决

安装页面空白

如果我们使用了反代cloudflare的方式,那么我们会发现,访问blog.example.com我们可以看到安装页面,但是当我们点击下一步之后,页面就只剩下空白了。因为typecho没有考虑到反代,安装代码里面有一部分阻止了跨站请求,把这段注释掉即可。

// 挡掉可能的跨站请求
if (!empty($_GET) || !empty($_POST)) {
    if (empty($_SERVER['HTTP_REFERER'])) {
        exit;
    }
    $parts = parse_url($_SERVER['HTTP_REFERER']);
    if (!empty($parts['port'])) {
        $parts['host'] = "{$parts['host']}:{$parts['port']}";
    }
    if (empty($parts['host']) || $_SERVER['HTTP_HOST'] != $parts['host']) {
        exit;
    }
}
使用sqlite3无法连接到数据库

如果我们想直接使用sqlite3,那么安装一下扩展 php-sqlite3即可在安装界面看到使用sqlite3的选项,不过,记得把你的typecho文件夹拥有者设置成www-data:www-data 不然是没办法新建数据库文件的。

资源文件不显示(页面样式混乱)

除此之外,如果我们反代服务器用的https而源站是http,默认情况资源文件会出错,因为站点生成的html文件中资源文件还是用的http,这些资源文件都是不会被加载的,所以我们还需要设置一下强制开启typecho的https,编辑/var/www/html/typecho/config.inc.php,加上

/** 启用https **/
define('__TYPECHO_SECURE__', true);
安装后访问后台只看的到空白页面

安装完成后,当我们尝试访问后台的时候,可能会只看得到空白的页面。查找官网faq发现:

一般的出现这种情况时,nginx.conf里的的location设置都是类似这样
location ~ .*.php$
要支持pathinfo,要改成
location ~ ..php(/.)*$

虽然我的php location不是他上面那样,不过当我改成下面这样并重启后,一切就正常了。

还有一点要补充的,直接反代cloudflare,当进入/admin管理后台时,依旧会跳到cdn.example.com,但是这是个302重定向,我们是没办法直接修改的,所以还是忍一忍吧,毕竟访客不需要进入后。
这些问题都是我遇到的,一一解决后网站便能正常工作了,如果你还有什么问题就评论留言吧。