问题
在搭建博客的过程中,按照我的想法,我只要直接把阿里云买的域名,用 CNAME 的方式指向 github pages 提供的域名就 OK 了。
比如,我想把 test.forelax.space 这个域名指向我 github pages 的地址,我就在阿里云上增加一条配置,如图所示:
可是这时当我访问 test.forelax.space 这个域名的时候,得到的却是一个 404 的页面:
查看 github pages 的说明,我必须要在我的仓库的设置中添加一个自定义域名选项,我才能正确的把我的域名 forelax.space.io 正确的指向 github pages 上的页面:
可这是为毛啊?我就直接指过来怎么就不行?这个设置项到底做了什么?我们一个个问题来解决。
一个个问题我们来尝试解决
给 Github Pages 的 Custom Domain 设置域名后发生了什么?
当我尝试删除然后重新填入这个设置项后,我发现我仓库中多出了两个 commit:
由此看来,这个设置项仅仅是帮我们在仓库的 master 分支中更方便的修改一个叫做 CNAME 的文件而已。那么 github pages 什么时候会用到这个问题呢?这个问题我们要从域名的过程说起。
当我在阿里云上购买了 forelax.space 这个域名后,发生了什么?
简单来说,阿里云(其实是万网,不过说起来都一样:P)通过自己域名经销商的身份,向 .space 域名服务器增加了两条记录,当有人向 .space 域名服务器询问 forelax.space 的 IP 地址的时候,就告诉询问者,我不知道这个域名的 IP 是多少,但是你可以去 dns17.hichina.com 或者 dns18.hichina.com 这两个域名对应的服务器去问一下,他们知道。因为我在购买域名的时候,选择了默认的域名解析服务,所以给 .space 域名服务器中添加的记录是阿里云自己的域名服务器。如果有能力自己搭建 DNS 服务器,也可以在阿里云的控制台把 DNS 解析服务器改成自己的 DNS 服务器的 IP。如下图:
如何证实这个过程呢?我们可以用 dig +trace forelax.space
这个命令来看看域名解析过程中的每一步都发生了什么:
; <<>> DiG 9.9.7-P3 <<>> +trace forelax.space
# 上面只是输出 dig 的版本号以及我们这次命令的参数
;; global options: +cmd
# 上面表示 dig 这个命令默认还会加上 +cmd 选项
. 63324 IN NS e.root-servers.net.
. 63324 IN NS a.root-servers.net.
. 63324 IN NS c.root-servers.net.
. 63324 IN NS k.root-servers.net.
. 63324 IN NS l.root-servers.net.
. 63324 IN NS g.root-servers.net.
. 63324 IN NS f.root-servers.net.
. 63324 IN NS j.root-servers.net.
. 63324 IN NS h.root-servers.net.
. 63324 IN NS d.root-servers.net.
. 63324 IN NS i.root-servers.net.
. 63324 IN NS m.root-servers.net.
. 63324 IN NS b.root-servers.net.
;; Received 508 bytes from 192.168.31.1#53(192.168.31.1) in 38 ms
# 上面表示我们从本地的路由器中,得到了 13 台根 DNS 服务器的地址, . 表示这是根服务器, 63324 表示 TTL,也就是这个信息还会缓存多久,在 63324s 内我们访问得到的还会是这个结果
# IN 表示我们返回的是 IP 协议,基本上我们都是 IP 协议,所以可以忽略他
# NS 表示这条记录是一个 Name Server 记录,告知请求者任何根目录以下的记录都可以找这个服务器
space. 172800 IN NS a.nic.space.
space. 172800 IN NS b.nic.space.
space. 172800 IN NS c.nic.space.
space. 172800 IN NS d.nic.space.
space. 86400 IN DS 44251 8 1 36ACB68B734DFE465CC1112F9DAC08B8B66627CC
space. 86400 IN DS 44251 8 2 A82D8ED2B07D66D6E7AF375E0E44B22A82F4479AD45F5D8E1859DF6F C170E67C
space. 86400 IN RRSIG DS 8 1 86400 20171202050000 20171119040000 46809 . Fg9GkuRICx7mfbOmfuQumQ5ofrxniMi4+lw0AKbE15CJO6Sqj8S1H45T 9LyVhdjxWZ5oRsLOG4YIJum7rAa1IlORTePVlSwLjwz1AuDDOdb603C4 ibqknFSkjYJgw82wTbx5K48SvWRUk8u7aIqvX29Tdl0YR/5FPicjOAvi 0hkRCir8vyg1DHebDNiKKl0/l2f4YJG9x2LUxdUYlRPHOwYbhgscMcJf 8q5TvqW4mC1BdfaysfwLUA1Uf+9qAO4y51QSnxAsXReZH5r296Er7/sQ 6pGigQXiGJhlm9etpKyzqtpe3EcK5TBVKcc6S8Xu2OLUSShbEx+3l9ga CBS0Fw==
;; Received 657 bytes from 198.41.0.4#53(a.root-servers.net) in 500 ms
# 上面表示我们从 a.root-servers.net 这个根服务器中得知了 .space 这个域名服务器的记录
# 其中 DS 表示这是一条 DS 类型的 DNS 记录,可以暂时理解为一种添加时要求更高的记录类型,比如这里就比 NS 多了很多的数据,细节有兴趣可以去维基百科查查 List of DNS record types
forelax.space. 3600 IN NS dns17.hichina.com.
forelax.space. 3600 IN NS dns18.hichina.com.
0eldeflreldugqhaejqrp17ppn34aaqp.space. 3600 IN NSEC3 1 1 1 - 0FIBQMPFM95T51I962J7PVBKHVQGF4Q1 NS SOA RRSIG DNSKEY NSEC3PARAM
0eldeflreldugqhaejqrp17ppn34aaqp.space. 3600 IN RRSIG NSEC3 8 2 3600 20171214211930 20171114215839 46195 space. nUIuP4ZS4WyiF4vdrPYeasfWR54ckTK4NBybw0vI42ZwWbcMV8kdwd0J VVDcYhR2OQTImjSoy945LwmSEM1nyV72EwldpjCX/ynIWfyH8FLJtuQr K2WP7IUAeAT9gBiI8bF+Y+Ir81Q9MDOHrDrPL5hZH8GFjQwkh+9aljjD nFc=
om8amflncknjroa3cjf9287ka296qfvm.space. 3600 IN NSEC3 1 1 1 - ONF07RDF2DJM0FDED9AG6MC3HK38HQEJ NS DS RRSIG
om8amflncknjroa3cjf9287ka296qfvm.space. 3600 IN RRSIG NSEC3 8 2 3600 20171214011525 20171114103910 46195 space. E9xkbsyIh6h+4faNQhAILNNALmF9EPveH5EiGzHPJpyJD0AIMzbcG1Iw b2+ahUtoHYgQjG+oqr/PvCV9ikub0i86WWrxIOwCnBLZG45t/so1P9Cz dQb1hZY39z5b0cv0Swzog/jyQnIQTWjZOgp0ZdP+Vtru+MbFmOtSGfZC zlQ=
;; Received 582 bytes from 194.169.218.51#53(a.nic.space) in 202 ms
# 上面表示我们从 a.nic.space 这个域名服务器得到了所有可以得知 forelax.space 这个域名地址的记录,这里我们看到了两个熟悉的阿里云的 DNS 解析服务器
也许你会疑惑这里获取到根服务器的时候,并没有给出 IP 啊,那下一步是怎么知道根服务器的地址的?其实返回的请求里头是带有地址的,只是 dig
这个命令没有显示出来,用 WireShark 抓取这一次的返回包我们就可以看到返回的内容中是包含有根服务器的 IP 地址的:
当我在阿里云上增加了一条解析记录后,发生了什么?
阿里云自己搭建的 DNS 解析服务器上,增加了一条新的 CNAME 记录。上边执行的 dig +trace forelax.space
命令其实最后还有一段,我把他截掉放在这里了:
forelax.space. 600 IN CNAME forelaxx.github.io.
;; Received 74 bytes from 106.11.211.57#53(dns17.hichina.com) in 9 ms
# 最终,我们从 dns17.hichina.com 这个服务器中得到了 forelax.space 需要跳转到 forelaxx.github.io 的记录,这是一个 CNAME 类型的记录,表示我们如果想知道 forelax.space 的
# IP 地址,只要知道 forelaxx.github.io 的 IP 地址就可以了
那当我们在浏览器中访问 forelax.space 的时候,会发生什么?
现在我们知道,如果想得知 forelax.space 的 IP ,只要得知 forelaxx.github.io 的 IP 就好了,于是我们继续发 DNS 请求包来查询,我们继续通过 dig +trace forelaxx.github.io
命令可以得知,如果想知道 forelaxx.github.io 的 IP,只要知道 sni.github.map.fastly.net 的地址就可以了,继续查找,我们得知了 sni.github.map.fastly.net 的 IP 地址为 151.101.73.147。
以上的过程在浏览器最终发起对 forelax.space 的 HTTP 请求之前就会完成,因此当我们最终给 forelax.space 发起 HTTP 请求的时候,浏览器已经得知他最终需要给哪个 IP 发送 HTTP 请求了:
这里注意,github pages 这个服务不管你是哪个仓库的静态资源,最终他都是部署在同一台服务器上面的,比如这里我用 dig sketchk.github.io
来看看我的好伙计七爷的博客的地址,最终会发现得到的结果也是 151.101.73.147。
于是问题来了, 151.101.73.147 这台服务器在接收到一个 HTTP 的请求的时候,他怎么知道到底要返回哪个博客的静态资源呢?此时,我们之前在仓库里的 CNAME 文件便起了作用。当我们创建了一个 CNAME 文件的时候, github 便给 151.101.73.147 这台服务器增加了一条记录,告诉他,如果 HTTP 请求中的 Host 字段中的值是 forelax.space 的话,就返回给他这个仓库里头的静态资源。
由于 Host 字段是 HTTP 在 header 中要求必有的一个字段,因此这个机制保证了 github 可以正确返回那个仓库里的静态资源。
如果我想使坏,把我的域名挂到别人的 github pages 上,可以不?
答案是 NO,github 禁止你这样做,在设置项里头完全不允许你这么做,即便你修改了 CNAME 文件并强行 push 上去,github 也不会认你的这个 CNAME 文件,并且会在设置项中给出警告:
同时结合上面我们已知的内容,即便你把自己的域名解析改成别人的 github pages 页面也是没有用的,因为别人的仓库中的 CNAME 并没有记录你的域名,所以访问你的域名跳转过去就会显示文章一开头的那个 404 页面。