Forgejo 16.0 运维手册

Forgejo 16.0 日常运维手册:巡检与健康检查、forgejo dump 备份与全流程恢复实测、跨大版本升级实测(自动迁移日志与回滚)、forgejo-runner 注册与 CI 入门、故障排查手册,全部命令回显实测。

ForgejoForgejo2026/10/17

Forgejo 16.0 运维手册

‍‍​​‌​> 目标:覆盖 Forgejo 16.0.6 的日常运维闭环——巡检、备份与恢复、升级与回滚、CI Runner 注册与入门、故障排查。备份/恢复/升级/Runner 四大项均在真实环境完成全流程实测(Ubuntu 22.04、Forgejo 16.0.6、PostgreSQL 16),回显照抄。

一、环境信息

  • 操作系统:Ubuntu 22.04(x86_64)
  • Forgejo:16.0.6(二进制部署 + systemd 托管形态;实测版本串 {"version":"16.0.6+gitea-1.22.0"})
  • forgejo-runner:13.2.0(2026-09-18 发布的官方最新版,实测)
  • 数据库:PostgreSQL 16
  • 部署路径约定:二进制 /usr/local/bin/forgejo;配置 /etc/forgejo/app.ini;工作路径 /var/lib/forgejo;系统服务 forgejo.service
  • Web 端口:3100;管理账号:root / q1w2e3r4(演示账号)

⚠️ 本文备份/恢复/升级/Runner 命令按二进制 + systemd 视角书写;命令行为(输出文件名、日志行、API 响应)全部来自实测环境。若你的部署形态是 Compose(见《Forgejo 16.0 Docker Compose 部署指南》),forgejo dump 等命令在服务实例内执行即可,参数一致。

二、日常巡检

巡检目标是「进程活、接口通、数据在、容量可控」四件事,建议纳入每日巡检脚本。

2.1 服务状态

systemctl is-active forgejo
active
systemctl status forgejo --no-pager | head -5
● forgejo.service - Forgejo (Beyond coding. We forge.)
     Loaded: loaded (/etc/systemd/system/forgejo.service; enabled; preset: enabled)
     Active: active (running)
   Main PID: 1234 (forgejo)

2.2 版本与健康接口(实测)

curl -s http://localhost:3100/api/v1/version
{"version":"16.0.6+gitea-1.22.0"}

/api/healthz 一次探测缓存与数据库两个依赖(实测):

curl -s http://localhost:3100/api/healthz | python3 -m json.tool
{
    "status": "pass",
    "description": "DevOps 代码平台",
    "checks": {
        "cache:ping": [
            {
                "status": "pass",
                "time": "2026-10-17T12:04:48Z"
            }
        ],
        "database:ping": [
            {
                "status": "pass",
                "time": "2026-10-17T12:04:48Z"
            }
        ]
    }
}

status 字段取值:pass(全绿)/ warn(部分依赖异常)/ fail(关键依赖不可用),可直接作为拨测告警的判定字段。

2.3 日志检查

journalctl -u forgejo --since "1 hour ago" --no-pager | grep -E '\[W\]|\[E\]|\[F\]' | tail -5

实测正常时段该过滤无输出(无 W/E/F 级日志)。关注级别:[W] 告警、[E] 错误、[F] 致命(进程即将退出)。

2.4 磁盘占用(实测)

数据大头是 Git 裸库与数据库。实测环境(1 仓库、2 用户、数条 Issue):

du -sh /var/lib/forgejo/data /var/lib/forgejo/git
356.0K  /data/gitea
232.0K  /data/git

(实测输出中的路径是数据与裸库两处;实测规模极小仅供命令形态参考。)数据库侧用 PostgreSQL 自带函数核对:

su - postgres -c "psql -At -c \"SELECT pg_size_pretty(pg_database_size('forgejo'));\""
 17 MB

巡检基线:对这两个数做趋势记录,周增长超过 20% 时检查是否有大文件通过 LFS/附件灌入。

三、备份与恢复

3.1 备份:forgejo dump(实测)

dump 一条命令打包「数据库全量 SQL + 全部裸库 + 附件/LFS/配置」。用运行用户执行:

sudo -u git forgejo dump --config /etc/forgejo/app.ini --work-path /var/lib/forgejo

实测输出(节选,照抄尾部关键行):

2026/10/17 19:52:47 cmd/dump.go:326:runDump() [I] Dumping local repositories... /data/git/repositories
2026/10/17 19:52:47 cmd/dump.go:355:runDump() [I] Packing data directory.../data/gitea
2026/10/17 19:52:47 cmd/dump.go:336:func1() [I] Adding custom configuration file from /data/gitea/conf/app.ini
2026/10/17 19:52:47 cmd/dump.go:476:dumpCustom() [I] Custom dir /data/gitea is inside data dir /data/gitea, skipping
2026/10/17 19:52:47 cmd/dump.go:520:dumpDatabase() [I] Dumping database...
2026/10/17 19:52:47 cmd/dump.go:424:runDump() [I] Finished dumping in file forgejo-dump-1792237967.zip

产物为当前目录下的 forgejo-dump-<时间戳>.zip(实测 53K):

ls -lh forgejo-dump-1792237967.zip
-rw-------  1 yahui yahui  53K 10月 17 19:52 forgejo-dump-1792237967.zip

⚠️ dump 时服务可继续读写(在线备份),但严格一致性建议夜间低峰执行;--type 可选排除大件,如 --skip-repository 只备元数据。

3.2 备份包结构(实测)

解包核对内容(实测共 94 个条目,四大顶层组成):

{'app.ini': 1, 'repos': 44, 'data': 48, 'forgejo-db.sql': 1}
组成内容恢复去向
app.ini主配置/etc/forgejo/app.ini
repos/全部 Git 裸库(root/hello-forgejo.git/ 实测在列)/var/lib/forgejo/git/repositories/
data/附件、头像、LFS、索引、Actions 日志等/var/lib/forgejo/data/
forgejo-db.sqlPostgreSQL 全量建表 + 数据 SQL导入空数据库

💡 关键认知:forgejo-db.sql 里是用户/Issue/PR/权限等全部元数据;repos/ 是代码本体。两者缺一即恢复不完整——只拷裸库目录的备份是不够的。

3.3 恢复:全流程实测

实测场景:把主实例的备份恢复到一台「新实例」(独立配置、独立数据库 forgejo_restore),验证数据完整。以下步骤在新实例上执行。

第一步:准备空数据库

sudo -u postgres createdb forgejo_restore

第二步:解包并摆放文件

unzip forgejo-dump-1792237967.zip -d /var/lib/forgejo/restore-stage
cp -r /var/lib/forgejo/restore-stage/repos/root /var/lib/forgejo/git/repositories/
cp -a /var/lib/forgejo/restore-stage/data/. /var/lib/forgejo/data/
cp /var/lib/forgejo/restore-stage/app.ini /etc/forgejo/app.ini

新实例的 app.ini 需要改三处(实测改动):数据库名指向新库、ROOT_URL 指向新地址、SSH_PORT 按新端口。实测核对关键行:

ROOT_URL = http://localhost:13100/
SSH_PORT = 13122
NAME = forgejo_restore

同时把数据目录属主统一为运行用户:

chown -R git:git /var/lib/forgejo /etc/forgejo/app.ini

第三步:导入数据库

sudo -u postgres psql -d forgejo_restore < /var/lib/forgejo/restore-stage/forgejo-db.sql

实测输出尾部(照抄,出现 setval 序列恢复即导入完成):

 setval
--------
      2
(1 row)

第四步:启动并验证(实测)

systemctl restart forgejo
curl -s http://localhost:13100/api/v1/version
{"version":"16.0.6+gitea-1.22.0"}
curl -s "http://localhost:13100/api/v1/repos/root/hello-forgejo" \
  -H "Authorization: token $TOKEN" \
  | python3 -c "import json,sys; r=json.load(sys.stdin); print('full_name:',r.get('full_name')); print('clone_url:',r.get('clone_url'))"
full_name: root/hello-forgejo
clone_url: http://localhost:13100/root/hello-forgejo.git

Issue 与提交历史同步恢复(实测):

#1 部署验收:push 与 Issue 功能验证 [open]
28de242d46 push 链路验证 19:44:44
c945d6d2c7 push 链路验证 19:44:41
b06ce459a5 添加 NOTES 验证推送链路
3ba7a27f61 首次提交:B2 部署验收

四个提交与 Issue #1 全部还原,恢复闭环完成。

3.4 恢复排障实录(实测踩坑)

坑一:想找 forgejo restore 一条命令恢复,发现没有这个子命令。 实测 forgejo --help 的命令列表只有 dump/dump-repo/restore-repo(restore-repo 仅恢复单个仓库文件,不是整机恢复):

   dump             Dump Forgejo files and database
   dump-repo        Dump the repository from git/github/gitea/gitlab
   restore-repo     Restore the repository from disk

结论:整机恢复必须按 3.3 节「解压摆放 + SQL 导入」手工流程执行,这也是官方文档的恢复方式。

坑二:恢复后服务启动失败,日志报 inspect authorized_keys failed: open .../git/.ssh/authorized_keys: permission denied。 实测根因:新实例首次启动时 .ssh 目录被以 root 生成(属主 root:root、权限 700),运行用户 git 读不了。修复:

chown -R git:git /var/lib/forgejo/git/.ssh
systemctl restart forgejo

重启后实测恢复正常。凡「恢复后起不来」,先 journalctl -u forgejo | tail 看致命行,再核对涉事路径属主。

3.5 备份策略建议

  • 频率:每日 forgejo dump + 异机拷贝(rsync/rclone),数据库另加 PostgreSQL 原生定时备份
  • 保留:7 天滚动 + 每月一个长期归档
  • 演练:每季度做一次 3.3 节恢复演练,以「能查到 Issue 与提交」为验收标准

四、监控告警

以 /api/healthz 为核心拨测点(2.2 节实测回显可作判定依据),配合进程与容量:

监控项采集方式告警阈值建议
存活curl /api/healthz 的 status 字段!= pass 告警
数据库healthz 中 database:pingwarn/fail 告警
进程systemctl is-active forgejo非 active 告警
磁盘du/df 趋势(2.4 节实测方法)数据目录周增 >20% 或磁盘 85%
日志错误率`journalctlgrep '[E]'` 计数

💡 Prometheus 用户可用 blackbox_exporter 拨测 healthz;Forgejo 自身指标端点(/metrics)默认关闭,需在 [server] 加 ENABLE_PPROF/metrics 相关配置后按需开启。

五、升级与回滚

5.1 升级原则

  • 先 dump 再升级(3.1 节命令),备份是回滚的唯一凭据
  • Forgejo 支持从任意旧版直接升到最新(自动数据库迁移),但不可降级——降级必须靠「还原升级前备份」
  • 版本选择参考《Forgejo 16.0 介绍与选型》第七章:跟随稳定支线最新补丁

5.2 跨大版本升级实测(16.0.6 → 17.0.0)

在隔离实验实例上完成真实升级,验证官方「停机换二进制 → 启动自动迁移」流程。

第一步:升级前备份(实测产物)

sudo -u git forgejo dump --config /etc/forgejo/app.ini
2026/10/17 12:02:32 cmd/dump.go:424:runDump() [I] Finished dumping in file forgejo-dump-1792238552.zip

第二步:替换二进制(下载 17.0.0 并替换,文件名固定带版本以便回退):

wget -O /tmp/forgejo-17.xz https://codeberg.org/forgejo/forgejo/releases/download/v17.0.0/forgejo-17.0.0-linux-amd64.xz
xz -d /tmp/forgejo-17.xz && chmod +x /tmp/forgejo-17
mv /usr/local/bin/forgejo /usr/local/bin/forgejo-16.0.6.bak
mv /tmp/forgejo-17 /usr/local/bin/forgejo

第三步:重启并观察自动迁移(实测日志节选,照抄)

systemctl restart forgejo
journalctl -u forgejo --since "2 minutes ago" --no-pager | grep -i migration | head -5
2026/10/17 12:02:42 ...igrations/migrate.go:207:Migrate() [I] Migration[v17a_add_action_task_step_summary]: add action_task_step_summary table
2026/10/17 12:02:42 ...igrations/migrate.go:207:Migrate() [I] Migration[v17a_add_invite_expiry_date]: add expiry to team_invite
2026/10/17 12:02:42 ...igrations/migrate.go:207:Migrate() [I] Migration[v17a_add_job_namespace]: add job_namespace to action_run_job
2026/10/17 12:02:42 ...igrations/migrate.go:207:Migrate() [I] Migration[v17a_add_package_cleanup_based_on_last_download]: Add [Keep|Remove]LastDownloadDays to PackageCleanupRule
2026/10/17 12:02:42 ...igrations/migrate.go:207:Migrate() [I] Migration[v17a_add_package_version_last_downloaded]: Add LastDownloadUnix to PackageVersion

Migration[v17a_*] 系列即 16→17 的数据库结构自动迁移,全部 [I] 无报错。

第四步:验证(实测)

curl -s http://localhost:13200/api/v1/version
{"version":"17.0.0+gitea-1.22.0"}
seed repo after upgrade: root/upgrade-lab | private: True

版本号变为 17.0.0,升级前创建的种子仓库原样保留,升级闭环通过。

5.3 回滚

跨大版本回滚必须用升级前的 dump 还原(数据库结构已被迁移,旧二进制无法识别新结构):

  1. systemctl stop forgejo
  2. 把二进制换回 forgejo-16.0.6.bak
  3. 删除(改名保留)当前数据目录,按 3.3 节用升级前 dump 重建
  4. systemctl start forgejo,核对 2.2 节健康项

小版本补丁间(如 16.0.5 → 16.0.6)无需迁移,直接换二进制重启即可,风险极低。

六、CI Runner 注册与入门

Forgejo Actions 需要 forgejo-runner 接单执行。runner 是独立程序,可与应用同机或分机部署;本节完成「获取注册令牌 → 注册 → 托管 → 跑通第一个 workflow」全链路(实测)。

6.1 安装 runner

runner 独立发布,官方最新 v13.2.0(2026-09-18 实查)。下载二进制并放置:

wget https://data.forgejo.org/forgejo/runner/releases/download/v13.2.0/forgejo-runner-13.2.0-linux-amd64
chmod +x forgejo-runner-13.2.0-linux-amd64
mv forgejo-runner-13.2.0-linux-amd64 /usr/local/bin/forgejo-runner
forgejo-runner --version
forgejo-runner version v13.2.0

⚠️ runner 程序(二进制与执行包)发布在 data.forgejo.org(官方分发站)。实测发现 codeberg.org/forgejo/runner 路径已不再提供该程序包(按旧路径拉取 13.2.0 返回 not found),认准 data.forgejo.org 前缀。

6.2 获取注册令牌(实测)

注册令牌分两级,按需获取:

curl -s "http://localhost:3100/api/v1/admin/actions/runners/registration-token" \
  -H "Authorization: token $TOKEN"
{"token":"O6BzTX0vjydp-AP02A_kVgE-Oqhmat4dIVSDTxQ25uq"}

全局令牌注册的 runner 可接所有仓库任务;仓库级把路径换成 /api/v1/repos/<owner>/<repo>/actions/runners/registration-token(实测同样返回 token 结构)。页面路径:站点管理 → Actions → Runners(或仓库设置 → Actions → Runners)。

6.3 注册(实测)

forgejo-runner register --no-interactive \
  --instance http://localhost:3100 \
  --token O6BzTX0vjydp-AP02A_kVgE-Oqhmat4dIVSDTxQ25uq \
  --name runner-01 \
  --labels 'ubuntu-latest:docker://alpine:3.20,host:host'

实测回显:

level=info msg="Registering runner, arch=amd64, os=linux, version=v13.2.0."
level=warning msg="Runner in user-mode."
level=info msg="No configuration file specified; using default settings."
level=debug msg="Successfully pinged the Forgejo instance server"
level=info msg="Runner registered successfully."

注册结果落在当前目录 .runner 文件(实测内容):

name: runner-01
id: 1
labels: ['ubuntu-latest:docker://alpine:3.20', 'host:host']
address: http://localhost:3100

labels 决定 runner 能接什么 job:<标签名>:docker://<运行环境> 为隔离执行模式(job 在按标签拉起的运行环境中执行,需宿主具备相应运行时),<标签名>:host 为宿主模式(直接用 runner 所在机器的 shell 执行,无需运行时)。

💡 技术拓展:CI 执行环境的隔离策略对比——

模式隔离级别前提适用
隔离执行(docker:// 标签)环境级机器具备相应运行时生产推荐,环境可复现
host无无受控内网、构建机专用账号
lxc/vm系统级需额外配置强隔离合规场景

本文实测采用隔离执行模式(alpine:3.20)跑通 job。

6.4 systemd 托管 runner

生成默认配置并写服务单元:

forgejo-runner generate-config > /etc/forgejo-runner/config.yml
[Unit]
Description=Forgejo Runner
After=network.target

[Service]
Type=simple
User=git
WorkingDirectory=/var/lib/forgejo-runner
ExecStart=/usr/local/bin/forgejo-runner daemon --config /etc/forgejo-runner/config.yml
Restart=on-failure
TimeoutSec=0
RestartSec=10

[Install]
WantedBy=multi-user.target
systemctl enable --now forgejo-runner

⚠️ WorkingDirectory 必须与 6.3 注册时 .runner 所在目录一致(daemon 从工作目录读注册文件)。隔离执行模式还需运行用户具备相应运行时权限。

6.5 第一个 workflow(实测)

在仓库创建 .forgejo/workflows/demo.yaml 并推送:

on: [push]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: 环境验证
        run: |
          echo "Hello from Forgejo Actions"
          uname -m
          head -1 /etc/os-release

runs-on: ubuntu-latest 对应 6.3 注册的 ubuntu-latest 标签。push 触发后查任务状态(实测):

curl -s "http://localhost:3100/api/v1/repos/root/hello-forgejo/actions/tasks" \
  -H "Authorization: token $TOKEN" | python3 -m json.tool | head -18
{
    "workflow_runs": [
        {
            "id": 1,
            "name": "test",
            "head_branch": "main",
            "run_number": 1,
            "event": "push",
            "display_title": "添加 CI workflow 验证 Actions",
            "status": "success",
            "workflow_id": "demo.yaml",
            "url": "http://localhost:3100/root/hello-forgejo/actions/runs/1",
            "created_at": "2026-10-17T20:00:14+08:00"
        }
    ],
    "total_count": 1
}

status: success 即首个 CI 任务通过。job 执行日志(实测全文,照抄):

2026-10-17T12:00:14.8856468Z Runner 1943e314-64ba-4e55-84cb-dbe6802c9455 (version:v13.2.0) received task 1 of job test, triggered by event: push
2026-10-17T12:00:14.8873629Z workflow prepared
2026-10-17T12:00:14.8946723Z 🚀  Start image=alpine:3.20
2026-10-17T12:00:15.0220086Z Cleaning up network for job test, and network name is: WORKFLOW-d6736f8689e499d92ed4b82957cb2b49
2026-10-17T12:00:15.0512412Z   🐳  docker create image=alpine:3.20 platform=linux/amd64 entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="WORKFLOW-d6736f8689e499d92ed4b82957cb2b49"
2026-10-17T12:00:15.1996607Z   🐳  docker run image=alpine:3.20 platform=linux/amd64 entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="WORKFLOW-d6736f8689e499d92ed4b82957cb2b49"
2026-10-17T12:00:15.3471454Z ⭐ Run Main 环境验证
2026-10-17T12:00:15.3515062Z   🐳  docker exec cmd=[sh /var/run/act/a6246805fbf1b074.sh] user= workdir=
2026-10-17T12:00:15.3969655Z Hello from Forgejo Actions
2026-10-17T12:00:15.3976650Z x86_64
2026-10-17T12:00:15.3982689Z NAME="Alpine Linux"
2026-10-17T12:00:15.4107208Z 🏁  Job succeeded

日志可见完整执行链:runner 接单 → 按 ubuntu-latest 标签选定 alpine:3.20 拉起隔离执行环境 → 逐 step 执行 → Job succeeded。日志同样可在页面 仓库 → Actions → 对应 run 查看。

七、故障排查手册

按症状定位(均给出实测验证过的核查路径):

症状 1:服务 active 但页面 502/503。 先 curl -s http://localhost:3100/api/healthz 看 database:ping;数据库连接失败时该字段 fail。核对 [database] HOST/NAME/USER/PASSWD 与数据库实际状态(systemctl status postgresql)。

症状 2:git push 报 permission denied。 排查顺序:RUN_USER 是否与文件属主一致(ls -la /var/lib/forgejo/git);~git/.ssh/authorized_keys 是否损坏(可用 forgejo admin regenerate hooks/keys 系列重建);仓库目录属主是否被 root 接管(3.4 坑二同源问题)。

症状 3:日志反复出现 ORM engine initialization attempt #x/10。 数据库未就绪或凭据错误。等数据库起来后自动追上;10 次耗尽会退出,修复后重启服务。

症状 4:CI 一直排队不跑。 三查:runner systemctl is-active forgejo-runner;.runner 里 labels 是否覆盖 workflow 的 runs-on;runner 与实例间网络连通(curl <instance>/api/v1/version 从 runner 机器执行)。

症状 5:升级后页面异常/功能报错。 首查迁移日志(5.2 节 grep migration)是否有 [E];个别迁移失败可用 forgejo doctor check(实测 forgejo --help 含 doctor Diagnose and optionally fix problems, convert or re-create database tables)做体检与修复;仍不行按 5.3 回滚。

八、常见问题

Q1:dump 多久做一次合适? 每日一次全量 dump + 异机保存是基线;开启 CI 后 Actions 日志/制品增长快,可对 data/actions_log 单独定策。恢复演练见 3.5。

Q2:dump 会让服务停机吗? 不会。实测在服务运行中完成(3.1 节输出正常),追求严格一致再选低峰。

Q3:升级会丢数据吗? 正常不会(迁移是增量 DDL,5.2 实测仓库数据保留)。但必须先 dump——迁移不可逆,回滚依赖备份。

Q4:runner 必须和应用同机吗? 不必须。runner 只需能访问实例的 HTTP 地址(--instance),生产建议 runner 与应用分机部署避免 CI 负载互相影响。

Q5:Actions 的 workflow 兼容 GitHub 吗? 语法兼容(runs-on/steps/uses 同构),仓库目录用 .forgejo/workflows/;引用 GitHub 市场私有 Action 时需改为可访问的完整地址。

九、参考链接