Revel应用必须编译为静态二进制部署,不可用go run;需确保conf/、public/、views/路径可访问,推荐revel build内嵌资源,手动go build须显式调用revel.Init()和revel.Run()并导入app包,否则路由注册失败导致404。

Revel 应用不能直接 go run 部署到裸机——它依赖源码结构、conf/ 目录和热重载机制,这些在生产环境完全失效。必须编译为静态二进制,并确保运行时能访问 conf/、public/ 和 views/ 这三个路径。
用 revel build 打包带资源的二进制
这是最省心的方式:它会把 conf/、public/、views/ 全部内嵌进可执行文件,避免部署时漏掉静态资源或配置。
-
revel build myapp /tmp/myapp生成完整目录结构,含run.sh、conf/app.conf和二进制文件 - 输出目录里
myapp是主二进制,run.sh只是简单包装:./myapp -import="myapp" -port="9000" - 若项目用了自定义
app.Init()或revel.NewApp(),务必确认import _ "myapp/app"在main.go中存在,否则路由注册失败、所有请求返回 404 且无报错 - 别改
run.sh里的-import参数名——它必须和go.mod的 module 名或 GOPATH 路径严格一致,否则启动时找不到应用入口
手动 go build 的关键参数与陷阱
当需要精细控制(比如禁用 CGO、指定目标平台)时,得绕过 revel build,但代价是自己处理资源路径和初始化逻辑。
- 必须显式启用静态链接:
CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' -o myapp . - 检查是否真静态:
file myapp输出应含statically linked;否则在 Alpine 等精简系统上会报no such file or directory(实为缺 libc) - 如果用了
github.com/mattn/go-sqlite3等 CGO 驱动,则CGO_ENABLED=1不可省,且构建机需装gcc和sqlite3-dev -
main.go必须调用revel.Init()+revel.Run(),且顶部有import _ "myapp/app"—— 缺一不可,否则启动成功但无路由
裸机部署时必须挂载的三个路径
即使二进制是静态的,Revel 启动时仍会尝试读取某些路径。内嵌资源只覆盖 public/ 和 views/,conf/ 永远不内嵌(因为要支持运行时修改)。
-
conf/是强制挂载项:启动前必须存在,且含有效的app.conf;否则 panic 报错open conf/app.conf: no such file or directory -
logs/不是必须,但建议创建并赋写权限,否则日志全打到 stdout,不利于排查 -
public/在revel build后可省略(已内嵌),但手动go build未打包资源时,必须保留原目录结构并确保http.static.dir指向它 - 运行命令示例:
./myapp -import="myapp" -port="8080" -conf="./conf" -log="./logs"
验证二进制能否真正跑起来
别急着 systemctl enable,先做三件事:看启动、看监听、看首屏。
- 执行
./myapp -h:能正常输出帮助说明 flag 解析没问题;若直接 panic,大概率是缺失import _ "myapp/app"或 CGO 环境不匹配 - 用
lsof -i :8080(或ss -tuln | grep 8080)确认端口已监听,且绑定地址是127.0.0.1:8080(非0.0.0.0) - curl
http://127.0.0.1:8080/assets/css/app.css:能返回 CSS 内容,说明静态资源路径和服务都通;404 则检查conf/app.conf是否设了http.static.enable = true - 最后才配 systemd:注意
WorkingDirectory要指向含conf/的目录,ExecStart里不要漏-conf参数
最容易被忽略的是:revel build 生成的二进制默认不读当前目录的 conf/app.conf,它只认启动时用 -conf 显式指定的路径;而手动 go build 出来的二进制,哪怕加了 -conf,也会因初始化顺序问题静默 fallback 到当前目录——这种不一致会让排查变得极其耗时。











