上线必须用 go build 生成的二进制文件,因 go run 依赖本地环境、不安全、不可控、无法被进程管理器接管,且与 embed 等特性行为不一致;go build 需注意路径、GOOS/GOARCH、CGO 和证书配置。

上线必须用 go build 生成的二进制文件,别再 go run main.go ——服务器不装 Go 编译器,也没必要。
为什么不能用 go run 上线
go run 是开发时的快捷方式,它会临时编译并执行,依赖本地 GOPATH、go.mod、模块缓存甚至 GOROOT。生产环境既不安全(暴露源码路径、编译器权限),也不可控(进程无守护、崩溃即死)。更关键的是:它根本不是部署行为,只是“跑了一下”。
- 服务器上通常禁用 root 权限,
go命令根本不可用 -
go run启动的进程无法被 systemd / supervisor 管理 - 每次启动都要重新解析依赖、重编译,延迟高、不可预测
- 若用了
embed或//go:embed,go run行为与go build不一致,线上可能出错
go build 的正确姿势和常见坑
核心命令就一句:go build -o myapp main.go。但路径、模块、CGO、目标平台这四点一错,二进制就跑不起来。
- 必须在项目根目录执行,且该目录下要有
go.mod;否则依赖无法解析,报no required module provides package - 确保
GOOS和GOARCH匹配目标服务器(如 Linux x64:GOOS=linux GOARCH=amd64 go build -o myapp main.go) - 若项目含 C 代码(比如 SQLite 驱动),需关 CGO:
CGO_ENABLED=0 go build -o myapp main.go,否则二进制动态链接 libc,换机器就报not found - 别把
go.mod、go.sum、vendor/一起传到服务器——二进制已静态链接全部逻辑,多传是冗余,还可能被误当配置读取
上线后怎么管住这个进程
别用 nohup ./myapp & 或 screen ——它们不参与系统生命周期,重启服务器后服务就没了,崩溃也不会自动拉起。
立即学习“go语言免费学习笔记(深入)”;
- Linux 推荐用 systemd:写一个
/etc/systemd/system/myapp.service,里面指定ExecStart=/opt/myapp/myapp、Restart=always、User=www-data - 记得
sudo systemctl daemon-reload && sudo systemctl enable myapp && sudo systemctl start myapp - 检查状态:
systemctl status myapp,看日志:journalctl -u myapp -f - 如果用 Docker,
CMD ["./myapp"]即可,但注意 WORKDIR 和文件权限(chmod +x ./myapp)
HTTPS 和 HTTP 重定向必须手动处理
Gin 没有“开箱即用”的 HTTPS 开关,RunTLS 只是封装,证书路径错、权限错、链不全,都会静默失败或连接拒绝。
-
r.RunTLS(":443", "cert.pem", "key.pem")最简,但只适合开发;生产务必用&http.Server手动构造,才能设ReadTimeout、IdleTimeout、TLSConfig.MinVersion - HTTP 自动跳 HTTPS 必须另起一个
http.Server监听:80,用http.Redirect发送http.StatusMovedPermanently(301),别用默认的 302 - 证书路径要用绝对路径,或确保工作目录是二进制所在目录;私钥权限必须是
0600,否则 Go 拒绝加载(错误提示常误导为“key doesn’t match”) - Let’s Encrypt 的证书要用
fullchain.pem(不是cert.pem),否则 iOS 和部分安卓客户端会报x509: certificate signed by unknown authority
最易被忽略的点:上线前没验证 X-Forwarded-Proto 头是否透传。Nginx/Apache 反向代理后,Gin 看不到真实协议,c.Request.TLS 永远为 nil,导致重定向永远拼成 http://,Cookie 的 Secure 标志失效,前端登录态直接崩。


















