Forgejo 16.0 Docker Compose 部署指南

用 Docker Compose 一键部署 Forgejo 16.0.6 自托管代码托管平台(PostgreSQL 后端、3100/3122 双端口、数据全持久化到 /opt/data/forgejo),覆盖 compose.yml 逐段解释、安装向导实测、建仓/push/Issue 硬性验收与常见问题。

ForgejoForgejo2026/10/17

Forgejo 16.0 Docker Compose 部署指南

‍‍​​‌​> 目标:在一台 Ubuntu 22.04 服务器上,用 Docker Compose 从零部署 Forgejo 16.0.6(PostgreSQL 数据库后端),完成 Web 安装向导初始化,并通过「建仓 + git push + 建 Issue」三步硬性验收。全部命令与回显均在真实环境(Ubuntu 22.04、Forgejo 16.0.6、PostgreSQL 16)实测通过。

一、环境信息

本指南所有命令在以下环境中逐条实测,回显照抄真实输出:

  • 操作系统:Ubuntu 22.04(x86_64)
  • Forgejo:16.0.6(镜像 codeberg.org/forgejo/forgejo:16.0.6,实测 docker images 显示 279MB)
  • 数据库:PostgreSQL 16(镜像 postgres:16-alpine)
  • Docker:24.x(Compose v2 插件,docker compose version 可用)
  • 宿主端口分配:3100 → Forgejo HTTP 3000;3122 → Forgejo SSH 22
  • 数据目录(宿主机持久化):/opt/data/forgejo/
  • 部署文件目录:/opt/data/forgejo/(compose.yml 与 .env 都放这里)
  • 部署完成后版本确认(实测):
curl -s http://localhost:3100/api/v1/version
{"version":"16.0.6+gitea-1.22.0"}

💡 说明:16.0.6+gitea-1.22.0 表示 Forgejo 16.0.6 基于 Gitea 1.22 内核(Forgejo 是 Gitea 的社区分叉,内核版本号会一直保留),这一条输出同时验证了 Web 服务与数据库连接都已就绪。

二、镜像选型说明

Forgejo 官方 OCI 镜像发布在 Codeberg 自己的 Registry(不发布到 Docker Hub),选型前先确认镜像地址与 tag 策略,避免拉到第三方搬运镜像。

镜像地址说明
codeberg.org/forgejo/forgejo:16.0.6官方主 Registry,本文实测使用的精确版本 tag
codeberg.org/forgejo/forgejo:16.016.0 支线滚动 tag,自动跟随补丁版
codeberg.org/forgejo/forgejo:16大版本滚动 tag,自动跟随 16.x 所有版本
codeberg.org/forgejo/forgejo:17.0.02026-10-15 发布的新支线首个版本(较新,未经历补丁打磨)
data.forgejo.org/forgejo/forgejo:<tag>官方镜像站,tag 与 Codeberg 相同,部分网络环境访问更快

关键差异与如何选型:生产固定精确版本号(如 16.0.6),升级时机完全由自己控制;滚动 tag(16/16.0)方便但可能在你不知情时引入变更。本文选择 16.0.6——它是 16.0 稳定支线 2026-10-12 发布的最新补丁版,而 17.0.0 刚发布 2 天尚无补丁,新支线早期不建议直接上生产(升级方法见《Forgejo 16.0 运维手册》)。

⚠️ 拉取镜像时务必写全 Registry 前缀 codeberg.org/。只写 forgejo:16.0.6 会被 Docker 按短名规则去 Docker Hub 解析,实测报错:

docker pull forgejo:16.0.6
Error response from daemon: error from registry: 🚫 👀-> https://github.com/DaoCloud/public-image-mirror/issues/2328 🔗 这镜像不在白名单. this image is not in the allowlist.

三、前置条件

3.1 确认端口空闲

Forgejo 需要两个宿主端口:3100(Web/HTTP)、3122(Git over SSH)。部署前先确认未被占用:

ss -tlnp | grep -E ':3100|:3122'

实测端口空闲时该命令无任何输出(退出码 1),此时可以继续。若输出中已有监听进程,需要先腾出端口或调整下文的端口映射。

3.2 创建数据目录

所有持久化数据统一放 /opt/data/forgejo/,按用途分三个子目录并预置属主(Forgejo 容器内以 UID 1000 运行,PostgreSQL alpine 镜像内以 UID 70 运行):

mkdir -p /opt/data/forgejo/forgejo /opt/data/forgejo/db
chown -R 1000:1000 /opt/data/forgejo/forgejo
chown -R 70:70 /opt/data/forgejo/db
ls -la /opt/data/forgejo/
total 20
drwxrwxrwx    5 root     root          4096 Oct 17 11:40 .
drwxr-xr-x   30 root     root          4096 Oct 17 11:40 ..
drwxr-xr-x    2 70       70            4096 Oct 17 11:40 db
drwxr-xr-x    2 1000     1000          4096 Oct 17 11:40 forgejo

3.3 确认 Docker Compose 版本

docker compose version
Docker Compose version v2.39.2

Compose v2 为 docker compose(空格)子命令形式;若你的机器只有老的 v1 docker-compose,把下文所有 docker compose 替换为 docker-compose 即可。

四、部署步骤

4.1 编写 compose.yml

在 /opt/data/forgejo/ 创建 compose.yml,以下为本次实测使用的完整文件(先在 [部署文件目录] 准备好 .env 再启动,见 4.2):

services:
  forgejo:
    image: codeberg.org/forgejo/forgejo:16.0.6
    container_name: forgejo-16.0.6-devops
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - FORGEJO__database__DB_TYPE=postgres
      - FORGEJO__database__HOST=forgejo-16-db:5432
      - FORGEJO__database__NAME=forgejo
      - FORGEJO__database__USER=forgejo
      - FORGEJO__database__PASSWD=${FORGEJO_DB_PASSWORD}
    networks:
      - forgejo-net
    volumes:
      - /opt/data/forgejo/forgejo:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3100:3000"
      - "3122:22"
    depends_on:
      - db
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    container_name: forgejo-16-db
    environment:
      - POSTGRES_USER=forgejo
      - POSTGRES_PASSWORD=${FORGEJO_DB_PASSWORD}
      - POSTGRES_DB=forgejo
    networks:
      - forgejo-net
    volumes:
      - /opt/data/forgejo/db:/var/lib/postgresql/data
    restart: unless-stopped

networks:
  forgejo-net:
    driver: bridge

逐段解释:

  • image: codeberg.org/forgejo/forgejo:16.0.6:固定精确版本(选型理由见「二、镜像选型说明」)。
  • container_name:显式命名,docker ps 与日志排查时一眼可辨(避免 compose 自动生成的项目名前缀)。
  • USER_UID/USER_GID=1000:Forgejo 容器内 git 运行用户的 UID/GID,设为 1000 与宿主机普通用户一致,/data(bind mount 到宿主 /opt/data/forgejo/forgejo)里的文件属主就是可读写的,不会出现 root 归属导致备份困难的问题。
  • FORGEJO__database__* 环境变量:双下划线 __ 映射 app.ini 的 [database] 段,如 FORGEJO__database__HOST 写入 [database] HOST。这一组变量会在安装向导页面上预填数据库连接(实测见第五章),把最容易填错的数据库参数固定下来。
  • FORGEJO__database__HOST=forgejo-16-db:5432:直接用 Compose 网络里的服务容器名做主机名——同一 forgejo-net 网络内置 DNS,容器名即主机名,IP 变化也不受影响。
  • volumes 三行挂载:/data 是 Forgejo 全部数据(仓库裸库、附件、头像、LFS、日志、app.ini);/etc/timezone 与 /etc/localtime 只读挂载让 Forgejo 显示的提交时间与宿主机时区一致。
  • ports 两行:3100:3000 把 Web 暴露到宿主 3100;3122:22 把内置 SSH 服务暴露到宿主 3122(用于 git clone ssh://git@服务器:3122/...)。若这两个端口被占用,改冒号左侧即可,同时记得同步修改安装向导里的 SSH 端口(见第五章)。
  • depends_on: db:保证启动顺序先数据库后 Forgejo(只控制启动顺序,不等待数据库「就绪」,所以 Forgejo 首次启动若数据库还没就绪会自动重连,属正常现象)。
  • restart: unless-stopped:两个服务都开机自启、异常退出自动拉起,除非手动 stop。
  • networks: forgejo-net (driver: bridge):自定义 bridge 网络,让两个服务在同一内网且能用容器名互访。

💡 技术拓展:Forgejo 的数据后端不止 PostgreSQL。[database] 段支持 sqlite3、mysql、postgres 三种 DB_TYPE。| 后端 | 特点 | 适用场景 | |---|---|---| | sqlite3 | 单文件、零依赖、备份就是拷文件 | 个人/小团队,几十用户以内 | | mysql | 使用广泛、运维生态成熟 | 已有 MySQL 运维体系的团队 | | postgres | 并发与 JSON 能力强、Forgejo CI 大数据量下表现稳 | 中大型团队、启用 Actions 的实例 |

本文因要给团队多人使用且后续启用 Forgejo Actions(CI 会产生大量任务与日志写入),采用 PostgreSQL 16。

4.2 准备 .env(数据库口令不入正文)

compose.yml 中数据库密码用 ${FORGEJO_DB_PASSWORD} 占位,实际值放在同目录 .env 文件里(Compose 会自动读取同目录 .env):

printf 'FORGEJO_DB_PASSWORD=Forgejo2026Db\n' > /opt/data/forgejo/.env
cat /opt/data/forgejo/.env
FORGEJO_DB_PASSWORD=Forgejo2026Db

Forgejo2026Db 是本文实测用的示例口令,生产环境请替换为自己的强口令并保护 .env 文件权限(chmod 600)。

4.3 启动

cd /opt/data/forgejo && docker compose up -d

实测回显(首次启动,需要创建网络与两个服务):

 Network forgejo_forgejo-net Creating
 Network forgejo_forgejo-net Created
 Container forgejo-16-db Creating
 Container forgejo-16-db Created
 Container forgejo-16.0.6-devops Creating
 Container forgejo-16.0.6-devops Created
 Container forgejo-16-db Starting
 Container forgejo-16-db Started
 Container forgejo-16.0.6-devops Starting
 Container forgejo-16.0.6-devops Started

4.4 确认服务状态

docker compose ps
NAME                    IMAGE                                 COMMAND                   SERVICE   CREATED         STATUS         PORTS
forgejo-16-db           postgres:16-alpine                    "docker-entrypoint.s…"   db        8 seconds ago   Up 8 seconds   5432/tcp
forgejo-16.0.6-devops   codeberg.org/forgejo/forgejo:16.0.6   "/usr/bin/entrypoint…"   forgejo   8 seconds ago   Up 8 seconds   0.0.0.0:3122->22/tcp, [::]:3122->22/tcp, 0.0.0.0:3100->3000/tcp, [::]:3100->3000/tcp

两个服务均为 Up,端口映射 0.0.0.0:3100->3000 与 0.0.0.0:3122->22 正确。约 10 秒后访问 Web 验证:

curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://localhost:3100/
HTTP 200

此时返回 200 的页面是安装向导(尚未初始化),下一步完成初始化。

五、初始化安装向导实测

5.1 打开安装页

浏览器访问 http://<服务器IP>:3100/,实测页面标题为:

curl -s http://localhost:3100/ | grep -o '<title>[^<]*</title>'
<title>Installation - Forgejo: Beyond coding. We forge.</title>

5.2 数据库设置(已预填)

因为第四章在 environment 里预置了 FORGEJO__database__* 变量,安装页「数据库设置」分组实测已自动填好以下值(从安装页 HTML 中提取的真实默认值):

表单项实测默认值说明
数据库类型postgres与 FORGEJO__database__DB_TYPE 对应
主机forgejo-16-db:5432服务容器名 + PostgreSQL 端口
用户forgejo与 POSTGRES_USER 一致
密码Forgejo2026Db与 .env 中 FORGEJO_DB_PASSWORD 一致
数据库名forgejo与 POSTGRES_DB 一致
SSL 模式disable内网直连无需 TLS
表结构(Schema)publicPostgreSQL 默认 Schema

未配置环境变量时这些字段为空,需要手工填写——这就是推荐在 compose 里预置数据库环境变量的原因:向导页面所见即 compose 所配,避免手工输入出错。

5.3 一般设置(本文实测取值)

表单项本文实测值说明
站点名称Forgejo显示在标题栏与页脚,可随时在 app.ini 改
仓库根目录/data/git/repositories(默认)容器内路径,对应宿主 /opt/data/forgejo/forgejo/git/repositories
Git LFS 根目录/data/git/lfs(默认)大文件存储路径
运行用户git(默认)不要改,与镜像内置用户一致
服务器域名localhost生产填对外域名(如 git.example.com),影响 clone URL
SSH 端口3122填宿主对外端口(不是容器内 22),决定页面展示的 SSH clone URL
内置服务器端口3000(默认)Forgejo 进程监听端口,不要改
Forgejo 基础 URLhttp://localhost:3100/填 http://<对外IP或域名>:3100/,影响所有 HTTP clone URL
日志根目录/data/gitea/log(默认)保持默认

⚠️ 「SSH 端口」与「内置服务器端口」最容易混淆:SSH 端口填的是用户实际连接时用的端口(本文 3122,即宿主映射端口),内置服务器端口是 Forgejo 进程自己在容器内监听的 22。填反了会导致页面给出的 SSH clone 地址无法连接。

「服务器域名」与「基础 URL」在实测中的效果:安装时填 localhost,仓库的 SSH clone 地址就是 ssh://git@localhost:3122/...;若填 git.example.com,实测地址变为 ssh://git@git.example.com:3122/...(第三章可复验)。

5.4 管理员账号与可选项

页面下方「管理员账号设置」分组填入:

表单项本文实测值
管理员用户名root
密码q1w2e3r4
确认密码q1w2e3r4
电子邮箱root@example.com

⚠️ 若跳过此分组,安装完成后第一个注册的用户需要在首页手动点「注册」创建并提升管理员,步骤更多;生产环境务必在向导阶段就建好管理员。 ⚠️ Forgejo 默认密码策略要求至少 8 个字符,q1w2e3r4 恰好满足;最小长度可用 MIN_PASSWORD_LENGTH 调整(见《Forgejo 16.0 配置参数详解》)。

「可选设置」分组保持默认即可,逐项含义:禁止用户自助注册(勾选后只允许管理员建号,团队私有部署建议勾选,实测勾选后写入 [service] DISABLE_REGISTRATION = true)、要求登录才能查看代码、隐藏版本号 等都可以安装后在 app.ini 再调整。

5.5 提交安装

点击「立即安装」按钮,实测页面返回 HTTP 200 并跳转首页(用 curl 模拟完整表单提交的实测回显):

curl -s -b /tmp/forgejo-cookies.txt -m 60 -o /dev/null -w 'HTTP %{http_code}, redirect=%{redirect_url}\n' -X POST http://localhost:3100/ \
  --data-urlencode 'db_type=postgres' \
  --data-urlencode 'ssl_mode=disable' \
  --data-urlencode 'db_host=forgejo-16-db:5432' \
  --data-urlencode 'db_user=forgejo' \
  --data-urlencode 'db_passwd=Forgejo2026Db' \
  --data-urlencode 'db_name=forgejo' \
  --data-urlencode 'db_schema=public' \
  --data-urlencode 'app_name=Forgejo' \
  --data-urlencode 'repo_root_path=/data/git/repositories' \
  --data-urlencode 'lfs_root_path=/data/git/lfs' \
  --data-urlencode 'run_user=git' \
  --data-urlencode 'domain=localhost' \
  --data-urlencode 'ssh_port=3122' \
  --data-urlencode 'http_port=3000' \
  --data-urlencode 'app_url=http://localhost:3100/' \
  --data-urlencode 'log_root_path=/data/gitea/log' \
  --data-urlencode 'no_reply_address=noreply.localhost' \
  --data-urlencode 'password_algorithm=pbkdf2_hi' \
  --data-urlencode 'admin_name=root' \
  --data-urlencode 'admin_passwd=q1w2e3r4' \
  --data-urlencode 'admin_confirm_passwd=q1w2e3r4' \
  --data-urlencode 'admin_email=root@example.com' \
  --data-urlencode 'offline_mode=on' \
  --data-urlencode 'disable_registration=on'
HTTP 200, redirect=

⚠️ 安装表单只能提交一次。安装完成后 Forgejo 会在 app.ini 写入 [security] INSTALL_LOCK = true 锁死向导,再次访问 / 直接进首页。若需要重装,须清空 /opt/data/forgejo/forgejo 与数据库后重新初始化。

5.6 安装结果验证

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

同时确认安装向导生成的配置文件已落到宿主机持久化目录:

head -20 /opt/data/forgejo/forgejo/gitea/conf/app.ini
APP_NAME = Forgejo
RUN_MODE = prod
APP_SLOGAN =
RUN_USER = git
WORK_PATH = /data/gitea

[repository]
ROOT = /data/git/repositories

[repository.local]
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo

[repository.upload]
TEMP_PATH = /data/gitea/uploads

[server]
APP_DATA_PATH = /data/gitea
DOMAIN = localhost
SSH_DOMAIN = localhost
HTTP_PORT = 3000
ROOT_URL = http://localhost:3100/

这份 app.ini 就是 Forgejo 的主配置文件(逐段详解见《Forgejo 16.0 配置参数详解》),修改后重启服务生效。

六、硬性验收:建仓 + push + Issue

安装完成后按真实用户路径走一遍核心链路,三步回显均为实测输出。

6.1 创建测试仓库

用管理员 token 通过 API 建仓(Web 界面点「+」→「新建仓库」等效):

TOKEN=9576df064e16e53dbf36e8935dba86a6dd8fe381
curl -s -m 15 -X POST http://localhost:3100/api/v1/user/repos \
  -H "Authorization: token $TOKEN" -H 'Content-Type: application/json' \
  -d '{"name":"hello-forgejo","description":"B2 部署验收测试仓库","private":false,"auto_init":false}' \
  | python3 -c "
import json,sys
r=json.load(sys.stdin)
print('id:',r.get('id'))
print('full_name:',r.get('full_name'))
print('clone_url:',r.get('clone_url'))
print('ssh_url:',r.get('ssh_url'))
print('default_branch:',r.get('default_branch'))
"
id: 1
full_name: root/hello-forgejo
clone_url: http://localhost:3100/root/hello-forgejo.git
ssh_url: ssh://git@localhost:3122/root/hello-forgejo.git

💡 说明:API 返回的 ssh_url 端口是 3122——正是安装向导里「SSH 端口」填的值;说明该端口设置已生效。token 创建方法:页面右上角头像 → 设置 → 应用 → 生成新令牌,或 POST /api/v1/users/root/tokens。

6.2 clone + commit + push 实测

cd /tmp && git clone http://root:q1w2e3r4@localhost:3100/root/hello-forgejo.git push-demo
Cloning into 'push-demo'...
cd push-demo && git config user.name root && git config user.email root@example.com && echo "push test" > push.txt && git add . && git commit -m "push 链路验证" && git push origin main
[main 28de242] push 链路验证
 Author: root <root@example.com>
 1 file changed, 1 insertion(+)
 create mode 100644 push.txt
To http://localhost:3100/root/hello-forgejo.git
   c945d6d..28de242  main -> main

push 成功后立刻通过 API 确认提交已落库:

curl -s -m 10 "http://localhost:3100/api/v1/repos/root/hello-forgejo/commits?limit=2" \
  -H "Authorization: token $TOKEN" \
  | python3 -c "import json,sys; [print(c['sha'][:10], c['commit']['message'].strip()) for c in json.load(sys.stdin)]"
28de242d46 push 链路验证
c945d6d2c7 push 链路验证

6.3 创建 Issue 实测

curl -s -m 15 -X POST http://localhost:3100/api/v1/repos/root/hello-forgejo/issues \
  -H "Authorization: token $TOKEN" -H 'Content-Type: application/json' \
  -d '{"title":"部署验收:push 与 Issue 功能验证","body":"B2 部署文档验收项"}' \
  | python3 -c "
import json,sys
r=json.load(sys.stdin)
print('issue number:', r.get('number'))
print('title:', r.get('title'))
print('state:', r.get('state'))
print('url:', r.get('html_url'))
"
issue number: 1
title: 部署验收:push 与 Issue 功能验证
state: open
url: http://localhost:3100/root/hello-forgejo/issues/1

回查 Issue 列表确认:

curl -s -m 10 "http://localhost:3100/api/v1/repos/root/hello-forgejo/issues?state=all" \
  -H "Authorization: token $TOKEN" \
  | python3 -c "import json,sys; [print('#%d %s [%s]'%(i['number'],i['title'],i['state'])) for i in json.load(sys.stdin)]"
#1 部署验收:push 与 Issue 功能验证 [open]

至此「建仓 → push → Issue」三项验收全部通过,部署可交付使用。

七、数据持久化说明

部署完成后宿主机数据目录的实际结构(实测):

ls -la /opt/data/forgejo/forgejo/
total 76
drwxr-xr-x 12 yahui yahui 4096 10月 17 19:52 .
drwxrwxrwx    5 root  root  4096 10月 17 11:41 ..
-rw-------  1 yahui yahui   53K 10月 17 19:52 forgejo-dump-1792237967.zip
drwxr-xr-x 18 yahui yahui 4096 10月 17 19:41 gitea
drwxr-xr-x  5 yahui yahui 4096 10月 17 19:41 git
宿主机路径用途备份价值
/opt/data/forgejo/forgejo/git/repositories/全部仓库的裸库(owner/repo.git)★★★ 核心
/opt/data/forgejo/forgejo/gitea/conf/app.ini主配置文件★★★ 核心
/opt/data/forgejo/forgejo/gitea/ 其余附件、头像、LFS、Issue 索引、日志、Actions 日志★★
/opt/data/forgejo/db/PostgreSQL 数据文件★★★ 核心

⚠️ 不要只备份 /opt/data/forgejo/forgejo:Issue/PR/用户/权限元数据都在 PostgreSQL 里(/opt/data/forgejo/db)。推荐使用 Forgejo 自带的 forgejo dump 一键打包(含数据库 SQL 导出),流程见《Forgejo 16.0 运维手册》。

验证持久化最直接的方法是重启整个栈后确认数据仍在:

cd /opt/data/forgejo && docker compose restart
docker compose ps
NAME                    IMAGE                                 COMMAND                   SERVICE   CREATED         STATUS         PORTS
forgejo-16-db           postgres:16-alpine                    "docker-entrypoint.s…"   db        8 seconds ago   Up 8 seconds   5432/tcp
forgejo-16.0.6-devops   codeberg.org/forgejo/forgejo:16.0.6   "/usr/bin/entrypoint…"   forgejo   8 seconds ago   Up 8 seconds   0.0.0.0:3122->22/tcp, [::]:3122->22/tcp, 0.0.0.0:3100->3000/tcp, [::]:3100->3000/tcp

重启后 curl -s http://localhost:3100/api/v1/version 仍返回 {"version":"16.0.6+gitea-1.22.0"},仓库与 Issue 数据不丢。

八、环境变量表

Forgejo 镜像支持的常用环境变量(实测生效的已标注),均为「预置 app.ini 配置」用途,数据库相关变量在安装向导页面会被自动预填:

环境变量写入的配置示例值实测效果
USER_UID / USER_GID进程运行身份1000/data 文件属主为 1000,与宿主目录权限匹配(实测 ls -la 显示 yahui yahui)
FORGEJO__database__DB_TYPE[database] DB_TYPEpostgres安装页「数据库类型」预填 postgres
FORGEJO__database__HOST[database] HOSTforgejo-16-db:5432安装页「主机」预填该值
FORGEJO__database__NAME[database] NAMEforgejo安装页「数据库名」预填该值
FORGEJO__database__USER[database] USERforgejo安装页「用户」预填该值
FORGEJO__database__PASSWD[database] PASSWD${FORGEJO_DB_PASSWORD}安装页「密码」预填,实际值来自 .env
FORGEJO__server__DOMAIN[server] DOMAINgit.example.com预填服务器域名
FORGEJO__server__ROOT_URL[server] ROOT_URLhttps://git.example.com/预填基础 URL
FORGEJO__security__INSTALL_LOCK[security] INSTALL_LOCKtrue置 true 跳过安装向导(配合导入备份恢复场景)

规则:FORGEJO__<段名>__<键名> 双下划线分隔段与键,段名小写。其余任意 app.ini 键都可用该规则注入,无需挂载配置文件。

九、配置文件挂载

除了环境变量注入,也可以直接挂载完整的 app.ini。两种方式对比:

方式适用场景做法
环境变量注入少量关键项(数据库、域名、密码),向导预填environment: 里写 FORGEJO__段__键(本文采用)
挂载配置文件配置项多、需要版本化管理 app.inivolumes: 增加 - /opt/data/forgejo/app.ini:/data/gitea/conf/app.ini

⚠️ 两种方式同时使用时环境变量优先级更高(启动时覆盖挂载文件中的对应键)。首次部署推荐「环境变量注入 + 向导生成」;后续把生成的 /opt/data/forgejo/forgejo/gitea/conf/app.ini 纳入配置管理即可——它本身就是 bind mount 出来的宿主文件,直接可改,改完重启生效(实测流程见《Forgejo 16.0 配置参数详解》)。

十、等价 docker run 命令

不用 Compose 时,以下两条 docker run 与本文 compose.yml 完全等价(注意先手工建网络):

docker network create forgejo-net

docker run -d --name forgejo-16-db --network forgejo-net \
  -e POSTGRES_USER=forgejo \
  -e POSTGRES_PASSWORD=Forgejo2026Db \
  -e POSTGRES_DB=forgejo \
  -v /opt/data/forgejo/db:/var/lib/postgresql/data \
  --restart unless-stopped \
  postgres:16-alpine

docker run -d --name forgejo-16.0.6-devops --network forgejo-net \
  -p 3100:3000 -p 3122:22 \
  -e USER_UID=1000 -e USER_GID=1000 \
  -e FORGEJO__database__DB_TYPE=postgres \
  -e FORGEJO__database__HOST=forgejo-16-db:5432 \
  -e FORGEJO__database__NAME=forgejo \
  -e FORGEJO__database__USER=forgejo \
  -e FORGEJO__database__PASSWD=Forgejo2026Db \
  -v /opt/data/forgejo/forgejo:/data \
  -v /etc/timezone:/etc/timezone:ro \
  -v /etc/localtime:/etc/localtime:ro \
  --restart unless-stopped \
  codeberg.org/forgejo/forgejo:16.0.6

💡 生产仍推荐 Compose:两个服务的网络、依赖、重启策略在一个文件里声明,升级与迁移时 docker compose pull && docker compose up -d 一步完成。

十一、常用运维命令

以下命令在 /opt/data/forgejo/ 目录下执行:

操作命令
查看服务状态docker compose ps
查看实时日志docker compose logs -f forgejo
重启单个服务docker compose restart forgejo
停止整个栈(保留数据)docker compose down
停止并删除数据卷之外的所有资源docker compose down --remove-orphans
升级镜像(先备份!)docker compose pull && docker compose up -d

⚠️ docker compose down 不会删除 bind mount 的宿主目录(/opt/data/forgejo/),数据安全;但千万不要对数据目录执行 rm -rf 来"重置"——数据库文件被删后无法恢复,重置前先做 dump。

十二、常见问题

Q1:访问 3100 端口返回的页面是英文的安装向导,但数据库报错连不上? 先确认数据库服务状态 docker compose ps 中 db 为 Up;再看日志 docker compose logs db | tail。实测中最常见的根因是 .env 未创建导致 POSTGRES_PASSWORD 与 Forgejo 侧不一致——两者必须用同一个变量值(本文统一为 ${FORGEJO_DB_PASSWORD})。

Q2:git push 时提示 The requested URL returned error: 403? HTTP push 需要 URL 中携带账号密码(本文 http://root:q1w2e3r4@localhost:3100/...)或在客户端配置凭据。若用 token,用户名填任意非空字符串、密码填 token。403 也可能因为目标仓库为私有且凭据无写权限。

Q3:页面显示的 SSH clone 地址是 git@localhost:3122/...,同事机器上连不上? localhost 是安装向导「服务器域名」填的值。生产改为对外域名或 IP(改 app.ini 的 [server] DOMAIN 与 SSH_DOMAIN 后重启),实测改法与效果见《Forgejo 16.0 配置参数详解》。

Q4:首次启动时 Forgejo 反复重连数据库? depends_on 只保证启动顺序不保证就绪。PostgreSQL 首次初始化(创建目录结构)需要几秒到几十秒,Forgejo 默认重试 10 次,通常能自动追上;若日志出现 ORM engine initialization attempt #x/10 后仍失败,等数据库 Up 后 docker compose restart forgejo 即可。

Q5:想用 SQLite 快速试一下,compose 怎么改? 去掉 db 整个 service、去掉 Forgejo 的 5 个 FORGEJO__database__* 变量与 depends_on,安装向导「数据库类型」选 SQLite3、路径填 /data/gitea/forgejo.db 即可。SQLite 实测可正常完成建仓/push/Issue 验收,但多人协作与 Actions 场景建议 PostgreSQL。

十三、参考链接