我是在一个普通的工作日晚上决定在家里的群晖上搭一套私有Git服务器的。起因并不复杂电脑里积累的脚本、配置文件、还有和几个朋友一起维护的小项目越来越多公共托管平台虽然方便但有些东西放上去总感觉不太对劲——不是说平台不好而是代码资产在自己手里、在自己的设备上才睡得踏实。群晖这台机器本来就7x24小时开着硬盘空间也够折腾一套Git服务几乎是顺理成章的事。当时为了选方案我把群晖官方Git Server套件、Gitea、GitLab CE都试了一遍最后稳定跑起来的是基于Docker部署的Gitea。整个过程不算复杂但坑是真不少尤其是端口冲突、权限、证书这类细节文档里往往一句话带过实操时却能卡你一下午。这篇就按我真实搭建的顺序把从选型到部署、从接入到日常维护的关键步骤和踩坑记录全写出来。如果你手里正好有一台群晖不管是DSM 7还是老一点的型号想给家里或小团队搞一个私有Git仓库这篇应该能帮你少走不少弯路。1. 为什么放着现成的托管平台不用偏要在群晖上折腾Git很多人听到私有Git服务器第一反应是“有必要吗”。说实话如果只是一个人写点玩具项目公共托管平台的免费仓库完全够用没必要给自己找事。但当你遇到下面几种情况感受就完全不一样了。代码资产归属权的问题最直接。放公共平台代码虽然在你账号下但物理存储、服务可用性、未来的政策走向都不是你能控制的。有些内部工具脚本里可能带着内网地址、数据库连接信息、密钥样本这些东西不适合交给第三方托管。还有一类是学习笔记和实验项目内容不一定敏感但你就是不想让它们被公开搜索到更不希望某天收到平台的服务调整通知被迫迁移仓库。多设备协同也是我实际感受到的痛点。家里有台式机、笔记本偶尔还要在另外一台上拉代码。公共平台在国内的连通性时好时坏拉一个不大的仓库经常卡在对象枚举阶段更别说频繁推送了。自建在局域网内速度基本就是硬盘读写速度的上限推送大文件或者很多小文件时体感差距非常明显。群晖又是常开设备白天在公司推代码晚上回家在另一台设备上pull所有历史记录都同步在自己的NAS里这种“数据在自己手里”的踏实感用过一次就不太想回去。适合什么样的使用者我得说得实际一点。这套方案最适合的是个人开发者、两到五个人的小团队、家庭内部共享代码的场景。如果你需要复杂的CI/CD流水线、大规模多人协作、细粒度的Code Review流程群晖这台设备从硬件性能到软件生态都不太合适那是GitLab服务器或者专业托管平台的主场。说到底群晖上跑Git服务定位是“轻量、可控、私有”不是“企业级平台替代品”。我当时的决策逻辑很简单先明确需求边界——要Web界面不要纯裸仓库要用户和权限管理不要每个人都共用同一个系统账号要部署和维护简单不要像GitLab CE那样动辄吃好几个G内存。这样一来答案基本上就锁定在Gitea了。2. 动手前的准备群晖型号差异、存储规划与两条技术路线2.1 先确认你的群晖能不能跑起来不是所有群晖都适合做这件事。先看处理器架构Gitea官方镜像对x86_64架构支持最好绝大多数主流群晖型号比如Intel或AMD处理器的机器都没问题。如果是ARM架构的老机器虽然也有对应镜像但部分功能模块和一些社区组件的兼容性会差一些遇到问题排查起来成本更高。我的建议是ARM机型能跑但如果还没开始折腾优先用x86设备。内存方面Gitea本身是Go写的单二进制运行内存占用不算高日常大约200到300MB加上系统和其他容器2GB内存的机器能跑但有点紧4GB或以上就比较从容了。如果NAS上还跑着下载、相册、视频转码这些服务内存本来就不富裕那在开容器之前先看一下资源监控别一个服务把整台机器拖垮。DSM系统版本方面DSM 7以后套件中心里可以直接安装Container Manager界面化的容器管理体验不错。DSM 6 时代用的是Docker套件命令基本通用但界面和管理方式有差异。我后面写的操作以DSM 7 Container Manager为主如果你的系统还是旧版本建议先升级系统再折腾省得某些设置项找不到。另外建议提前在“控制面板 - 终端机”里把SSH功能打开后面有很多操作需要在命令行里执行。SSH功能默认端口22这个端口后面会和Gitea容器的SSH端口产生冲突我在第4章会专门讲怎么处理。2.2 存储目录设计别把Git仓库随手丢在Home目录这是我在第一次搭建时忽略的细节后来花了不少时间收拾。Gitea容器需要持久化存储包括仓库数据、数据库文件、配置、密钥等。如果在创建容器时随便挂载到一个临时目录或者干脆不指定卷容器一删除所有仓库全没了那感觉比丢代码还难受。我建议在NAS上单独规划一个目录跟其他服务隔离开。我的结构是这样的/volume1/docker/ ├── gitea/ │ ├── data/ # 容器数据卷挂载点 │ └── backup/ # 备份文件存放目录data目录是Gitea容器内/data的挂载点里面会存放git/repositories、sqlite数据库、conf/app.ini配置文件、ssh密钥等所有运行时数据。backup目录专门放定期打包的压缩包不参与容器运行避免备份文件混进数据卷里造成容器启动时扫描异常。这里有个关键点目录权限。群晖的共享文件夹和Docker容器的用户权限体系是两套逻辑。Gitea容器默认以USER_UID1000和USER_GID1000运行这个UID在多数群晖上对应着第一个创建的admin用户。如果你把目录创建在了某个特定共享文件夹下又给目录设置了复杂的ACL权限容器启动时可能因为写不进目录而直接报错退出。最稳妥的做法是在File Station里创建好目录然后用chmod给目录设成755或777级别的宽松权限或者干脆用命令行创建并显式指定属主。sudo mkdir -p /volume1/docker/gitea/data sudo mkdir -p /volume1/docker/gitea/backup sudo chown -R 1000:1000 /volume1/docker/gitea/data2.3 两条路线怎么选官方Git Server套件还是Docker跑Gitea群晖套件中心里其实有一个官方的“Git Server”套件很多人的第一个念头是“官方出的总该最省事吧”。我的实际体验是它只是把Linux系统里的git命令和一个裸仓库管理脚本打包成了套件装完之后你面对的不是一个Web界面而是一堆需要在SSH里手动初始化的裸仓库。要建仓库得登录NAS命令行执行git init --bare要加用户得在系统层面开账号要看代码没有网页入口只能靠git客户端走协议。这套东西适合极客玩家展示技术但对日常使用来说门槛和可维护性都很不友好。另一条路线是在Docker容器里跑Gitea。Gitea是一个开源的轻量Git服务界面和操作逻辑跟主流托管平台非常接近支持用户注册、组织、仓库权限、分支保护、Webhook、LFS等日常需要的功能。它的资源占用比GitLab CE小一个数量级部署时只要一个镜像加一把参数确实适合群晖这种资源有限的设备。如果追求更完整的功能矩阵还有人会尝试GitLab CE。我必须提醒GitLab CE默认内存要求是4GB起步实际跑起来经常到6GB以上群晖上如果还要跑其他服务光是内存占用就够喝一壶。配置和维护的复杂度也高更新、备份、权限体系都更重。除非你确实需要一套接近企业级的DevOps平台否则在群晖上跑GitLab纯属给自己找罪受。三条路线的核心差异我整理成了一张表方便直接做决策对比项官方Git Server套件Docker部署GiteaDocker部署GitLab CEWeb管理界面无有有用户/权限管理依赖系统账号内置完整体系内置完整体系资源占用极低低约300MB高4GB起步部署难度低中高备份迁移裸仓库手工打包打包数据卷即可依赖自带backup工具适合规模1-2人极客场景个人/小团队推荐中型团队或演示环境我最后选了Gitea理由有三个一是有Web界面非命令行用户也能上手二是权限模型够用不用给每个人开NAS系统账号三是备份和迁移极其简单数据卷打包走天下。如果你也是“想省心、不想折腾太多系统层面的东西”Gitea会是更顺手的选项。3. Docker部署Gitea的完整过程与关键参数解读3.1 安装Container Manager并把Gitea镜像拉到本地确认硬件和目录都准备好了就可以开始安装容器管理工具。DSM 7在套件中心搜“Container Manager”安装完打开你会看到一个支持镜像管理、容器创建、日志查看的可视化界面。我先在NAS上建好目录然后通过SSH命令行拉取镜像。拉镜像这一步如果你的网络环境一般就耐心等一会儿别中途中断不然镜像层损坏之后会留下一些莫名其妙的启动问题。sudo docker pull gitea/gitea:1.21.11版本标签我建议指定具体版本而不是用latest。latest虽然方便但Gitea升级有时会带来配置格式或数据库版本的变动你未必每一次都关注到。我用的是1.21.x系列稳定性和功能平衡都比较成熟。拉完之后可以用sudo docker images确认镜像已经存在。3.2 创建容器时容易被忽略的三个配置在Container Manager里创建容器时界面上会有一堆参数我重点说三个最容易出问题的配置项端口映射、卷映射、环境变量。端口映射要理解两层含义。Gitea本身有两个服务端口Web界面默认监听容器内的3000端口SSH服务默认监听容器内的22端口。群晖系统自带SSH服务也占用22端口如果让Gitea容器也直接用22端口就冲突了。常见的做法是把主机的3000端口映射到容器的3000同时把主机的2222端口映射到容器的22。这样从外部访问时Web是http://NAS地址:3000SSH是ssh://gitNAS地址:2222。卷映射就是把容器内的数据目录挂载到NAS实体路径上。这个我已经在第2.2节规划好了把/volume1/docker/gitea/data挂载到容器的/data。这一步漏掉的话容器一删除仓库和配置全没别问我怎么知道的。环境变量有三个值得关注USER_UID、USER_GID和TZ。前两个决定容器内进程以什么用户身份运行我设置为1000:1000对应群晖的admin权限避免文件在数据卷里攒下一堆容器内用户创建的古怪属主。TZ设置为Asia/Shanghai时区不对会导致容器内时间和宿主机不一致进而引发HTTPS证书校验之类的问题后面第5章会专门讲。在Container Manager的界面上这些参数分布在“端口设置”“存储设置”“环境”几个标签页里。如果想用命令行一气呵成也可以在NAS的SSH终端里执行sudo docker run -d \ --namegitea \ --restartalways \ -p 3000:3000 \ -p 2222:22 \ -v /volume1/docker/gitea/data:/data \ -e USER_UID1000 \ -e USER_GID1000 \ -e TZAsia/Shanghai \ gitea/gitea:1.21.11--restartalways这个参数别漏设置之后NAS重启容器会自动拉起来省得你每次重启都要手动打开。3.3 首次打开网页完成管理员初始化容器启动之后浏览器访问http://NAS的IP地址:3000第一次打开会进入Gitea的初始化配置页面。这一步看起来简单但里面几个字段直接决定了后续所有仓库的URL格式见过不少人在这里埋下隐患。初始化页面往下拉有几个设置项要仔细填。站点名称随意仓库根目录保持默认/data/git/repositories数据库类型这里推荐选SQLite。我知道有人会担心SQLite不够专业但群晖上跑Gitea的典型场景是个人或小团队并发量很低SQLite单文件数据库既省事又好备份恢复时把整个数据卷拷回去就行。真要上PostgreSQL或MySQL部署和备份的复杂度都会上一个台阶资源占用也更高收益却有限。等哪天仓库数量和并发数大到SQLite都扛不住时再规划迁移也不迟。重点在“应用通用设置”区域。这里的“域名”和“基础URL”要填Gitea对外可访问的地址如果暂用IP访问域名就填NAS的IP如果已经打算用HTTPS域名接入第4章会讲这里就直接填最终的域名地址免去以后挨个仓库改URL的麻烦。SSH端口务必填2222跟容器端口映射保持一致。很多人的SSH clone地址不对就是在这里没同步修改。填好之后创建管理员账号把用户名、密码、邮箱记牢初始化完成会自动跳转登录页。用管理员账号登录先去“管理面板”里看一眼“应用配置”确认SSH端口、基础URL都已经生效。3.4 创建第一个仓库并完成一次完整的push服务跑起来后先用管理员账号创建一个普通测试账号模拟真实用户的使用路径。然后登录测试账号点击右上角的“”新建仓库仓库名比如hello-gitea可见性选私有。在本地电脑上初始化一个项目并推送mkdir hello-gitea cd hello-gitea git init git config user.name 你的名字 git config user.email 你的邮箱 echo # Hello Gitea README.md git add README.md git commit -m first commit git remote add origin http://NAS的IP地址:3000/用户名/hello-gitea.git git push -u origin master首次使用HTTP方式推送时Git会提示输入账号密码这里的密码是Gitea账号的密码跟NAS系统密码不是一回事。推送成功后去Web界面刷新页面能看到README.md已经在仓库里了第一条推送链路就算完整打通。我建议从这里开始后续操作就切到SSH方式具体方法看第4.3节。HTTP推送虽然能用但每次都要输密码很多自动化脚本和git工具对HTTP方式的兼容处理也不如SSH干净。4. 让外部设备真正连上来SSH端口、HTTPS证书与访问入口4.1 群晖自带SSH和Gitea容器带SSH端口是怎么打架的这是我在搭建时遇到的第一个真正意义上的坑。群晖系统自己要开SSH服务端口默认是22而Gitea容器内部也跑着一个SSH服务端口也是22。要让两者共存就得把主机的2222端口映射给容器的22端口也就是前面创建容器时那条-p 2222:22的由来。光做端口映射还不够还要在DSM防火墙里放行TCP 3000和TCP 2222。如果你之前给NAS设置过防火墙规则很可能会发现容器端口对外不可达——不是Gitea没起来是防火墙把入站流量拦了。在“控制面板 - 安全性 - 防火墙”里为这两个端口添加允许规则来源IP可以根据实际需求限制如果在局域网内用直接填局域网网段就行。端口映射和防火墙都搞定后登录Gitea Web界面进入“管理面板 - 服务器设置 - SSH服务器”把“SSH端口”从默认的22改成2222。这个设置影响的是Gitea生成SSH clone地址时显示的端口号不改的话界面上给用户的clone地址会是ssh://gitNAS地址/用户名/仓库.git端口缺失用户复制过去必然连接失败。验证一下在本地终端执行ssh -p 2222 gitNAS地址看到Gitea返回的类似“Hi there, You‘ve successfully authenticated”的信息就说明SSH端口链路通了。4.2 用DSM反向代理和证书给Gitea一个正经的HTTPS地址一直用IP加3000端口访问能用但不够体面。更好的方案是用群晖自带的反向代理功能把Gitea的Web服务挂到一个域名和HTTPS端口下。在DSM里打开“控制面板 - 登录门户 - 高级 - 反向代理”新建一条规则。来源协议选HTTPS来源端口选443来源主机名填一个你想用的内网域名比如git.lan目的地协议选HTTP目的地端口填3000目的地主机名填localhost或NAS的局域网IP。注意开启“启用WebSocket”选项否则某些git客户端走HTTPS时会因为长连接被切断而报错。证书方面群晖的证书管理支持为域名签发受公共CA信任的免费证书申请时会验证域名所有权。这一步适合已经有了一个可控域名的场景比如你有一个自己的域名解析到NAS所在网络的IP上。如果只是纯内网使用也可以签一张内网自签证书只是客户端首次连接时会提示不受信任需要手动接受。申请到证书后回到“反向代理”设置把这条规则的证书指定为刚才签发的证书。之后浏览器访问https://git.lan就能到Gitea了。别忘了把Gitea初始化设置里的“基础URL”也改成https://git.lan这样Web界面生成的所有仓库clone地址都会自动带上HTTPS域名不会出现界面上显示的还是IP端口的情况。如果考虑外网访问我多说一句把群晖的任何管理端口直接暴露到公网都不是好主意。Gitea的Web登录、SSH端口都建议只在受信任网络内使用。如果确实需要在外网拉代码先想清楚身份认证、攻击面、端口扫描这些问题再决定要不要开公网入口。4.3 SSH公钥登录免密推送的关键一步有了SSH端口还需要配置公钥登录才能做到免密、安全地推送。原理很简单Gitea容器内部有一个专门的git用户当SSH请求进来时Gitea会读取对应账号下的公钥把它和仓库访问权限绑定起来。也就是说你往Gitea账号里添加一个公钥就等于把“持有这把公钥对应私钥的设备”授权为这个账号的身份。在本地电脑上生成密钥ssh-keygen -t ed25519 -C 你的备注信息一路回车即可默认会生成在~/.ssh/id_ed25519.pub。然后用文本编辑器打开公钥文件整段复制。登录Gitea Web界面进入“设置 - SSH密钥”粘贴保存。添加完成后把本地仓库的remote地址从HTTP改成SSH格式git remote set-url origin ssh://gitNAS的IP地址:2222/用户名/hello-gitea.git改完之后测试一下ssh -T -p 2222 gitNAS的IP地址第一次连接会提示确认主机指纹输入yes回车。看到欢迎信息就说明认证成功。之后再执行git push就不会再问密码了。我见过不少人卡在这一步明明加了公钥但还是提示要密码。通常是remote地址还停留在HTTP形式Gitea初始化设置里的SSH端口没同步或者公钥复制时多了一个换行符、少了前后缀。逐个检查这三点基本都能解决。5. 真实使用中的高频故障权限、时间、网络与备份5.1 连接超时与端口假死先分清是防火墙还是NAT跑了一段时间后遇到最多的现象是“突然连不上了”。这时候别急着怀疑Gitea服务挂了先按链路顺序排查。第一层容器本身是否在运行。SSH登录NAS执行sudo docker ps -a如果容器状态显示Exited看日志找原因如果状态是Up但就是访问不了继续往下查。第二层端口映射是否生效。sudo docker port gitea正常的输出会显示3000/tcp - 0.0.0.0:3000、22/tcp - 0.0.0.0:2222。如果映射缺失说明创建容器时参数就没对。第三层防火墙规则。在局域网内用另一台设备执行telnet NAS的IP 3000如果显示连接被拒绝或超时基本就是DSM防火墙拦截了。打开防火墙设置确认放行了3000和2222。第四层如果是从外网或者跨网段访问还要检查路由器或上级防火墙有没有做端口转发。这一层跟Gitea本身毫无关系纯网络环境问题。很多人在内网里访问正常一换网络就失败原因基本都在NAT层面。这套排查顺序的价值在于先底层后上层先本地后网络。直接去重启容器是最低效的做法因为很多时候容器根本没出问题。5.2 容器内时间不同步HTTPS证书验证莫名其妙的失败有一个坑我印象很深某天开始HTTPS推送开始随机报certificate has expired可证书明明刚续签过。排查了很久最后发现是容器内时间和宿主机差了快一天。原因是创建容器时没有设置时区相关的环境变量容器默认使用UTC时间如果宿主机本身的NTP同步又不够及时两者之间的时间差就会越来越大。HTTPS的TLS握手是强校验客户端和服务器时间戳的时间错乱时证书在服务器视角“还没到有效期”客户端就会判定证书无效。解决方法是创建容器时加两个参数-e TZAsia/Shanghai \ -v /etc/localtime:/etc/localtime:ro把宿主机的时区文件挂进去再设置环境变量容器内时间和宿主机一致。然后重启容器sudo docker restart gitea重启后进容器确认时间sudo docker exec -it gitea date如果时间还不对回头检查群晖系统本身的时间同步设置。这个坑比较隐蔽因为它不是每次都报错而是间歇性出现特别容易把人往证书配置方向带偏。我现在每过一段时间会顺手看一眼容器时间算是那次踩坑养成的新习惯。5.3 push正常但pull需要密码SSH公钥没被使用还有一种情况很迷惑push能成功pull却一直要求输入密码。遇到这个先执行git remote -v看看实际的remote地址是什么。很多时候问题根源在于仓库是从HTTP clone下来的remote地址里还带着HTTP链接而push时之所以能用SSH是因为你在另一个目录里重新设置了remote。如果remote地址确实已经是SSH格式再看Gitea账号下有没有添加这台设备的公钥。一台设备一个公钥这是基本原则。添加公钥后记得通知Git不要缓存错误的凭据git config --global credential.helper 还有一种相对隐蔽的场景Gitea初始化配置里的SSH端口是默认的22但你实际映射的是2222。这时Gitea生成SSH clone地址时会漏掉端口或生成githost:owner/repo.git这种格式Git客户端会默认走22端口连接被拒后自动回退到密码认证表现起来就是“要密码”。解决办法就是在管理面板里把SSH端口改成2222重新复制clone地址。5.4 大文件、仓库膨胀与备份策略Git仓库有个天然的问题只增不改历史记录会越来越大。如果项目里有人不小心提交了一个几百MB的压缩包整个仓库体积会瞬间膨胀克隆速度直接崩。Gitea默认支持Git LFS也就是大文件存储。需要处理大文件时在仓库根目录创建.gitattributes文件*.zip filterlfs difflfs mergelfs -text *.psd filterlfs difflfs mergelfs -text然后提交这个文件后续再添加这类文件就会走LFS存储。当然NAS的硬盘空间也不是无限的LFS对象同样要占用存储只是避免了每个克隆者都要完整拉取大文件的问题。备份策略上Gitea数据都在/volume1/docker/gitea/data这个卷里备份其实就是打包这个目录。我写了一个简单的脚本配合群晖的计划任务定期执行#!/bin/bash # Gitea 数据卷备份脚本 BACKUP_DIR/volume1/docker/gitea/backup tar -czf $BACKUP_DIR/gitea-$(date %F).tar.gz -C /volume1/docker/gitea data # 只保留最近 7 份备份 find $BACKUP_DIR -name gitea-*.tar.gz -mtime 7 -delete在“控制面板 - 任务计划”里新建一个计划任务选择“用户自定义脚本”执行时间可以设在凌晨执行用户选root。脚本每跑一次就会生成一个带日期的完整备份包。恢复时也很朴素把备份包解压回/volume1/docker/gitea目录重建容器命令保持不变所有仓库、用户、配置都会原样回来。如果群晖本身开了快照功能再叠加这个脚本安全性就更稳了。6. 把Gitea纳入日常用户管理、仓库策略与多设备协同6.1 多设备密钥管理不同电脑用不同key不用反复复制账号密码当你有台式机、笔记本、甚至临时借用别人的电脑时密钥管理就变得重要了。正确做法是给每台设备生成独立的密钥对而不是把同一份私钥复制到所有设备上。这样任何一台设备出问题比如丢了、坏人可能拿到都可以单独在Gitea里删掉对应公钥其他设备不受影响。每台设备上的流程都一样ssh-keygen -t ed25519生成密钥把id_ed25519.pub内容粘到Gitea用户设置的SSH密钥列表里最后ssh -T -p 2222 gitNAS地址验证。给公钥备注时写清楚设备和用途比如“笔记本-2024”“台式机-工作”管理时一眼就能识别。一个容易忽略的点是私钥文件的权限。Linux和macOS下如果~/.ssh/id_ed25519权限太宽松SSH客户端会拒绝使用这把密钥报“Permissions too open”之类错误。执行一次chmod 600 ~/.ssh/id_ed25519把私钥权限收紧这个问题就没了。6.2 仓库与团队权限设置私有库、只读协作、组织管理Gitea的权限模型比大多数人想象中完善。仓库可见性分成Public、Internal、Private三档。个人仓库我一般直接Private只有明确添加了权限的协作者能看到。如果给朋友或同事开一个小项目可以用组织来管理。创建一个组织然后把成员加进组织下的Team。Team支持Owner、Write、Read等权限级别Owner可以管理整个组织Write可以推送代码Read只能拉取。这样分配权限比把每个人加到NAS系统用户组里安全得多也精细得多。分支保护是团队协作里的一个实用功能。进入仓库“设置 - 分支”选择主干分支可以开启“禁止直接推送”“要求合并请求”“封禁强推”等规则。小团队可能觉得这些规则啰嗦但只要你经历过一次别人直接往master推了个坏改动回头看分支保护就觉得很值。Webhook也值得一提。Gitea支持HTTP Webhook可以把push事件、PR事件推送给你自己的通知渠道比如群机器人或自建接口。这样别人推了代码你能第一时间知道不需要每隔几分钟刷新一次仓库页面。6.3 让NAS上的项目可持续维护日志、更新、迁移Gitea部署好以后不是一劳永逸的容器需要更新日志需要关注万一换NAS也要能迁走。看日志是最基本的操作。Gitea把运行日志都打到容器里用sudo docker logs -f gitea就能实时跟踪。遇到Web界面打不开、推送异常、认证失败之类的问题日志里的[ERROR]行往往直接给出原因。我遇到过一次推送超时日志里显示数据库锁等待超时才知道是SQLite在高频并发下的一个性能瓶颈换成低并发场景就没事了。升级Gitea也不难。先执行备份脚本然后拉新版本镜像删除旧容器数据卷还在用原命令重新创建容器指向同一个/data卷启动后会自动完成数据库迁移。升级前一定要先看版本发布说明跳过太多大版本可能导致数据库升级链路异常稳妥的做法是一个版本一个版本地升别直接跨好几个大版本。换NAS时Gitea的迁移几乎是无痛的。把data卷打包的文件拷到新NAS的相同路径按第3.2节的命令重新创建容器指向这个数据卷启动后所有仓库、用户、SSH密钥、配置全都在。因为所有状态都在/data里容器本身是无状态的这是当初选Gitea时最满意的一点。最后分享一个小技巧。Gitea的配置集中在/volume1/docker/gitea/data/gitea/conf/app.ini这个文件里大部分Web界面上的设置最终都会写入这里。如果你对某个设置项不确定可以先备份这个文件然后手动改一行试试。改完重启容器生效得很快。这一招在排查SSH端口、基础URL这类问题时特别管用——直接在配置文件里看当前值比在Web界面上翻半天菜单清晰多了。我自己从开始折腾到现在Gitea一直稳稳跑着没出过大幺蛾子。这套组合的可靠程度确实是出乎我意料的。