我将从最基础的例子开始,逐步深入到更高级和安全的配置。

最简单的 HTTPS 服务器
这个例子将使用 Go 标准库 net/http 和 crypto/tls 来创建一个 HTTPS 服务器,为了方便测试,我们将使用 Go 内置生成的自签名证书。
步骤 1: 生成自签名证书(仅用于测试)
在运行代码之前,你需要一个证书文件 (cert.pem) 和一个私钥文件 (key.pem),在终端中执行以下命令:
# 生成一个 2048 位的 RSA 私钥 openssl genrsa -out key.pem 2048 # 使用私钥生成一个自签名证书 openssl req -new -x509 -key key.pem -out cert.pem -days 365
在生成证书时,它会问你一些信息,比如国家、城市等,你可以直接按回车跳过,或者随意填写。
步骤 2: 编写 Go 代码
创建一个名为 main.go 的文件,并写入以下代码:

package main
import (
"fmt"
"log"
"net/http"
)
// 定义一个处理函数
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, HTTPS! This is a secure connection.")
}
func main() {
// 1. 定义处理函数的路径
http.HandleFunc("/", handler)
// 2. 指定证书和密钥文件
certFile := "cert.pem"
keyFile := "key.pem"
// 3. 启动 HTTPS 服务器
// 使用 http.ListenAndServeTLS,它会监听指定端口并处理 TLS 连接
// 函数签名: ListenAndServeTLS(addr, certFile, keyFile, handler)
log.Printf("Server starting on https://localhost:8443...")
err := http.ListenAndServeTLS(":8443", certFile, keyFile, nil)
if err != nil {
log.Fatal("ListenAndServeTLS error: ", err)
}
}
步骤 3: 运行和测试
-
运行服务器:
go run main.go
你会看到日志输出:
Server starting on https://localhost:8443... -
测试:
- 打开你的浏览器,访问
https://localhost:8443。 - 浏览器会显示一个安全警告,因为这是一个自签名证书,不被浏览器信任,点击“高级” -> “继续访问”。
- 如果一切正常,你应该会看到页面显示 "Hello, HTTPS! This is a secure connection."。
- 打开你的浏览器,访问
更健壮和安全的 HTTPS 服务器
在生产环境中,直接使用 ListenAndServeTLS 可能不够灵活和安全,更推荐的方式是手动创建一个 tls.Config 结构体,这样可以更精细地控制 TLS 的行为,例如强制使用特定的 TLS 版本和密码套件。

代码示例
package main
import (
"crypto/tls"
"fmt"
"log"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from a more secure HTTPS server!")
}
func main() {
// 1. 创建一个多路复用器 (Mux)
// 虽然可以直接用 http.DefaultServeMux,但创建自己的 Mux 是更好的实践
mux := http.NewServeMux()
mux.HandleFunc("/", handler)
// 2. 配置 TLS
// 创建一个 tls.Config 结构体
tlsConfig := &tls.Config{
// 强制使用 TLS 1.2 或更高版本,禁用不安全的旧版本
MinVersion: tls.VersionTLS12,
// 指定支持的密码套件,优先使用更安全的 ECDHE 算法
// 这是一个推荐的密码套件列表,可以根据需要调整
CipherSuites: []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
},
// 优先选择客户端和服务器都支持的、安全性最高的密码套件
PreferServerCipherSuites: true,
// 可选:启用 HTTP/2 支持
// Go 1.6+ 会自动在支持 TLS 的连接上尝试 HTTP/2
// 显式设置可以确保行为符合预期
NextProtos: []string{"h2", "http/1.1"},
}
// 3. 创建服务器结构体
server := &http.Server{
Addr: ":8443", // 监听地址和端口
Handler: mux, // 设置路由处理器
TLSConfig: tlsConfig, // 应用我们自定义的 TLS 配置
}
// 4. 启动服务器
log.Printf("Secure server starting on https://localhost:8443...")
// 使用 Server 的 ListenAndServeTLS 方法
err := server.ListenAndServeTLS("cert.pem", "key.pem")
if err != nil {
log.Fatal("Server error: ", err)
}
}
代码解析
-
tls.Config:MinVersion: tls.VersionTLS12: 强制要求客户端至少使用 TLS 1.2,这是非常重要的安全措施,可以防止如 POODLE 这样的旧漏洞。CipherSuites: 显式指定服务器支持的加密算法,我们选择的是目前认为非常安全的现代算法组合,优先选择前向保密的 ECDHE 算法。PreferServerCipherSuites: true 表示当客户端和服务器都支持多个密码套件时,优先使用服务器配置中靠前的、安全性更高的套件。NextProtos: 用于应用层协议协商。"h2"代表 HTTP/2,"http/1.1"代表 HTTP/1.1,Go 会自动处理 HTTP/2 的协商。
-
http.Server:- 将
tls.Config赋值给Server的TLSConfig字段,使得整个服务器都应用这个安全配置。
- 将
使用 Let's Encrypt 获取免费证书(生产环境推荐)
在生产环境中,绝对不要使用自签名证书,你应该使用由受信任的证书颁发机构(CA)签发的证书,Let's Encrypt,它提供免费的自动化证书。
最常用的工具是 certbot。
步骤 1: 安装 Certbot
根据你的操作系统,参考官方安装指南。
步骤 2: 获取证书
假设你的服务器域名为 myawesomego.com。
# 使用 certbot 获取证书 # --standalone 模式会临时启动一个 web 服务器来验证域名所有权 # -d 指定域名 # --email 指定邮箱,用于接收续期提醒和证书失效通知 # --agree-tos 同意服务条款 sudo certbot certonly --standalone -d myawesomego.com --email your-email@example.com --agree-tos
执行成功后,证书文件会存放在 /etc/letsencrypt/live/myawesomego.com/ 目录下:
fullchain.pem: 完整的证书链(你的证书 + 中间证书)privkey.pem: 你的私钥
步骤 3: 修改 Go 代码
修改你的 Go 代码,使用 Let's Encrypt 提供的证书文件路径。
package main
import (
"crypto/tls"
"fmt"
"log"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from a production-ready HTTPS server!")
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", handler)
// Let's Encrypt 证书路径
certFile := "/etc/letsencrypt/live/myawesomego.com/fullchain.pem"
keyFile := "/etc/letsencrypt/live/myawesomego.com/privkey.pem"
// 为了安全,可以加载并验证证书
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
log.Fatalf("Error loading certificate: %v", err)
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS12,
// ... 其他安全配置 ...
}
server := &http.Server{
Addr: ":443", // 生产环境通常使用 443 端口
Handler: mux,
TLSConfig: tlsConfig,
}
log.Printf("Production server starting on https://myawesomego.com...")
err = server.ListenAndServeTLS("", "") // 证书已在 tls.Config 中加载,这里传空字符串
if err != nil {
log.Fatal("Server error: ", err)
}
}
注意: 在上面的例子中,我们通过 tls.LoadX509KeyPair 加载了证书,并将其放入 tls.Config 的 Certificates 字段,这样在调用 ListenAndServeTLS 时,第三个和第四个参数(证书和密钥文件路径)就可以为空字符串了。
步骤 4: 设置自动续期
Let's Encrypt 的证书有效期为 90 天,你必须手动续期,为了避免忘记,可以设置一个定时任务(cron job)。
# 编辑 crontab sudo crontab -e
添加以下行,让它每天检查并自动续期:
# 每天凌晨 2 点自动续期 Let's Encrypt 证书,并重启 Go 服务 0 2 * * * /usr/bin/certbot renew --quiet && /bin/systemctl restart my-go-service.service
注意: 你需要将 /bin/systemctl restart my-go-service.service 替换为你实际重启 Go 服务的命令,你的 Go 服务会以 systemd 服务的形式运行。
| 场景 | 方法 | 关键点 | 适用性 |
|---|---|---|---|
| 快速测试/开发 | http.ListenAndServeTLS |
简单直接,使用自签名证书。 | 本地开发、临时测试。 |
| 生产环境/高安全 | http.Server + tls.Config |
精细控制 TLS 版本、密码套件,配置更安全。 | 所有需要自定义安全策略的生产环境。 |
| 生产环境/真实域名 | Let's Encrypt + certbot |
使用受信任的免费证书,需配置自动续期。 | 任何面向公网的网站或服务。 |
希望这份详细的指南能帮助你理解和创建 Golang 的 HTTPS 服务器!
