[Day15] 帮我们的网站设定 SSL 凭证

截至目前为止,我们的 .NET Web API 都是使用开发者凭证,浏览器并不承认这个凭证,所以每次发 request 到我们的 API,浏览器都会警告我们。今天,我们就来介绍一下如何替我们的 Nginx 加上 SSL 凭证,让我们的浏览器不再罗哩罗嗦。

什麽是 SSL 凭证

简单来说,就是替我们的网站申请一张良民证,让别人信任我们的网站,然後透过加密连线(https)连到我们我们的网站。资安这块笔者实在没天分,无法分享更多东西,就连部落格或技术文章也没找到自己觉得很好啃的,这里就请邦友自己 Google 找跟自己缘分合得来的资料了。

Let’s Encrypt

身为开发者自己玩,当然要尽量当免费仔,SSL 凭证当然也不例外。本篇文章我们要介绍一个广为人知的免费 SSL 凭证发行机构: Let’s Encrypt。它提供了大多数浏览器都承认的免费 SSL 凭证,虽然期限只有 90 天,但是可以免费更新(renew)。

因为每三个月都要手动更新很麻烦,而且有时候忘记更新也可能出问题,所以後来就有一个叫做 Certbot 的软件来帮我们完成这些麻烦的事,只要在 Linux 上下下指令就能帮我们产生凭证、修改 Nginx 设定档、自动更新凭证,真香!Let’s Encrypt 官网甚至直接开传送门,让我们连到 Certbot 官网跟着步骤做,BUT!!! 笔者分别在今年 4 月跟 8 月都试过 Certbot 官网的步骤,都会出现错误,Google 爬了一下文看别人说这是 VM 映像档的 Hyper-V bug。

笔者最後也找不到方法解决个问题,而是放弃了 Certbot 官网的步骤,改从一篇部落格找到可以 work 的方法,果然高手在民间阿XD

开始之前

申请 SSL 凭证的时候我们会需要一个固定的 IP 或一个域名(domain name, 简单的理解就是网址斜线(/)前面那一串啦)。不过,由於免费的凭证发行者不提供纯 IP 的凭证,如果要专为一个 IP 申请凭证,不仅要钱申请也麻烦。再加上 SSL 凭证绑定 IP,如果以後我们想把 VM 换到其他地方就又更麻烦,所以笔者还是建议到其他网路供应商看看,趁特价的时候买一个域名。

笔者自己是在 GoDaddy 上面买了一个冷门的域名,第一年好像不到 100 台币。买完域名之後,需要设定一下 DNS(domain name server),DNS 简单来说就是让我们用网址查询真正 IP 的服务器,更多关於 DNS 的知识请参考这篇文章。设定 DNS 的介面各家厂商间不尽相同,不过大致上都只要设定这 A 纪录跟 CNAME,其他的用厂商的预设值就好

  • A 纪录(A Record)- 设定我们的域名所要指向的 IP,也就是我们 VM 的外部 IP
  • CNAME 把这个域名指向另外一个域名。例如把 www.testdomain.tw 指向 testdomain.tw,然後 testdomain.tw 再指向 VM 的外部 IP

笔者自己在 GoDaddy 上的设定如下,供各位参考
https://ithelp.ithome.com.tw/upload/images/20210915/20140664qP6cUE9ov6.png

终於要开始了

终於真正来到要装 SSL 凭证的步骤了。首先一样用 SSH 连到我们的 VM,然後透过 yum 安装 Certbot。

sudo yum install certbot-nginx

与 Nginx 一样,Certbot 是被包含在 EPEL (Extra Packages for Enterprise Linux) 这个 Package 之中。GCP 的 CentOS 内建这个 EPEL所以可以直接安装,如果邦友是用 DigitalOcean 的 CentOS,会需要先安装 EPEL
sudo yum install epel-release

接着,修改我们的 nginx 设定档,把之前的 server_name 改成我们申请的域名
vi sudo vi /etc/nginx/conf.d/ironman.conf

server {
    listen        80;
    server_name   mydomain.com www.mydomain.com; #这边改成我们申请的域名
	# 其他设定不变
}

接着,输入 Certbot 指令产生并设定凭证
sudo certbot --nginx -d mydomain.com -d www.mydomain.com

这里稍微解释一下,这个指令的 --nginx 就是叫 Certbot 去找我们的 Nginx 设定档,帮我们申请 SSL 凭证并自动修改 Nginx 设定。因为我们前面的 Nginx 设定档中有两个域名(mydomain.com 与 www.mydomain.com),所以需要输入两次 -d 把两个域名都告诉 Certbot

产生凭证的过程中,certbot 会要求提供几个资讯

  1. email - 凭证快过期或需要紧急更新的时候会寄发通知
  2. 确认读过服务条款 - 直接输入 Y
  3. 是否愿意分享 email 给 EFF - EFF 基金会是 Let's Encrypt 的夥伴,是个非营利组织,如果分享 email,他们会寄一些资讯给你。这边笔者选 N

有时候 certbot 会出现莫名的错误,重新跑一次指令可能就会过
https://ithelp.ithome.com.tw/upload/images/20210915/20140664LyskQTm66c.png

执行完毕後会发现 Certbot 已经帮我们存好 SSL 凭证档案,并且修改 Nginx 设定档

server {
    server_name   mydomain.tw www.mydomain.tw; # 我们的域名
    location / {
        proxy_pass         http://127.0.0.1:5000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/goattl.tw/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/goattl.tw/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot


}
server {
    if ($host = www.mydomain.tw) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = mydomain.tw) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen        80;
    server_name   mydomain.tw www.mydomain.tw;
    return 404; # managed by Certbot
}

修改 API 程序

如果这个时候输入 https://外部IP/api/User 会发现浏览器仍然不信任我们的凭证,点开凭证资讯看,会发现我们的 API 程序还在用 localhost 的开发者凭证。要解决这个问题,我们要修改一下我们的 API 程序,在 Startup.cs 里使用 UseForwardedHeaders 中介软件(middleware)

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // 加入这段
    app.UseForwardedHeaders(new ForwardedHeadersOptions
    { 
        ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
    });
    // 後面不变
}

接着重新发布(publish)我们的 API 程序然後重启 systemd service,然後再重新连到 https://申请的域名/api/User 就能顺利取从我们的 API 取得资料,而且我们的网址上了锁头,浏览器不再警告了。

https://ithelp.ithome.com.tw/upload/images/20210915/201406645paXH4wNR0.png

设定自动更新(renew)凭证

设定排成前请注意 GCP VM 预设是 +0 时区,编辑 crontab 排程的时候要自己推算一下时间,或者使用 sudo timedatectl set-timezone Asia/Taipei 把 VM 变成台湾的 +8 时区。

最後,我们要透过 Linux 的排成管理功能 cron 帮我们做自动更新。要编辑排成我们需要编辑自己的 crontab
sudo crontab -e
输入上面这行指令後,会自动开启 vim 编辑排程内容,在我们的排程内容中加入类似下列的指令。
59 23 * * * /usr/bin/certbot renew --quiet

crontab 的排程,前面的五个数字分别代表 分、时、日、月、DayOfWeek(礼拜几),星号代表不限,以上面的指令为例,cron 会在每天的 23:59 帮我们执行 certbot renew --quiet 指令。後面的路径帮 cron 找到 certbot,renew 是 certbot 指令,--quiet 表示不要显示讯息。

告一段落

飞上云端架设 VM 的文章暂时告一段落,廷天开始我们要再回到地上,简单的介绍 MySQL,我们就不用把资料写死在 code 里或者自干读写功能了。咱们明天见~


<<:  Day 15 实作测试 (1)

>>:  [Day1]前言:为何选择学习区块链?

资料驱动的元件

资料驱动绘制 (Model-driven Rendering) 英雄列表范例已经初步展示过 List...

浅谈分支预测与 Hazards 议题

本篇章介绍经常发生在 Pinpline 上的潜在伤害 (Hazards) 以及针对各种 Case 所...

Navigation (2)

在 Android,navigation graph 是 resource 的一种,我们先建立 et...

玩转 Storybook: Day 30 总结 & 学习资源

根据研究指出,重用程序码可以节省42–81%的时间,并提高生产力 40%。易於共享UI元件的Desi...

Day4 VPC & Security Group

从地端 On-Premise的传统资讯部署,再到云端 Cloud的新形态部署模式,在这个转型过程初...