go二进制需先go build生成绝对路径可执行文件并设chmod +x,再写入systemd service的execstart;必须显式指定user、workingdirectory、type=simple、environment,并用log.setoutput(os.stdout)适配journal日志。

Go 二进制怎么写进 systemd service 文件
systemd 不认 Go 源码,只认可执行文件路径。你得先 go build 出一个干净的二进制(最好加 -ldflags="-s -w" 去掉调试信息),再把它的绝对路径写进 ExecStart。
常见错误是用相对路径、或把 go run main.go 直接塞进 ExecStart —— 这会导致启动失败,日志里只显示 Failed at step EXEC spawning go: No such file or directory(因为 systemd 不加载 shell 环境,找不到 go 命令)。
- 二进制必须有可执行权限:
chmod +x /opt/myapp/myapp -
User字段建议显式指定(比如User=www-data),别依赖 root;Go 程序通常不需要 root,除非监听:80或访问特殊设备 -
WorkingDirectory要设,尤其你的程序读配置文件或写日志时依赖当前路径 - 别漏
Type=simple(默认值,但显写更稳);如果程序 fork 自己成 daemon,得改Type=forking并配好PIDFile
环境变量和标准输入输出怎么处理
systemd service 默认不继承 shell 的 env,os.Getenv 拿不到你在终端里 export 的变量。日志也不会自动刷到 journal,fmt.Println 可能卡住或丢行。
Go 程序本身要适配:用 log.SetOutput(os.Stdout) 把日志导向 stdout,systemd 会自动收走;别写文件日志(除非你真需要落盘),否则得额外配 ReadWritePaths 权限。
- 环境变量统一在 service 文件里用
Environment=写,例如:Environment="APP_ENV=prod" "PORT=8080" - 想加载
.env文件?不行 —— systemd 不解析它;要么提前用脚本 source 后 exec,要么让 Go 程序自己读(推荐用godotenv库) - stdin 默认被关闭,
os.Stdin是 nil;别在 main 里等用户输入,会 hang 住整个服务
启动失败时怎么看日志和状态
别急着查 /var/log/syslog 或自己写的 log 文件 —— 先用 journalctl。systemd 把所有 stdout/stderr 都打了时间戳、带 unit 名,比手动日志可靠得多。
典型错误现象:Active: inactive (dead) 但没报错;其实是程序启动后立刻 panic 退出了,journal 里一定有 panic: 行,只是你没翻到。
- 看最近一次启动日志:
journalctl -u myapp.service -n 50 -f - 查完整历史(含启动前的 env 和 cgroup 信息):
journalctl -u myapp.service --no-pager - 如果日志空空如也,八成是
ExecStart路径错了,或者 binary 缺共享库(用ldd /path/to/binary检查) -
systemctl status myapp.service输出里的Process: XXX ExecStart=...那行,就是实际执行命令,对照看有没有拼写/空格问题
开机自启、重启策略和信号处理要注意什么
Go 程序默认不响应 SIGHUP 或 SIGTERM,systemd 发完终止信号就直接 kill -9,可能导致连接没 graceful shutdown、临时文件没清理。
service 文件里 Restart=on-failure 很常用,但别设成 always —— 如果程序一启动就 panic,systemd 会疯狂拉起,打满 CPU。
- 加
RestartSec=5控制重启间隔,避免雪崩 - Go 里用
signal.Notify接os.Interrupt和syscall.SIGTERM,做超时退出(比如 10 秒内关掉 HTTP server) - 开机自启只用一句:
systemctl enable myapp.service;注意它只是建 symlink,不是立即启动 - 如果程序要等网络就绪(比如连 PostgreSQL),加
After=network-online.target和Wants=network-online.target,否则可能抢在网卡 up 前启动失败
最常被忽略的是工作目录和用户权限 —— Go 程序跑在 systemd 下,不是你 ssh 登录时那个家目录,也不是那个 umask,更不是那个 PATH。每个路径、每个环境变量、每个信号,都得显式声明清楚。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











