Let's Encrypt 是一家全新的 SSL 证书颁发机构,为用户提供免费、自由、自动化的证书颁发流程。我们可以通过 Let's Encrypt 申请 SSL 证书来为我们的 GitLab 提供 HTTPS 接入。

安装 Let's Encrypt 客户端

首先,通过 git 下载 Let's Encrypt 的客户端:

git clone https://github.com/certbot/certbot
cd certbot
./certbot-auto --help

(注:自 2016 年 5 月起,letsencrypt 项目改名为 certbotletsencrypt-auto 工具改名为 certbot-auto。不过为了保持兼容性,克隆仓库时仍可使用 https://github.com/letsencrypt/letsencrypt,使用命令时也仍可用 letsencrypt-auto。)

申请证书

下载完 Let's Encrypt 客户端后,我们可以借助随 GitLab 启动的 nginx 服务器来验证我们的域名,进而获得证书。

./certbot-auto --agree-tos --email [email protected] certonly --webroot -w /opt/gitlab/embedded/service/gitlab-rails/public/ -d www.example.com

上述命令中:

--agree-tos
同意用户协议。
--email
首次申请证书时,需要邮箱地址来创建 Let's Encrypt 的账号。不过,并不会验证此账号。
邮箱地址用于接受证书过期提醒。
certonly
只申请证书。
--webroot
通过在当前运行的 web 服务器下存放验证文件来验证身份。
-w
指定当前运行的 web 服务器的根目录。
对于通过 Omnibus 安装的 GitLab 的默认的 nginx 服务器的根目录位于 /opt/gitlab/embedded/service/gitlab-rails/public/
-d
指定要申请证书的域名。

证书申请成功后,会有类似如下输出:

Requesting root privileges to run certbot...
  /home/zzz.buzz/.local/share/letsencrypt/bin/letsencrypt --agree-tos --email [email protected] certonly --webroot -w /opt/gitlab/embedded/service/gitlab-rails/public/ -d www.example.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Performing the following challenges:
http-01 challenge for www.example.com
Using the webroot path /opt/gitlab/embedded/service/gitlab-rails/public for all unmatched domains.
Waiting for verification...
Cleaning up challenges
Generating key (2048 bits): /etc/letsencrypt/keys/0001_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0001_csr-certbot.pem

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/www.example.com/fullchain.pem. Your cert
   will expire on 2017-07-22. To obtain a new or tweaked version of
   this certificate in the future, simply run certbot-auto again. To
   non-interactively renew *all* of your certificates, run
   "certbot-auto renew"
 - 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

得到的证书及私钥存放在 /etc/letsencrypt/live/www.example.com/ 目录下,其中

  • cert.pem: 网站自身的证书;
  • chain.pem: 网站证书链中的上级证书;
  • fullchain.pem: 包含了网站自身证书和上级证书的完整证书链;
  • privkey.pem: 网站自身证书对应的私钥。

更新证书

由于证书的有效期为三个月,因此我们需要定时执行以下命令来更新证书:

./certbot-auto renew

注意如果证书还有较长时间才会过期,那么证书并不会得到更新,并会得到类似如下输出:

Requesting root privileges to run certbot...
  /home/zzz.buzz/.local/share/letsencrypt/bin/letsencrypt renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/gitlab.zzz.buzz.conf
-------------------------------------------------------------------------------
Cert not yet due for renewal

The following certs are not due for renewal yet:
  /etc/letsencrypt/live/gitlab.zzz.buzz/fullchain.pem (skipped)
No renewals were attempted.

而如果证书即将过期(有效期不足 20 天,10 天和 1 天时),用户却还未执行命令更新证书,那么 Let's Encrypt 会自动发邮件至申请证书时所留的邮件地址,提醒更新证书。

Let's Encrypt certificate expiration notice

更新完证书后,还需要让 nginx 重新加载新证书:

sudo gitlab-ctl hup nginx

除了手动执行外,也可以把以上命令加入 cron 任务来定时执行。

使用以下命令来编辑 cron 任务:

sudo su -
crontab -e

在打开的文件中,添加以下内容:

0 3 * * 1 /home/zzz.buzz/certbot/certbot-auto renew && gitlab-ctl hup nginx

以上命令会在每周一的 3 点尝试更新证书,即如果证书将在 30 日内过期,则会被更新,否则将不会被更新;
同时还会发送 HUP 信号给 nginx 进程,以使其加载新证书。

注意将 certbot-auto 的路径替换为实际的路径。

在 GitLab 中应用证书

配置 GitLab 使用 HTTPS 协议

修改 /etc/gitlab/gitlab.rb 文件,配置 external_urlhttps 开头的地址,如:

external_url 'https://gitlab.zzz.buzz'

如果需要将经过 HTTP 的流量重定向至 HTTPS 还需要在 /etc/gitlab/gitlab.rb 文件中,进行如下配置:

nginx['redirect_http_to_https'] = true

配置证书

配置 GitLab 将要使用的证书有两种方式,一种是将之前通过 Let's Encrypt 申请的证书放置到 GitLab 默认要求的配置,如下文链接证书所示;另一种则是修改 GitLab 的配置文件,将证书的路径指向之前通过 Let's Encrypt 申请的证书,如下文修改配置所示。两种方式选一即可。

根据通过 Omnibus 安装的 GitLab 的默认配置,会寻找存放在 /etc/gitlab/ssl/ 目录下的 www.example.com.keywww.example.com.crt 文件,其中的 www.example.com 应当替换为在上文中 external_url 里设置的域名。

我们可以通过如下命令来将之前通过 Let's Encrypt 申请的证书链接到所需的位置。

# 切换至 root 用户(如已是 root 用户,则无需此步)
sudo su -

# 使用 root 用户执行以下命令
mkdir -p /etc/gitlab/ssl
chmod 700 /etc/gitlab/ssl
cd /etc/gitlab/ssl
ln -s ../../letsencrypt/live/www.example.com/fullchain.pem www.example.com.crt
ln -s ../../letsencrypt/live/www.example.com/privkey.pem www.example.com.key

配置方法二:修改配置

修改 GitLab 的配置文件 /etc/gitlab/gitlab.rb,添加以下内容:

nginx['ssl_certificate'] = "/etc/letsencrypt/live/www.example.com/fullchain.pem"
nginx['ssl_certificate_key'] = "/etc/letsencrypt/live/www.example.com/privkey.pem"

启用新配置

配置完成后,使用如下命令启用新配置:

sudo gitlab-ctl reconfigure

参考

Let's Encrypt

GitLab Nginx