司开星的博客

GitHub Pages迁移到GitLab Pages 并启用HTTPS 记录

前提

最近想给GitHub Pages上的个人博客添加HTTPS支持, 网上搜索后发现了CloudFlare这个服务, 注册并启用后确实变成了HTTPS, 但浏览器会提示证书问题, 翻了几个页面才知道GitHub Pages本身可以设置HTTPS, 但仅限原始github.io域名, 自定义域名目前没有什么好方法可以支持HTTPS。

更新:目前 GitHub Pages 已经支持自定义域名添加HTTPS证书。

既然GitHub不支持,那就换一个平台吧。 看到有人推荐GitLab,支持自定义域名证书, 于是就决定用它了。

笔者博客使用的框架为Hexo。

迁移 Pages 项目

注册没什么值得说的。注册后新建一个项目作为博客项目, 项目可以设置为私有 (相比之下GitHub 免费账户只能设置为公开), 项目名按照官方教程配置为 yourname.gitlab.io, 格式和GitHub的相同.

这时你会惊喜的发现, GitLab 支持直接导入GitHub的项目. 那是不是直接把GitHub上的博客项目导入进来就可以了呢? 不是, 因为GitLab和GitHub 对Hexo框架支持不同. 这点后面再说.

本地添加内容

创建好项目之后就可以添加内容了. 虽然是从GitHub迁移, 但还是建议在本地新建一个Hexo博客项目, 而不是直接复制原博客目录push到GitLab.

本地新建好项目之后就可以把原项目下的source文件夹和_config.yml文件覆盖到新项目中,之后就是….gitlab-ci.yml

*PS: 很多关于使用GitLab Pages新建Hexo博客的文章都是直接fork官方Hexo的项目来进行修改, 官方文档也有这种方式的示例。不过可惜的是, 在笔者迁移的时间内GitLab官方Hexo项目是空的, 无法使用。

.gitlab-ci.yml

与GitHub Pages不同, GitLab Pages原生就支持Hexo框架。Github Pages的生成命令:

hexo g

hexo d

要先在本地用hexo的命令生成静态文件, 再把静态文件同步到GitHub上. 而GitLab原生支持Hexo的意思就是通过markdown文件生成静态网页文件的步骤不需要本地做了, 直接把markdown 文件push上去, GitLab 的引擎会帮你转换好. 这看似是方便了一些, 不过实际使用后发现反而是麻烦了, 因为GitLab的引擎速度时快时慢, 有时候一些小改动都要几个小时才能解析完, 反而不如本地生成直接同步显示的 GitHub。

说了这么多, 那这个.gitlab-ci.yml是什么呢? 简单的说, 这是一个用于告诉服务器如何生成静态文件的命令相关配置, 官方的说法是:

What this file actually does is telling the GitLab Runner to run scripts as you would do from the command line.

所以除了Hexo生成的内容我们还要在项目根目录下新建一个.gitlab-ci.yml文件. 文件内容官方也有示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
image: node:4.2.2

pages:
cache:
paths:
- node_modules/

script:
- npm install hexo-cli -g
- npm install
- hexo deploy
artifacts:
paths:
- public
only:
- master

笔者写文章时官方提供的此配置有问题, hexo deploy 是多余的。另外在解决各种因.gitlab-ci.yml引发的问题时发现了一个第三方用户写的比较新的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Full project: https://gitlab.com/pages/hexo
image: node:6.10.0

pages:
script:
- npm install
- ./node_modules/hexo/bin/hexo generate
artifacts:
paths:
- public
cache:
paths:
- node_modules
key: project
only:
- master

笔者使用的就是此配置。

上传内容

文件内容填好之后就可以push到GitLab上刚刚新建的博客项目上了。首次使用需要新建SSH密钥对并将公钥上传到GitLab。这步在项目上可以看到提示, 而且没什么需要注意的地方, 本文就不赘述了。

上传内容不需要用hexo,因为hexo 命令主要是用来生成静态文件的, 这里我们不需要静态文件, 直接用git上传即可。 注意: 如果某些目录来自于原博客, 那需要先处理这些目录的git远程地址, 否则无法将其上传到GitLab。

Pipelines

项目上传之后GitLab就会根据我们项目中的.gitlab-ci.yml文件来生成静态文件。这步的状态在项目的Pipelines 标签下可以看到状态。 如果之前的步骤没问题的话此时Pipelines中应该会有一个Pipeline, 状态可能是pending准备, running生成, passed 成功, failed失败中的一种。

pending状态和running状态有时候会持续比较久, 耐心等待。 另外除pending状态外其他状态都可以看到当前GitLab服务器的命令行输出, 位置是点击状态图标, 再点击Test下的状态图标。 如果没有显示出来可以直接点击右侧的raw查看纯文字输出.

如果遇到failed可以看看命令行输出有什么错误。 比如笔者遇到过以下错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
*** Please tell me who you are.

Run

git config --global user.email "you@example.com"
git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'root@************0.(none)')
FATAL Something's wrong. Maybe you can find the solution here: http://hexo.io/docs/troubleshooting.html
Error:

这显然不是因为我本地git配置问题. 后来发现是多了hexo deploy, 更换.gitlab-ci.yml就解决了。

如果很幸运的第一次运行就passed, 就可以测试下自己的博客是否可以访问了, 地址就是项目名yourname.gitlab.io。有时候passed之后也不代表没问题, 笔者在此又遇到一个坑, 原本hexo的配置文件有问题, 但pipeline显示正常, 地址访问却是空的. 之后发现是由于hexo的配置文件中使用了next 主题, 但新项目中没有这个主题, 于是就不能显示。

配置域名

上面的步骤都完成后就可以把原域名解析到新博客上. 根据官方文档需要做两步:

  1. 在项目的Pages配置下新加域名. 由于此时还没有启用HTTPS, 只填写域名即可。
  2. 在域名的控制后台设置A记录。当前的github解析地址为52.167.214.135
  3. 把hexo的 _config.yml 中的url更新成自己的域名。

启用HTTPS

网站显示正常后就可以开始启用HTTPS了.

申请证书

本人使用的是免费证书中最热门的 Let’s Encrypt

申请使用的系统为 macOS 系统,直接按照官方教程使用命令申请:

1
2
3
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto certonly -a manual -d YOURDOMAIN.org

稍等一会儿终端上会显示一些注意事项需要你确认,确认之后就到验证服务器归属了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Make sure your web server displays the following content at
http://YOURDOMAIN.org/.well-known/acme-challenge/*********************************************** before continuing:

**************************************************************************

If you don't have HTTP server configured, you can run the following
command on the target server (as root):

mkdir -p /tmp/certbot/public_html/.well-known/acme-challenge
cd /tmp/certbot/public_html
printf "%s"
**********************************************> .well-known/acme-challenge/**********************************************************
# run only once per server:
$(command -v python2 || command -v python2.7 || command -v python2.6) -c \
"import BaseHTTPServer, SimpleHTTPServer; \
s = BaseHTTPServer.HTTPServer(('', 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \
s.serve_forever()"

这时候终端暂时不要输入,去服务器端做验证准备工作。

验证

简单来说验证就是能在 let’s Encrypt要求的网站访问路径下返回要求的字符串。

有两种方式能实现这个需求:

第一种比较简单,直接在.gitlab-ci.yml的 script 最后添加以下两个命令:

1
2
- mkdir -p public/.well-known/acme-challenge/
- echo [验证时所需要的内容代码] > public/.well-known/acme-challenge/[验证时所需要的文件名]

然后git push等构建好就可以去终端继续验证了。

笔者使用的是另一种方法,第一次验证比上一种方法麻烦一点,但之后的刷新则更方便。

首先在.gitlab-ci.yml的 script 最后加上一句:

- npm install hexo-processor-static —save

hexo-processor-static这个模块可以把source/_static文件夹下的所有内容原封不动地复制到public文件夹中。接下来就是自己在source下新建_static文件夹,然后在里面新建一个/.well-known/acme-challenge/文件夹,里面新建一个文件,文件名是 let’s Encrypt要求的路径中的文件名,文件内容是 let’s Encryp要求显示的文本内容。

之后就是 git push了,等待构建完成就可以去终端继续验证了。

启用HTTPS

验证好之后就会得到密钥:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Press Enter to Continue
Waiting for verification...
Cleaning up challenges
Generating key (2048 bits): /etc/letsencrypt/keys/0000_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0000_csr-certbot.pem

IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/sikaixing.com/fullchain.pem. Your cert will
expire on 2017-07-13. To obtain a new or tweaked version of this
certificate in the future, simply run letsencrypt-auto again. To
non-interactively renew *all* of your certificates, run
"letsencrypt-auto renew"
- Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
- If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

不过我们要的并不是显示出来的这两个,而是如下路径下的两个:

1
2
/etc/letsencrypt/live/YOURDOMAIN.org/fullchain.pem
/etc/letsencrypt/live/YOURDOMAIN.org/privkey.pem

接着去Gitlab当前博客项目中设置域名。先把原来的域名删掉(其实一开始不添加域名,等到这里再设置 HTTPS 域名也可以。之前添加域名是为了保证前面的步骤都没问题),新建域名,将/etc/letsencrypt/live/YOURDOMAIN.org/fullchain.pem的内容复制到Certificate (PEM)中,/etc/letsencrypt/live/YOURDOMAIN.org/privkey.pem的内容复制到Key (PEM),然后保存即可。等待一段时间,你就可以使用https://YOURDOMAIN.org访问你的博客了。

Hexo 模板修改

最后再改下hexo 的主题模版,实现 http自动跳转 https

NexT主题为例,打开layout目录下的_layout.swig,在<head>标签中加入以下代码,把yoursite.com替换为你的域名:

1
2
3
4
5
<script type="text/javascript">
var host = "yoursite.com";
if ((host == window.location.host) && (window.location.protocol != "https:"))
window.location.protocol = "https";
</script>

告诉搜索引擎只抓取 HTTPS 页面:

<link rel="canonical" href="https://YOURDOMAIN.org/specific/page" />

之后再git push即可。

刷新HTTPS证书

let’s Encrypt 的证书有效期为三个月,三个月后需要重新申请证书,验证及启用。

申请证书及方式与一开始的相同,如果你按第二种方法验证则现在只需要在申请证书之后添加文件并push即可。启用新证书则是删除gitlab上原域名重新添加域名并填入相应字段。

也可以直接使用开源的自动刷新脚本:

npm install -g gitlab-letsencrypt

$ gitlab-le --email example@example.com --token ... --domain example.com www.example.com --repository https://example.com/user/my-repo --path source/_static/.well-known/acme-challenge

$ gitlab-le --email example@example.com --token ... --domain example.com www.example.com --repository https://example.com/user/my-repo --path source/_static/.well-known/acme-challenge --production

命令中的email, token, domain, repository 根据实际情况填写即可,--path是针对本文使用的验证方式需要额外加的路径参数。不带--production参数是为了测试流程是否正常,如果正常则再加上此参数就可自动刷新ssl证书了。

参考内容:

  1. GitLab Pages documentation
  2. https://zongren.me/2016/07/20/add-tls-to-gitlab-pages/》
  3. Tutorial: Securing your GitLab Pages with TLS and Let’s Encrypt
  4. 为Github的Hexo博客启用SSL/TLS