如何为Go服务器应用程序设置Let's Encrypt证书

44

我有自己的域名,并使用Go编写了 Web 服务。目前,我正使用内置的 Go Web 服务器,没有在其前面加上 Nginx 或 Apache。

我想开始使用 HTTPS 来提供服务,我在意识到 Let's Encrypt 已成为实现这一目标的主流方式。

有人可以分享在 Linux 服务器上配置运行 Go 应用程序的整个设置过程吗?


5
请使用 https://caddyserver.com/ - 它可以为您完成此操作(颁发证书并代理到您的应用程序)。 - elithrar
2
问题是:如何为Go Web服务器创建证书?如何配置Go Web服务器以使用证书/私钥?还有其他问题吗? - T. Claverie
Go语言自带的crypto/tls包可以从PEM格式文件中加载证书(公钥和私钥)。由Let's Encrypt提供的工具(现在似乎更多地是由EFF推广)可以为您提供该PEM格式文件。因此:1)阅读有关从Let's Encrypt获取证书的指南并执行;2)一旦获得该证书,请查阅如何使crypto/tls读取它并在您的服务器上实现;3)让您的服务器读取您的证书。完成了。 - kostix
换句话说,除非您已经在服务器中实现了配置旋钮来执行此操作,否则无法“配置”您的服务器。由于您很可能尚未这样做,因此可以尝试让它们解析特殊的命令行选项,指定证书路径名,例如“-cert”。 - kostix
相关信息:将所有HTTP流量重定向到HTTPS。https://dev59.com/2FoU5IYBdhLWcg3wYWEM - Benny Jobigan
3个回答

83
我找到了一个使用Go和Let's Encrypt证书进行HTTPS服务器最小自动设置的方法:

以下是示例代码:

package main

import (
    "crypto/tls"
    "log"
    "net/http"

    "golang.org/x/crypto/acme/autocert"
)

func main() {
    certManager := autocert.Manager{
        Prompt:     autocert.AcceptTOS,
        HostPolicy: autocert.HostWhitelist("example.com"), //Your domain here
        Cache:      autocert.DirCache("certs"),            //Folder for storing certificates
    }

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello world"))
    })

    server := &http.Server{
        Addr: ":https",
        TLSConfig: &tls.Config{
            GetCertificate: certManager.GetCertificate,
            MinVersion: tls.VersionTLS12, // improves cert reputation score at https://www.ssllabs.com/ssltest/
        },
    }

    go http.ListenAndServe(":http", certManager.HTTPHandler(nil))

    log.Fatal(server.ListenAndServeTLS("", "")) //Key and cert are coming from Let's Encrypt
}

关于autocert包的更多信息:链接

编辑:由于 letsencrypt安全问题,需要提供http服务,请在此处阅读更多信息。通过此修复,我们现在可以实现 http --> https 的重定向。如果您已经在旧网站上获得了证书,则旧示例将继续工作,但对于新网站将会出现错误。


3
不,这是完整的包。如果您运行此代码,将会看到它创建了一个有效的证书。既然它能够创建,那么也就能更新。我正在运行此代码的服务器至少已经更新过一次证书。 - Pylinux
1
我遇到了两个握手错误,但我无法弄清楚问题所在:“acme/autocert: missing server name”和“acme/autocert: host not configured”。有人可以帮帮我吗? - Marco M
@MarcoM 创建一个新的stackoverflow问题,将你的代码粘贴在里面,我会看一下。 - Pylinux
@Pylinux 提出了一个问题: https://dev59.com/1qDia4cB1Zd3GeqPFYpo - Marco M
1
@Pushan 你使用的是哪个版本的 golang.org/x/crypto/acme/autocert?因为在 master 分支中,这个函数似乎已经存在了:链接 - Pylinux
显示剩余6条评论

37

我找到了一个非常简单的解决方案,使用独立模式。


安装CERTBOT客户端(Let's Encrypt推荐)

(go to the directory where you want to install the certbot client)
git clone https://github.com/certbot/certbot
cd certbot
./certbot-auto --help`


发放证书(首次)

N.B. 此操作通过80端口进行,因此如果您的Go应用程序侦听80端口,则需要在运行此命令之前关闭它(顺便说一下,这个命令运行非常快)

./certbot-auto certonly --standalone-supported-challenges http-01 -d www.yourdomain.com

在您的Go代码中添加SSL监听器

http.ListenAndServeTLS(":443", "/etc/letsencrypt/live/www.yourdomain.com/fullchain.pem", "/etc/letsencrypt/live/www.yourdomain.com/privkey.pem", nil)

完成!


续订证书(证书在90天后过期)

N.B. 您可以手动运行此操作(证书过期前几天会收到电子邮件),或设置一个crontab

如果您的Go应用程序不再侦听端口80,则可以在执行此命令时使Go应用程序继续运行:
./certbot-auto renew --standalone

如果您的Go应用程序仍然侦听端口80,则可以指定停止和重新启动Go应用程序的命令:
./certbot-auto renew --standalone --pre-hook "command to stop Go app" --post-hook "command to start Go app"

有关Certbot命令的完整文档: https://certbot.eff.org/docs/using.html


我也让它工作了,但是使用了“dns”挑战方法,在您的DNS中添加了TXT记录。 - Benny Jobigan
1
关于证书和permkey文件的权限问题怎么处理? 您不应该以root用户身份运行golang服务器/应用程序,但是这些文件却是由root用户拥有的。 - tipograf ieromonah
如何在Certbot更新时重新加载PEM文件而无需重启服务器? - Ruchira Hasaranga

0
如果可以使用DNS验证,那就是续订的方式。
对于使用证书,只需执行以下简单操作:
    c := &tls.Config{MinVersion: tls.VersionTLS12}
    s := &http.Server{Addr: ":443", Handler: Gzipler(nosurf.New(router), 1), TLSConfig: c}
    log.Fatal(s.ListenAndServeTLS(
        "/etc/letsencrypt/live/XXX/fullchain.pem", 
        "/etc/letsencrypt/live/XXX/privkey.pem"
    ))

这个包含了Gzip和CSRF保护。你可以使用它。

Handler: router

没有那些额外的功能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接