清羽AI正在绞尽脑汁想思路ING···
清羽のAI摘要
GLM-4-Flash
哎哟我滴个天,陕西这鬼天气真是要命,前几天去趟西安博物院差点热化了,不下雨根本不敢出门啊!
反正最近宅在家里闲着,出去玩也出不去,没什么事情可做,就找了一些开源项目部署,于是找到了ForgeJo
,作为Gitea
的开源替代,二者部署方式基本一致,只是有部分细节稍微不同,于是捣鼓了一下ForgeJo
,感觉还不错哦,功能方面打磨的也比较到位,符合我的要求。
不过 ForgeJo Action
的部署稍微有点麻烦。我主力服务器现在用的是 1Panel
面板来做运维,图个方便,就干脆顺手适配了一下 1Panel
的第三方应用商店,现在支持一键部署啦!
在部署ForgeJo
的过程中,很多人可能会搞混几个名字:Gogs
、Gitea
、ForgeJo
、GitLab
。这些工具本质上都能用来搭建私有的Git
仓库服务,但它们之间的关系和取舍点还是挺有意思的。
故事要从Gogs
开始。Gogs
是最早一批由国人开发的Go
语言写的Git
服务平台,主打一个“开箱即用、部署简单”。很多人最初自建 Git 服务就是靠它。
但由于Gogs
项目长期由一个核心作者主导,节奏比较慢,社区声音也不多,于是就有一群核心贡献者决定另起炉灶,创建了Gitea
。Gitea
一出来,立刻把“社区驱动”挂在了旗帜上,不仅继承了Gogs
的轻量特性,还快速迭代,增加了很多现代化功能,比如Issues
、项目看板、Pull Request
、Webhooks
等等。尤其是中文用户多,文档全、更新快,很快成为Gogs
的“精神续作”,用户非常广泛。
好景不长,Gitea
后来出现了一些争议,项目仓库被私人商业公司接管、核心决策开始不透明化。于是,2022
年底社区再次爆发,部分维护者又分叉出了ForgeJo
。ForgeJo
表面看和Gitea
几乎一模一样,实际上它更强调社区治理、反对商业控制。ForgeJo
仍然基于Gitea
构建,所以配置文件、插件系统、UI
等等几乎都通用。
Gitea收购?
关于Gitea
是否被收购这个问题,其实情况有些微妙。严格来说Gitea
项目本身并没有被外部公司直接收购,但在2022
年下半年,Gitea
的核心维护者之一、用户名为 lunny
的开发者,牵头成立了一家公司,名为 Gitea Limited。这家公司注册在香港,并在没有提前与社区广泛沟通的情况下,接管了Gitea
项目的主要GitHub
仓库、域名以及商标。这一行为虽然在法律上无可厚非,但在开源社区中引发了很大的争议,很多人认为原本由社区共治的项目突然被转交给一家私人公司,等于“悄悄地商业化”了。
这一变更过程几乎没有征询社区意见,导致一些长期参与Gitea
开发的核心维护者感到被排除在外。这种不透明的项目治理模式引起了部分维护者的强烈不满。于是,这些维护者决定分叉Gitea
,重新建立一个完全由社区驱动、保持开源纯洁性的项目,也就是后来诞生的 ForgeJo
。ForgeJo
的理念非常明确:不接受商业公司控制,坚持社区治理路线,强调开放透明的发展模式。虽然ForgeJo
诞生时间较短,但由于它是在Gitea
的基础上继续开发的,因此兼容性极好,几乎可以无缝替代原来的Gitea
部署方案。
目前,Gitea
依然在积极维护和更新,功能也非常丰富,社区规模较大。不过,由Gitea Limited
管理的模式意味着未来的方向可能会更偏向商业化,比如推出商业支持计划、专属插件、付费功能等。而ForgeJo
则选择了另一条路线,力图保持项目的独立性和社区性。
而GitLab
则是另一条路线了,它完全不是Gogs
这条Go
系的延伸,而是一个Ruby
起家的超大型DevOps
平台。它不仅是Git
托管工具,还是一个完整的CI/CD
流水线平台,甚至包括了代码审查、代码质量分析、容器仓库、项目Wiki
、权限管理等等,几乎覆盖了整个软件开发生命周期。当然,它也因此变得异常庞大:几GB内存是常态,部署配置极其复杂,小团队或个人基本折腾不动。虽然GitLab
功能强大到离谱,但更适合大型团队或者企业环境,不太适合像我这样只想自建个轻量代码库、顺便跑个Action
的个人用户。
特性 | Gogs | Gitea | ForgeJo | GitLab |
---|---|---|---|---|
起源 | 最初项目 | 从Gogs分叉 | 从Gitea分叉 | 独立开发 |
开发语言 | Go | Go | Go | Ruby + Go |
更新节奏 | 慢 | 快 | 稳定适中 | 快但复杂 |
功能丰富度 | 基础够用 | 功能齐全 | 功能齐全 | 功能极其强大 |
社区治理 | 作者主导 | 社区+公司 | 纯社区驱动 | 公司主导 |
系统资源占用 | 极低 | 低 | 低 | 非常高 |
部署难度 | 简单 | 简单 | 简单 | 麻烦 |
适合人群 | 个人用户 | 个人/小团队 | 个人/小团队 | 中大型团队 |
说到这里,其实也就能看出来各家的定位了:Gogs
是最轻量的基础版,不太推荐使用,功能略显简陋,Gitea
是功能全面的主流选手,ForgeJo
是理想主义的社区坚守者,而GitLab
就是面向企业的全能怪兽。如果你只是想找个能自己托管、顺手用的Git
服务,又不想买大服务器、不想被商业牵着走,Gitea
和ForgeJo
就是最好的选择。而我,选择了 ForgeJo
。
如果你是1Panel
用户,我比较推荐使用应用商店一键部署,可以更加便捷的连接到本地的数据库,以及方便管理。下面是我自己整理的三方仓库:
由于主要用于自用,所以应用并不是很多,你可以选择性的将仓库中app
内的文件夹移动到/opt/1panel/resource/apps/local
目录下,刷新一下本地应用即可看到。
如果懒得一个个选可以创建一个定时任务,脚本内容如下:
#!/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 仓库: GIT_REPO="https://github.com/willow-god/appstore"
执行一次定时任务后,在全部应用部分点击同步本地应用即可实现!
如果一切正常,你可以在此处搜索Forgejo
并直接安装啦!
本体的部署和Gitea
基本一致,所以没有什么可讲的,我们可以使用Docker-Compose
直接启动,在任意目录下创建文件docker-compose.yaml
,写入一下内容:
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
拉取方式已经能够满足需要啦!
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
文件,写入以下内容:
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
执行,建议的默认值如下:
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
尝试部署,应该就可以实现咯!
这种方法的安全性更高,不给最高权限,不会害怕影响到宿主机的数据。
还是先获取注册密钥,然后再在服务器的任意位置创建文件docker-compose.yaml
,写入内容:
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
文件,这里存的就是我们的所有配置,所有配置请查看说明文档:
这里我主要说明几个建议修改的配置项。
顶部的实例信息,可以设置实例的名称,和说明文字:
APP_NAME = 清羽Git
RUN_MODE = prod
APP_SLOGAN = 清羽飞扬の个人仓库
RUN_USER = 默认即可
WORK_PATH = /data/gitea
Server
:这里规定了一些实例相关的配置文本,和ssh
端口,如果你是用外部的222
映射,注意修改端口:
[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
Picture
:这里设置了个人头像的一些配置,默认使用gravatar
头像,但是由于已知原因,在国内速度不理想,所以可以按照以下方式修改:
[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
源码:
比如我需要覆写主页的代码,可以找到这个文件地址:
那么我们可以创建以下文件data/gitea/templates/home.tmpl
,这样在挂载的时候就会覆盖掉原始文件。
比如本站的home.tmpl
内容如下:
{{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
文件夹,这个文件夹内的所有内容都会被映射到网络路径上,比如上传图片文件:
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]
配置项,完整配置可看:
这里我们只需要THEME
和DEFAULT_THEME
两个参数:
;; 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
:
docker compose up -d --force-recreate
如果一切正常,你就可以在设置上修改主题啦!
Forgejo
配置完毕!事实上,开源项目商业化的事情早已屡见不鲜。今天是Gitea
和Alist
,明天也许就轮到了Forgejo
、OpenList
等新的项目涌现。问题的关键不在于是否收购,而在于收购方的信誉。以Alist
为例,其背后的公司曾因投毒和黑产行为破坏多个开源项目,如今几乎人人避之不及。而Gitea
虽然也经历了商业化,但至少目前尚未传出类似恶劣的声誉,用户群体依然庞大。
开源项目的发展确实需要资金和资源的支持,收购本身并非原罪。只是我个人认为,选择一个有信誉、有社区责任感的“下家”,才是真正对得起广大用户与每一位贡献者的做法。