从源码构建
入口有两个,互为等价的薄壳,任选其一:
入口 构建命令 仓库根 main.gogo build -o GoPanel .cmd/gopanel/main.gogo build -o GoPanel ./cmd/gopanel两者都只做转发,真正的启动编排在
internal/app,行为完全一致。
环境要求
| 工具 | 版本 | 说明 |
|---|---|---|
| Go | ≥ 1.26 | 与 go.mod 的 go 指令一致 |
| Node.js | ≥ 22 | 构建前端 SPA;只构建后端时可不装 |
| npm | ≥ 10 | 仓库根也带 pnpm-lock.yaml,用 pnpm 亦可 |
国内网络建议先设模块代理:
go env -w GOPROXY=https://goproxy.cn,direct最短路径(三行)
git clone https://cnb.cool/liumou_site/GoPanel.git
cd GoPanel
# 1. 构建前端(产物 frontend/management/dist —— 正是 go:embed 的目标,无需复制)
cd frontend/management && npm ci && npm run build && cd ../..
# 2. 构建后端(前端产物被 go:embed 原地打进二进制)
go build -o GoPanel . # 等价写法:go build -o GoPanel ./cmd/gopanel跑起来:
./GoPanel # 默认监听 12395(会去读 config/config.toml,缺失则用环境变量/内置默认值)
./GoPanel -version # 只看版本号
./GoPanel -h # 看全部参数浏览器打开 http://localhost:12395/,未初始化时会直接跳转安装向导。
embed 在哪、为什么不用复制
前端不是外挂目录,而是编译期嵌进二进制的:
// frontend/embed.go
//go:embed all:management/dist
var distFS embed.FS关键点:go:embed 的路径是相对本包目录的,而本包就在 frontend/ 下, vite 的输出恰好也在 frontend/management/dist —— 于是嵌入目录 = 构建产物目录, 一条相对路径就够,npm run build 之后直接编译,中间不需要任何复制动作。
frontend/
├── embed.go //go:embed all:management/dist
└── management/dist/ ← npm run build 的原始输出(真实产物不入库)干净的 git 检出任然能 go build:.gitignore 只放行一个占位 index.html (/frontend/management/dist/* + !/frontend/management/dist/index.html), 保证 //go:embed 在目录为空时不会以 pattern all:management/dist: no matching files found 报错。
注意:嵌入的是你构建时那一刻的 dist。先
go build再改前端,二进制里仍是旧页面 —— 改了前端记得重新编译。
读取规则:磁盘优先、embed 兜底
- 容器内发布形态:产物已嵌在二进制里,运行时不需要任何外挂文件
- 本机源码运行:进程还能从磁盘
frontend/management/dist读到刚构建的产物, 改完前端不必重编译后端(internal/server.WithAssetsDir,目录不存在则自动跳过)
为什么 embed 不放在根包
go:embed 只能嵌入本包目录及其子目录,不允许 ..。internal/server 需要导入 SPA 处理器,若它反向导入根包就构成 import cycle。所以:
- 嵌入放在
frontend/embed.go(只依赖embed/io/fs,零第三方依赖) - HTTP 处理器放在
internal/handler/frontend(只依赖 gin) - 两个入口(根
main.go/cmd/gopanel/main.go)调用frontend.Assets()后 经server.WithAssets(...)注入
三方互不反向依赖,既无 ../、也无循环。
数据库支持与构建标签
后端自带 GORM,四个数据库默认全部可用,无需额外标签:
mysql / mariadb / postgres / sqlite
SQLite 走纯 Go 驱动(github.com/glebarez/sqlite,不依赖 CGO), 所以 CGO_ENABLED=0 也能开箱用 SQLite。
只做本地调试时,可以完全不装数据库:
GOPANEL_DB_TYPE=sqlite GOPANEL_DB_PATH=config/gopanel.db ./GoPanel官方镜像(
Dockerfile.backend等)在编译时仍带-tags db_sqlite, 这是为了兼容历史构建脚本,不影响源码构建的使用。
交叉编译 / 自己出发布包
发布产物命名与安装脚本约定一致:GoPanel-linux-<arch>[-softfloat]。
# amd64
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -tags db_sqlite -ldflags "-s -w" -o GoPanel-linux-amd64 .
# arm64
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 \
go build -tags db_sqlite -ldflags "-s -w" -o GoPanel-linux-arm64 .
# armv7(32 位 arm 约定加 -softfloat 后缀)
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 \
go build -tags db_sqlite -ldflags "-s -w" -o GoPanel-linux-arm-softfloat .想让「面板里的版本号 / 检查更新」显示正确,可以在构建期注入:
go build -o GoPanel . \
-ldflags "-X cnb.cool/liumou.site/GoPanel/internal/bootstrap.build.Version=v1.0.0 \
-X cnb.cool/liumou.site/GoPanel/internal/bootstrap.build.Commit=$(git rev-parse --short HEAD) \
-X cnb.cool/liumou.site/GoPanel/internal/bootstrap.build.BuildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)"运行期还可用
GOPANEL_VERSION/GOPANEL_COMMIT/GOPANEL_BUILD_TIME覆盖(环境变量优先)。
注意事项
- 不要提交前端产物:
frontend/management/dist/*(仅index.html占位入库) (除占位index.html)都在.gitignore里 go build请带-o:裸跑go build/go build ./...会在仓库根留下一个 150MB+ 的无扩展名二进制,被 gvt 提交钩子的「无扩展名二进制」检查拦下- 只改后端、图快可以先跳过前端:沿用仓库里已有的
frontend/management/dist产物直接编译 - 前端构建报错时,先确认 Node 版本够新(
node -v),依赖用npm ci而非npm install
可选:用脚本一条命令跑通
仓库自带本地调试脚本,把「前端构建 → 复制产物 → 交叉编译 → 起镜像 + 数据库」串起来:
sh docker-compose/dev/build.sh # postgres + 构建 + 启动
sh docker-compose/dev/build.sh --db=mysql # 换 MySQL / mariadb
sh docker-compose/dev/build.sh --no-start # 只构建产物落在 docker-compose/dev/artifacts/(GoPanel 二进制 + frontend-dist/)。
前端开发模式
cd frontend/management
npm ci
npm run dev # http://localhost:3003开发服务器把 /api、/captcha、/term、/server 代理到后端, 目标地址由 frontend/management/.env.development 的 VITE_API_PROXY_TARGET 控制 (默认 http://localhost:12395)。
质量检查:
npm run typecheck # tsc --noEmit
npm run lint # oxlint --max-warnings 0
npm run format # prettier --write只想要 Docker 镜像
不想在本机装 Go / Node,可以让 Docker 多阶段构建在镜像内完成全部编译:
# 后端单体镜像(前端在镜像内构建并嵌入)
docker build -f Dockerfile.backend -t gopanel:local .
# 前端独立镜像(Nginx + /api 反代)
docker build -f Dockerfile.frontend -t gopanel-frontend:local .
# 单容器版
docker build -f Dockerfile.allinone -t gopanel-allinone:local .
docker build -f Dockerfile.nginx -t gopanel-nginx:local .| 文件 | 用途 |
|---|---|
Dockerfile.backend | 后端单体镜像(多阶段,前端已嵌入) |
Dockerfile.frontend | 前端独立 Nginx 镜像 |
Dockerfile.allinone | 单容器版(Caddy + GoPanel) |
Dockerfile.nginx | 单容器版(Nginx + GoPanel) |
Dockerfile.bin | 产出 Release 二进制附件(GoPanel-linux-<arch>) |
本机装了
gvt也可以用gvt docker(配置见.gvt/docker/,默认标签dev)。
官网与文档站
本官网(VitePress)源码在 frontend/vitepress/:
cd frontend/vitepress
npm install
npm run dev # 本地预览(默认 5173)
npm run build # 产出 .vitepress/dist