R·ex / Zeng


音游狗、安全狗、攻城狮、业余设计师、段子手、苦学日语的少年。

CloudFlare,DNS,以及 Nginx 的多域名配置

注意:本文发布于 2623 天前,文章中的一些内容可能已经过时。

在配置自己的个人网站的过程中,我学到了许多编程以外的知识,下面就来逐一说一说吧。

CloudFlare

由于我的网站是托管在 OpenShift 上面,而 OpenShift 提供的默认域名 xxx-xxx.rhcloud.com 在国内由于某些特殊原因无法访问,经过再三的搜索,我决定使用 CloudFlare 来在国内加速我的网站。CloudFlare(下文简称 CF)是一个可以帮助提升网站加载速度、阻止网络攻击的公司,原理是将域名的 NS 记录(后续会讲到)修改为 CF 的记录,所有走这个域名的流量都会经过 CF 的服务器处理。所以其实 CF 对于我的网站来说就是个代理,只不过功能多了点,我用到的大概有:配置 DNS、使用 Flexible SSL 实现 HTTPS、Web 防火墙、缓存、压缩静态资源。

CF 对我来说最有帮助的就是 Flexible SSL 了,因为我比较懒,不想管理证书,因此就全部交给了 CF,这样用户通过 HTTPS 连接到 CF,CF 通过 HTTP 连接到 OpenShift,普通用户并不能感受到与直连 HTTPS 网站有什么区别。

DNS 简述和配置

刚才提到了 NS 记录,这个其实是 DNS 的内容。NS 是 Name Server 的简称。说到这儿,该讲一讲 DNS 的原理了。

助记符与电话簿

举个例子(样例来源:POJ 1002),假设我的号码是 487-3279,那么有一个好记的方法就是:在九宫格键盘上输入 ITS-EASY 就可以了。在玩“勿忘我”这个游戏的时候,也多次提到“助记符”的概念,就是用一段话来记住一个口令(虽说我觉得游戏中 H3O 这个口令本身就很好记嘛)。但是这个并不能每次都奏效。例如一个网站的服务器 IPv4 地址由四个 0~255 的数字组成,正常人的脑子里一般记不住那么多的 IPv4 地址(更何况现在的 IPv6 更凶残),于是人们就想到了类似于电话簿的方法。就像刚才的例子,你只需要翻一下自己的电话簿,找到 REX 这一条,发现后面的值就是 4873279,再打电话就可以了。早期的互联网就是这样发展起来的,只不过你打电话变成了浏览器要访问网站,REX 变成了 www.rexskz.info4873279 变成了 104.27.166.43 而已。在现在的操作系统中依旧保留了这个电话簿文件,关键是这玩意居然还能用。Windows 中的位置在 %windir%/System32/drivers/etc/hosts,Linux 中的位置在 /etc/hosts。以 Windows 为例看一下里面默认的内容吧:

# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host

# localhost name resolution is handled within DNS itself.
#   127.0.0.1       localhost
#   ::1             localhost

每一行有两个字段,第一个是 IPv4 或者 IPv6,第二个是对应的域名,允许一个 IP 对应多个域名(多个 IP 对应一个域名的事情我没干过,毕竟从逻辑上来说不行,你总不能让浏览器随机选一个吧,但是不知道 Windows 允不允许这样写)。有两个例外:127.0.0.1::1 是被硬编码在 DNS 解析器里的,你不能通过设置 211.65.101.15 localhost 来将 localhost 修改成其它网站。当然,特殊的设备和程序也许可以,如果直接修改了 IP 报文的话。

至于这个文件为什么依旧被保留,原因之一是为了兼容一些古老的程序,当然对于我们开发者来说也很有用,例如你可以设置 127.0.0.1 rexskz.com,这样你访问 rexskz.com 就是访问本地网站了。当然,你也可以通过设置 127.0.0.1 xxx.baidu.com 来屏蔽百度的一些服务。

DNS 服务

早期互联网主机非常少,以至于一个文件就能存下了,但是现在的网站已经多到不知道多少个了,每个网站都可能会有很多很多域名(例如我的网站就有 blog.rexskz.infoterminal.rexskz.info 等五六个二级域名,还有 rexskz.cn 这样的域名),这种规模,一个文件肯定存不下,于是聪明的前辈们把这玩意单独摘了出来,形成了现在的 DNS 服务(还记得之前被 Mirai 搞掉的 Dyn 公司么?它就是提供 DNS 服务的,只不过恰好 某个不存在的网站 使用了它的 DNS 服务,因此美国的吃瓜群众们上不去了)。

至于实现的原理,可以看 这里这里

我们以 CF 为例,看一下我的域名 rexskz.info 是如何配置的(截取了部分记录):

0

可以看到 A 记录、CNAME 记录等,比较常见的有这么几个:

A:指向一个确定的 IPv4 地址
AAAA:指向一个确定的 IPv6 地址
CNAME:告诉你应该到哪个地方继续寻找
MX:指定域名的接收邮件服务器
SPF:指定域名的发送邮件服务器
TXT:该域名的说明文字

A 和 AAAA 没什么好说的,就是告诉你“这个域名的 IP 就是这个”;CNAME 的作用相当于别名,例如你访问 blog.rexskz.info 就相当于访问了后面的 xxx-xxx.rhcloud.com;MX 的作用是,如果你给 [email protected] 发邮件,那么邮件会被发送到 MX 所指定的邮件服务器,你也可以为不同的子域名指定不同的邮件服务器;SPF 和 TXT 常用于反垃圾邮件,例如我在邮件中声明我是 [email protected],你可以查一下看看发送这封邮件的服务器是否在 rexskz.info 的 SPF 列表中,如果不是,那肯定是假的了,当然也有把信息写在 TXT 里面的,例如网易的免费域名邮箱。

所以域名绑定就是先配置好 OpenShift,让 OpenShift 准备好接收这样的请求(其实相当于在 OpenShift 内部又新建了一条 DNS 记录,因为我们最终需要的是 IP,所以查询肯定会终止于某条 A 或者 AAAA 的记录),然后在 CloudFlare 配置好 CNAME 就可以啦!如果需要使用 CF 的服务(例如 Flexible SSL),则需要激活右边的那朵云,表示流量会先经过 CF 处理。

TTL

顺便提一下 TTL 好了,TTL 表明这个记录过多久就需要更新一次,有点像 Web 里面的 Cache control。对于一般的网站,一个域名配置好之后,可能很久都不会再改动了,增大 TTL 有助于降低 DNS 查询的频率,但是如果有了修改,生效的时间也会很长。所以具体取什么值也是一门学问。当然,CF 直接帮我选了“自动”……

Nginx 多域名配置

提示:下文与 OpenShift 无关。

其实关于 Nginx 的多网站配置还是相当简单的,在配置文件中多写几个 server 命令就可以了。但是如果是同一网站的多个子域名,感觉写好多个 server 不太好,而且我希望有个更方便的方式:在网站根目录下建立若干文件夹,xxx 文件夹就对应着 xxx.rexskz.info。搜索了一下,可以这么写:

server {
    listen            80;
    server_name       ~^(?<subdomain>.+)\.rexskz\.info$;
    root              /data/www/$subdomain;
    index             index.php index.html index.htm;
}

server_name'.rexskz.info' 之前的部分会被提取出来,可以用专门的 $subdomain 变量访问。这解决了我一开始的问题。然而随着网站规模的扩大(其实是我有强迫症),有时候我需要设置一些优雅链接,例如除夕夜的抢红包的网站 https://hongbao.rexskz.info/first,其实真正的网址应该是 https://hongbao.rexskz.info/index.php?code=first。对于这个需求,一般的 Nginx 配置文件倒也好写:

location ~ ^/([^_][0-9A-Za-z_]+)$ {
    rewrite ^/([^_][0-9A-Za-z_]+)$ /index.php?code=$1 last;
}

然后就有了一系列需求,例如我正在做的解谜网站 https://riddles.rexskz.info/first 也需要这样的链接,之前写的每日打卡的网站 https://withu.rexskz.info/day/63 也需要这样的链接……但是这几个网站都属于不同的域名,Nginx 的 if 命令又不能嵌套,于是很长一段时间我不知道该怎么办,直到有一天突然一开窍,发现 location ~ 后面的东西其实可以不用和 rewrite 后面的那一坨相同!于是索性把这几个整合成了一个 location

location ~ ^/(.+)$ {
    if ($host = hongbao.rexskz.info) {
        rewrite ^/([^_][0-9A-Za-z_]+)$ /index.php?code=$1 last;
    }
    if ($host = riddles.rexskz.info) {
        rewrite ^/([^.]+)$ /index.php?level=$1 last;
    }
    if ($host = withu.rexskz.info) {
        rewrite ^/day/([-\.\d]+)$ /day/index.php?day=$1 last;
    }
}

大功告成!


Update 2019.01.07

由于 OpenShift 也不提供免费服务了,于是我的网站现在挂在了 Vultr 上;此外 CF 也提供了 Domain Registrar,于是我又把域名从 Godaddy 转移到了 CF;最后是我在 CF 中开启了 Full SSL,安装了 CF 的自签证书,服务器上关掉了 80 端口并开了 443 端口,算是提高了一些安全性吧。

Disqus 加载中……如未能加载,请将 disqus.com 和 disquscdn.com 加入白名单。

这是我们共同度过的

第 3077 天