iT邦幫忙

2021 iThome 鐵人賽

DAY 15
0
Modern Web

網站一條龍 - 從架站到前端系列 第 15

[Day15] 幫我們的網站設定 SSL 憑證

  • 分享至 

  • xImage
  •  

截至目前為止,我們的 .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 裡或者自幹讀寫功能了。咱們明天見~


上一篇
[Day14] 架設 Nginx 當我們的 Web Server
下一篇
[Day16] MySQL 簡介
系列文
網站一條龍 - 從架站到前端33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言