清羽AI正在绞尽脑汁想思路ING···
清羽のAI摘要
GLM-4-Flash

碎碎念

哎哟我滴个天,陕西这鬼天气真是要命,前几天去趟西安博物院差点热化了,不下雨根本不敢出门啊!

反正最近宅在家里闲着,出去玩也出不去,没什么事情可做,就找了一些开源项目部署,于是找到了ForgeJo,作为Gitea的开源替代,二者部署方式基本一致,只是有部分细节稍微不同,于是捣鼓了一下ForgeJo,感觉还不错哦,功能方面打磨的也比较到位,符合我的要求。

不过 ForgeJo Action 的部署稍微有点麻烦。我主力服务器现在用的是 1Panel 面板来做运维,图个方便,就干脆顺手适配了一下 1Panel 的第三方应用商店,现在支持一键部署啦!

项目区别

在部署ForgeJo的过程中,很多人可能会搞混几个名字:GogsGiteaForgeJoGitLab。这些工具本质上都能用来搭建私有的Git仓库服务,但它们之间的关系和取舍点还是挺有意思的。

故事要从Gogs开始。Gogs是最早一批由国人开发的Go语言写的Git服务平台,主打一个“开箱即用、部署简单”。很多人最初自建 Git 服务就是靠它。

但由于Gogs项目长期由一个核心作者主导,节奏比较慢,社区声音也不多,于是就有一群核心贡献者决定另起炉灶,创建了GiteaGitea一出来,立刻把“社区驱动”挂在了旗帜上,不仅继承了Gogs的轻量特性,还快速迭代,增加了很多现代化功能,比如Issues、项目看板、Pull RequestWebhooks等等。尤其是中文用户多,文档全、更新快,很快成为Gogs的“精神续作”,用户非常广泛。

好景不长,Gitea后来出现了一些争议,项目仓库被私人商业公司接管、核心决策开始不透明化。于是,2022年底社区再次爆发,部分维护者又分叉出了ForgeJoForgeJo表面看和Gitea几乎一模一样,实际上它更强调社区治理、反对商业控制。ForgeJo仍然基于Gitea构建,所以配置文件、插件系统、UI等等几乎都通用。

Gitea收购?

关于Gitea是否被收购这个问题,其实情况有些微妙。严格来说Gitea项目本身并没有被外部公司直接收购,但在2022年下半年,Gitea的核心维护者之一、用户名为 lunny 的开发者,牵头成立了一家公司,名为 Gitea Limited。这家公司注册在香港,并在没有提前与社区广泛沟通的情况下,接管了Gitea项目的主要GitHub仓库、域名以及商标。这一行为虽然在法律上无可厚非,但在开源社区中引发了很大的争议,很多人认为原本由社区共治的项目突然被转交给一家私人公司,等于“悄悄地商业化”了。

这一变更过程几乎没有征询社区意见,导致一些长期参与Gitea开发的核心维护者感到被排除在外。这种不透明的项目治理模式引起了部分维护者的强烈不满。于是,这些维护者决定分叉Gitea,重新建立一个完全由社区驱动、保持开源纯洁性的项目,也就是后来诞生的 ForgeJoForgeJo的理念非常明确:不接受商业公司控制,坚持社区治理路线,强调开放透明的发展模式。虽然ForgeJo诞生时间较短,但由于它是在Gitea的基础上继续开发的,因此兼容性极好,几乎可以无缝替代原来的Gitea部署方案。

目前,Gitea依然在积极维护和更新,功能也非常丰富,社区规模较大。不过,由Gitea Limited管理的模式意味着未来的方向可能会更偏向商业化,比如推出商业支持计划、专属插件、付费功能等。而ForgeJo则选择了另一条路线,力图保持项目的独立性和社区性。

GitLab则是另一条路线了,它完全不是Gogs这条Go系的延伸,而是一个Ruby起家的超大型DevOps平台。它不仅是Git托管工具,还是一个完整的CI/CD流水线平台,甚至包括了代码审查、代码质量分析、容器仓库、项目Wiki、权限管理等等,几乎覆盖了整个软件开发生命周期。当然,它也因此变得异常庞大:几GB内存是常态,部署配置极其复杂,小团队或个人基本折腾不动。虽然GitLab功能强大到离谱,但更适合大型团队或者企业环境,不太适合像我这样只想自建个轻量代码库、顺便跑个Action的个人用户。

特性GogsGiteaForgeJoGitLab
起源最初项目Gogs分叉Gitea分叉独立开发
开发语言GoGoGoRuby + Go
更新节奏稳定适中快但复杂
功能丰富度基础够用功能齐全功能齐全功能极其强大
社区治理作者主导社区+公司纯社区驱动公司主导
系统资源占用极低非常高
部署难度简单简单简单麻烦
适合人群个人用户个人/小团队个人/小团队中大型团队

说到这里,其实也就能看出来各家的定位了:Gogs是最轻量的基础版,不太推荐使用,功能略显简陋,Gitea是功能全面的主流选手,ForgeJo是理想主义的社区坚守者,而GitLab就是面向企业的全能怪兽。如果你只是想找个能自己托管、顺手用的Git服务,又不想买大服务器、不想被商业牵着走,GiteaForgeJo就是最好的选择。而我,选择了 ForgeJo

部署教程

应用商店

如果你是1Panel用户,我比较推荐使用应用商店一键部署,可以更加便捷的连接到本地的数据库,以及方便管理。下面是我自己整理的三方仓库:

由于主要用于自用,所以应用并不是很多,你可以选择性的将仓库中app内的文件夹移动到/opt/1panel/resource/apps/local目录下,刷新一下本地应用即可看到。

如果懒得一个个选可以创建一个定时任务,脚本内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/bash

set -e

# 配置路径
GIT_REPO="https://cnb.cool/Liiiu/appstore"
TMP_DIR="/opt/1panel/resource/apps/local/appstore-localApps"
LOCAL_APPS_DIR="/opt/1panel/resource/apps/local"

echo "📥 Cloning appstore repo..."
git clone "$GIT_REPO" "$TMP_DIR"

mkdir -p "$LOCAL_APPS_DIR"

for app_path in "$TMP_DIR/apps/"*; do
[ -d "$app_path" ] || continue

app_name=$(basename "$app_path")
local_app_path="$LOCAL_APPS_DIR/$app_name"

echo "🔁 Updating app: $app_name"
[ -d "$local_app_path" ] && rm -rf "$local_app_path"
cp -r "$app_path" "$local_app_path"
done

echo "🧼 Cleaning up temporary repo..."
rm -rf "$TMP_DIR"

echo "✅ Sync completed."

国外环境请替换为 GitHub 仓库:

1
GIT_REPO="https://github.com/willow-god/appstore"

执行一次定时任务后,在全部应用部分点击同步本地应用即可实现!

同步本地应用

如果一切正常,你可以在此处搜索Forgejo并直接安装啦!

ForgeJo

本体的部署和Gitea基本一致,所以没有什么可讲的,我们可以使用Docker-Compose直接启动,在任意目录下创建文件docker-compose.yaml,写入一下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
networks:
forgejo:
external: false

services:
server:
image: codeberg.org/forgejo/forgejo:11
container_name: forgejo
environment:
- USER_UID=1000
- USER_GID=1000
restart: always
networks:
- forgejo
volumes:
- ./forgejo:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- '3000:3000'
- '222:22'

以上方式默认为SQLite启动,如果想要使用数据库启动,请参考文档:

如果一切正常,反向代理3000端口即可成功访问初始化页面,完成初始化页面即可实现部署啦!222端口是用于SSH拉取仓库,如果你不常用SSH,那么HTTP拉取方式已经能够满足需要啦!

Actions

action也可以在上面的应用商店一键下载,速度更快哦!可以选择dind或者宿主机安装版本。

Forgejo actions和普通的Gitea actions有一定的相似性,但又不完全相同,需要手动进行初始化,才能正常执行。

一般安装都是直接在宿主机docker安装,并挂在宿主机sock文件,这种方式给的权限过大,有整个容器网络的删除权限,如果个人用无所谓,但是容易被人滥用导致数据丢失,所以出现了dind安装和另一个context安装的方式,后者需要配置无根Docker,稍微比较麻烦,所以在这里我推荐使用dind或者宿主机安装的方式。

dind和宿主机安装的利弊

DIND,全称是Docker-in-Docker,就是在容器里再运行一套Docker守护进程,这样这个容器就能自己管理镜像、运行其他容器了。

使用DIND的好处在于它更安全、更隔离,每个Runner拥有自己独立的Docker环境,不会干扰宿主机上其他容器的运行。这在多用户、多Runner场景下非常有用。但代价是资源占用会高一些,因为每个Runner容器内部都要再启动一个完整的Docker守护进程,内存和CPU会有额外开销。

所以按需选择即可,如果你只是自己用、追求部署简单、对安全性要求没那么高,宿主机的Docker Socket更实用;但如果你希望构建环境隔离,避免相互干扰或者潜在的安全隐患,使用DIND是更稳妥的选择,尽管它会多占一些资源。

宿主机安装

首先,在你的Forgejo实例找到注册密钥,一般在右上角头像,设置,action中即可以看到:

获得注册密钥

由于是宿主机直接安装,我建议使用个人密钥,所以在这里创建,如果你想提供给Forgejo实例内的所有用户使用,可以在网站管理中的action进行创建。

随后,创建docker-compose.yaml文件,写入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
version: "3.9"

services:
forgejo_runner:
image: code.forgejo.org/forgejo/runner:7.0.0
container_name: forgejo-runner
restart: always
user: root
command: >-
/bin/sh -c '
cd /data &&
if [ ! -s .runner ]; then
echo ">>> Registering runner..."
forgejo-runner register --no-interactive \
--instance "https://git.liushen.fun/" \
--token "你的注册密钥" \
--name "runner名称" \
--labels "标签,不敢乱填,看下面说明";
forgejo-runner generate-config > config.yml
fi;
echo ">>> Starting daemon..."
forgejo-runner --config config.yml daemon
'
volumes:
- ./data:/data
- /var/run/docker.sock:/var/run/docker-forgejo-runner.sock
environment:
- FORGEJO_INSTANCE_URL="https://git.liushen.fun/"
- RUNNER_REGISTRATION_TOKEN="你的注册密钥"
- RUNNER_NAME="forgejo-runner"
- RUNNER_LABELS="标签,不敢乱填,看下面说明"
networks:
- 1panel-network
labels:
createdBy: "Apps"

networks:
1panel-network:
external: true

以上有一个标签的配置内容,这个标签是用于判断采用哪个action的重要依据,如果没有成功配置可能会导致无法分配action执行,建议的默认值如下:

1
ubuntu-latest:docker://gitea/runner-images:ubuntu-latest,ubuntu-24.04:docker://gitea/runner-images:ubuntu-24.04,ubuntu-22.04:docker://gitea/runner-images:ubuntu-22.04,ubuntu-20.04:docker://gitea/runner-images:ubuntu-20.04

尝试部署,应该就可以实现咯!

DinD安装

这种方法的安全性更高,不给最高权限,不会害怕影响到宿主机的数据。

还是先获取注册密钥,然后再在服务器的任意位置创建文件docker-compose.yaml,写入内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
version: "3.9"

services:
dind:
image: docker:24.0-dind
container_name: forgejo-dind
privileged: true
restart: always
environment:
DOCKER_TLS_CERTDIR: ""
volumes:
- forgejo-dind-data:/var/lib/docker
networks:
- 1panel-network

forgejo_runner:
image: code.forgejo.org/forgejo/runner:7.0.0
container_name: ${CONTAINER_NAME:-forgejo-runner}
depends_on:
- dind
restart: always
user: "1000:1000"
environment:
- DOCKER_HOST=tcp://dind:2375
- FORGEJO_INSTANCE_URL=${FORGEJO_INSTANCE_URL}
- RUNNER_REGISTRATION_TOKEN=${RUNNER_REGISTRATION_TOKEN}
- RUNNER_NAME=${RUNNER_NAME:-default-runner}
- RUNNER_LABELS=${RUNNER_LABELS:-docker:docker://node:20-bookworm}
command: >
/bin/sh -c '
cd /data &&
if [ ! -s .runner ]; then
echo ">>> Registering runner..." &&
forgejo-runner register --no-interactive \
--instance ${FORGEJO_INSTANCE_URL} \
--token ${RUNNER_REGISTRATION_TOKEN} \
--name ${RUNNER_NAME} \
--labels ${RUNNER_LABELS} &&
forgejo-runner generate-config > config.yml;
fi &&
echo ">>> Starting daemon..." &&
forgejo-runner --config config.yml daemon
'
volumes:
- ./data:/data
networks:
- 1panel-network

volumes:
forgejo-dind-data:

networks:
1panel-network:
external: true

请自行替换一些变量,这里我就懒得改咯!

如果一切正常,会启动两个容器,一个是runner本身,一个是dind,当runner接收到任务后,会在dind创建容器,执行任务,执行完成后,会自动清理dind内部的容器。

action具体怎么配置的话,大家自己琢磨琢磨吧~主要是我还没玩明白呢!

配置教程

Action具体倒是没啥能配置的,在这里我主要讲解一下Forgejo本体的配置和主题,自定义。

配置文件

找到Forgejo映射的目录,找到gitea文件夹,比如:/data/gitea/conf,如果没什么问题。里面会有一个app.ini文件,这里存的就是我们的所有配置,所有配置请查看说明文档:

这里我主要说明几个建议修改的配置项。

  1. 顶部的实例信息,可以设置实例的名称,和说明文字:

    1
    2
    3
    4
    5
    APP_NAME = 清羽Git
    RUN_MODE = prod
    APP_SLOGAN = 清羽飞扬の个人仓库
    RUN_USER = 默认即可
    WORK_PATH = /data/gitea
  2. Server:这里规定了一些实例相关的配置文本,和ssh端口,如果你是用外部的222映射,注意修改端口:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [server]
    APP_DATA_PATH = /data/gitea
    DOMAIN = git.liushen.fun
    SSH_DOMAIN = git.liushen.fun
    HTTP_PORT = 3000
    ROOT_URL = https://git.liushen.fun/
    DISABLE_SSH = false
    SSH_PORT = 222 # 这个端口记得修改
    SSH_LISTEN_PORT = 22
    LFS_START_SERVER = true
    LFS_JWT_SECRET = abcdefgabcdefgabcdefgabcdefgabcdefgabcd
    OFFLINE_MODE = false
  3. Picture:这里设置了个人头像的一些配置,默认使用gravatar头像,但是由于已知原因,在国内速度不理想,所以可以按照以下方式修改:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [picture]
    AVATAR_UPLOAD_PATH = /data/gitea/avatars
    REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars
    DISABLE_GRAVATAR = false
    GRAVATAR_SOURCE = https://weavatar.com/avatar/
    AVATAR_MAX_WIDTH = 4096
    AVATAR_MAX_HEIGHT = 4096
    AVATAR_MAX_FILE_SIZE = 1048576
    AVATAR_MAX_ORIGIN_SIZE = 262144
    AVATAR_RENDERED_SIZE_FACTOR = 2
    ENABLE_FEDERATED_AVATAR = false

其他的配置比如邮箱配置,主题配置,可以参考配置文件及其说明文档进行开发。

自定义页面

/data/gitea文件夹下,实际上还有一个templates文件夹,但是这个文件夹在启动的时候会在docker内部自动补全,外部一般看不到,所以在这里我们只需要覆盖一下即可实现自定义,具体templates文件夹的结构可以看下面forgejo源码:

比如我需要覆写主页的代码,可以找到这个文件地址:

home主页

那么我们可以创建以下文件data/gitea/templates/home.tmpl,这样在挂载的时候就会覆盖掉原始文件。

本站主页

比如本站的home.tmpl内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
{{template "base/head" .}}

<style>
:root {
/* 亮色模式默认值 */
--home-text: #2c3e50;
--home-text-light: #7f8c8d;
--home-text-dark: #2c3e50;
--home-primary: #3498db;
--home-primary-dark: #2980b9;
--home-secondary: #ffffff;
--home-secondary-dark: #f8f9fa;
--home-border: #dfe6e9;
--home-card-bg: #f8f9fa;
--home-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

@media (prefers-color-scheme: dark) {
:root {
--home-text: #ecf0f1;
--home-text-light: #bdc3c7;
--home-text-dark: #ecf0f1;
--home-primary: #3498db;
--home-primary-dark: #2980b9;
--home-secondary: #2d2d2d;
--home-secondary-dark: #252525;
--home-border: #444;
--home-card-bg: #252525;
--home-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
}

.custom-home {
display: flex;
justify-content: space-between;
align-items: center;
min-height: calc(100vh - 130px);
padding: 2rem 8%;
}

.custom-home .left {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 2rem;
}

.custom-home .left img {
max-width: 70%;
max-height: 60%;
object-fit: contain;
filter: drop-shadow(var(--home-shadow));
transition: transform 0.3s ease;
}

.custom-home .left img:hover {
transform: scale(1.05);
}

.custom-home .right {
flex: 1;
padding: 2rem;
color: var(--home-text);
}

.custom-home .right h1 {
font-size: 3.5rem;
margin-bottom: 1.5rem;
font-weight: 700;
color: var(--home-primary);
line-height: 1.2;
}

.custom-home .right h2 {
font-size: 1.75rem;
margin-bottom: 2rem;
color: var(--home-text-light);
font-weight: 400;
line-height: 1.5;
}

.custom-home .right .description {
font-size: 1.1rem;
color: var(--home-text-light);
margin-bottom: 2rem;
line-height: 1.6;
}

.custom-home .right p.credit {
font-size: 1rem;
color: var(--home-text-light);
margin-top: 2rem;
position: relative;
padding-left: 1.5rem;
}

.custom-home .right p.credit:before {
content: "";
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
height: 60%;
width: 3px;
background: var(--home-primary);
border-radius: 3px;
}

.action-buttons {
display: flex;
gap: 1rem;
margin-top: 2.5rem;
flex-wrap: wrap;
}

.btn {
padding: 0.75rem 1.5rem;
border-radius: 50px;
text-decoration: none;
font-weight: 500;
transition: all 0.3s ease;
text-align: center;
}

.btn-secondary {
background-color: var(--home-secondary);
color: var(--home-text);
border: 1px solid var(--home-border);
}

.btn-secondary:hover {
background-color: var(--home-secondary-dark);
transform: translateY(-2px);
}

.features {
display: flex;
gap: 1.5rem;
margin: 2rem 0;
flex-wrap: wrap;
}

.feature-item {
flex: 1;
min-width: 150px;
padding: 1rem;
border-radius: 8px;
background-color: var(--home-card-bg);
text-align: center;
}

.feature-icon {
font-size: 1.5rem;
margin-bottom: 0.5rem;
color: var(--home-primary);
}

@media (max-width: 992px) {
.custom-home {
flex-direction: column;
text-align: center;
padding: 4rem 5%;
}

.custom-home .right {
padding: 2rem 0;
}

.custom-home .right h1 {
font-size: 2.5rem;
}

.custom-home .right h2 {
font-size: 1.5rem;
}

.custom-home .right p.credit {
padding-left: 0;
}

.custom-home .right p.credit:before {
display: none;
}

.action-buttons {
justify-content: center;
}
}

@media (max-width: 576px) {
.custom-home .right h1 {
font-size: 2rem;
}

.custom-home .right h2 {
font-size: 1.25rem;
}

.action-buttons {
flex-direction: column;
gap: 0.75rem;
}

.btn {
width: 100%;
}
}
</style>

<div class="custom-home">
<div class="left">
<img src="https://git.liushen.fun/assets/img/logo.png" alt="QingYu Git Logo">
</div>
<div class="right">
<h1>QingYu Git</h1>
<h2>您的自托管Git解决方案</h2>

<div class="description">
QingYu Git提供稳定、高效的代码托管服务,专为国内开发者优化。<br>
支持Git仓库管理、代码审查、CI/CD集成,让您的开发流程更加顺畅。
</div>

<div class="features">
<div class="feature-item">
<div class="feature-icon"></div>
<div>极速访问</div>
</div>
<div class="feature-item">
<div class="feature-icon">🛡️</div>
<div>数据安全</div>
</div>
<div class="feature-item">
<div class="feature-icon">🌐</div>
<div>国内优化</div>
</div>
</div>

<div class="action-buttons">
<a href="/explore/repos" class="btn btn-secondary">浏览仓库</a>
<a href="/user/login" class="btn btn-secondary">登录账户</a>
<a href="/user/sign_up" class="btn btn-secondary">注册新账户</a>
</div>

<p class="credit">基于 <strong>ForgeJo</strong> 构建 | 专为国内开发者优化</p>
</div>
</div>

{{template "base/footer" .}}

这样就可以得到本站同款主页啦!

自定义图标

除了tmpl存放的模板文件夹,我们可以在data/gitea中创建一个public文件夹,这个文件夹内的所有内容都会被映射到网络路径上,比如上传图片文件:

1
2
local_path: ./data/gitea/public/assets/img/favicon.png
web_url: https://git.liushen.fun/assets/img/favicon.png

即可访问到如上本站的图标,按照这个原理,我们可以覆盖任意文件实现自定义所有图像,比如网站图标:

覆写网站图标

这里就不一一举例了,大家应该都懂哩!

自定义主题

我之前也自定义了主题,但是到后面发现其实也就默认的好用,适配最好,所以也都删哩,大家可以按需尝试!

同样是assets文件夹,自定义图标位置我们用的是img子文件夹,在自定义主题我们使用的是css子文件夹:

自定义主题

主题的css使用theme-前缀,后面是主题名称,一个主题对应一个css文件,css文件可以尝试搜索gitea-theme获取别人写好的,但是我总感觉有点兼容问题,所以后面恢复了默认主题QAQ:

只是放在这里无法启用主题,还需要一定的配置,在上面说的配置文件app.ini文件中,添加[ui]配置项,完整配置可看:

这里我们只需要THEMEDEFAULT_THEME两个参数:

1
2
3
4
5
6
7
8
9
10
;; Set the default theme for the Gitea install
DEFAULT_THEME = forgejo-auto
;;
;; All available themes. Allow users select personalized themes regardless of the value of `DEFAULT_THEME`.
;; By default available:
;; - forgejo-auto, forgejo-light, forgejo-dark
;; - gitea-auto, gitea-light, gitea-dark
;; - forgejo-auto-deuteranopia-protanopia, forgejo-light-deuteranopia-protanopia, forgejo-dark-deuteranopia-protanopia
;; - forgejo-auto-tritanopia, forgejo-light-tritanopia, forgejo-dark-tritanopia
THEMES = gitea-auto,gitea-light,gitea-dark

THEMES添加所有的主题,主题名称对应文件名称THEME-{主题名称}.css

然后重新创建docker

1
docker compose up -d --force-recreate

如果一切正常,你就可以在设置上修改主题啦!

总结

Forgejo配置完毕!事实上,开源项目商业化的事情早已屡见不鲜。今天是GiteaAlist,明天也许就轮到了ForgejoOpenList等新的项目涌现。问题的关键不在于是否收购,而在于收购方的信誉。以Alist为例,其背后的公司曾因投毒和黑产行为破坏多个开源项目,如今几乎人人避之不及。而Gitea虽然也经历了商业化,但至少目前尚未传出类似恶劣的声誉,用户群体依然庞大。
开源项目的发展确实需要资金和资源的支持,收购本身并非原罪。只是我个人认为,选择一个有信誉、有社区责任感的“下家”,才是真正对得起广大用户与每一位贡献者的做法。

每日一图

图片来自哲风壁纸

乡村夜景