在去年寫了一篇『申請 Let’s Encrypt 免費憑證讓網站支援 HTTP2』教學,如果您是用 Nginx,就可以參考該篇教學讓您的伺服器支援 HTTPS,而 Google Security Blog 也宣布在 56 版本以後將會提示 non-secure 網站,讓使用者可以選擇性瀏覽網站。Let’s Encrypt 官方也公布去年 2016 發了多少張憑證,相當驚人,想必大家對 HTTPS 已經有相當程度的瞭解。底下這張圖說明 2016 年 Let’s Encrypt 發憑證總量的狀況
此篇會介紹在 Go 語言如何跟 Let’s Encrypt 串接,底下有兩種方式。
使用 Caddy 伺服器
大家可以把 Caddy 想成跟 Nginx 同等關係,不同的是 Caddy 是一套完全用 Go 語言打造的伺服器,這邊就會介紹 Caddy 怎麼設定 HTTPS 憑證。先假設 domain 為 example.com,底下就是讓此 domain 自動掛上憑證的Caddyfile
設定檔
example.com { proxy / localhost:3000 }上面設定會自動將
http
轉換成 https
,也就是在瀏覽器鍵入 http://example.com Caddy 會自動換成 https://example.com。如果是 Nginx 呢?看看底下設定
server { listen 0.0.0.0:80; server_name example.com; location /.well-known/acme-challenge/ { alias /var/www/dehydrated/; } return 301 https://example.com$request_uri; } server { # listen 80 deferred; # for Linux # listen 80 accept_filter=httpready; # for FreeBSD listen 0.0.0.0:443 ssl http2; ssl_certificate /etc/dehydrated/certs/example.com/fullchain.pem; ssl_certificate_key /etc/dehydrated/certs/example.com/privkey.pem; # The host name to respond to server_name codeigniter.org.tw; }很明顯可以看出,用 Caddy 大勝 Nginx 設定檔簡易程度。另外 Let’s Encrypt 憑證會在三個月後過期,如果是使用 Caddy,可以不用擔心過期問題,Caddy 會自動在三個月內幫忙更新憑證有效日期,如果是 Nginx,請寫 Script 並且放到 Crontab 內。結論就是 Caddy 自動幫忙處理申請+更新憑證,而 Nginx 都必須手動打造。
使用 Go 語言 autocert package
相信很多 Go 開發者不希望前面有 Proxy Server 像是 Caddy 或 Nginx,而是希望 Go Binary 可以直接 Listen 443 port,這樣好處就是 Performance 會是最好,缺點就是一台機器只能使用一個 application。而 Go 語言要實現整合 Let’s Encrypt 相當容易,只需要引入 autocert 套件,底下是範例程式碼: (使用 Gin framework)程式碼範例
package main import ( "crypto/tls" "net/http" "github.com/gin-gonic/gin" "golang.org/x/crypto/acme/autocert" ) func main() { r := gin.Default() // Ping handler r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) m := autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"), Cache: autocert.DirCache("/var/www/.cache"), } s := &http.Server{ Addr: ":https", TLSConfig: &tls.Config{GetCertificate: m.GetCertificate}, Handler: r, } s.ListenAndServeTLS("", "") }程式碼內有兩個地方需要注意,一個是
HostWhitelist
這是綁定特定 Domain,請務必填寫,當然你也可以填空,但是這樣任意 Domain 指向你的機器,就可以直接對 Let’s Encrypt 請求憑證,所以請務必填上自己的 Domain,另一個是 DirCache
這是憑證存放的目錄,你可以任意指定到其他目錄,第一次請求會比較久,原因是憑證還沒下來。上面範例你會發現,哪是一行,看起來就是好幾行才完成此功能,在不久之前(本週) @bradfitz (Go 語言 HTTP 核心開發者) 開發了 Listener
函示 (相關 Commit),讓開發者可以用一行取代上面冗長的程式碼:
程式碼範例
package main import ( "log" "net/http" "github.com/gin-gonic/gin" "golang.org/x/crypto/acme/autocert" ) func main() { r := gin.Default() // Ping handler r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) log.Fatal(http.Serve(autocert.NewListener("example1.com", "example2.com"), r)) }現在只要填入您的 Domain 就可以綁定憑證及自動更新 (不必擔心三個月會過期),這邊你會問,那憑證是放在哪裡呢?
- MacOS 放在
/Users/xxxx/Library/Caches/golang-autocert
- Windows
${HOMEDRIVE}/${HOMEPATH}
加上依序先找APPDATA
,CSIDL_APPDATA
,TEMP
,TMP
全域變數的目錄 - Linux 放在家目錄內
.cache/golang-autocert
目錄
XDG_CACHE_HOME
變數來轉換您想要的目錄。請在 Dockerfile 內放入
ENV XDG_CACHE_HOME /var/lib/.cache這樣 docker 會把憑證放在
/var/lib/.cache/golang-autocert
內,使用者不用管憑證放哪裡,因為就算消失了,下次重新啟動,自然會在產生一次。最後要講的是,如何用 Go 語言實現 http
轉到 https
呢?非常簡單,請參考底下程式碼
程式碼範例
var g errgroup.Group g.Go(func() error { return http.ListenAndServe(":http", http.RedirectHandler("https://example.com", 303)) }) g.Go(func() error { return http.Serve(autocert.NewListener("example.com"), handler) }) if err := g.Wait(); err != nil { log.Fatal(err) }