前阵子帮一个小团队理代码托管的事情预算几乎为零云端私有仓库按人头收费算下来一年小几千还不算上拉代码时那点带宽的憋屈。最后我把 Gitea 装在了他们那台闲置的 Windows 服务器上从下载到跑通前后不到四十分钟。这篇就把 Gitea 在 Windows 平台的安装过程和后续踩过的坑完整记下来顺带把日常最常用的几个动作讲清楚。如果你手上只有一台 Windows 机器又想给自己或者小团队搭一个能私有托管的 Git 服务那这篇基本能让你照着走完。需要说明的是Windows 不是 Gitea 最顺手的宿主环境很多地方需要手动补位但完全能跑而且跑得还挺稳。1. 为什么我把 Gitea 装在了 Windows 机器上1.1 小团队自建代码托管到底图什么先聊动机动机不清楚后面做选择就容易摇摆。小团队或者个人折腾自建 Git 服务绝大多数跑不出三个诉求。第一是数据留在自己手里代码不往第三方服务器上放这一条在接外包、做内部系统的时候特别硬甲方合同里经常直接写明源码不得上传公有平台。第二是成本云端私有仓库按席位收费五个人和十五个人是两个价自建是一次性投入之后只花电费和硬盘钱。第三是内网速度公司内网千兆环境下克隆一个几百兆的仓库可能就十几秒走公网得几分钟日常提交推送的体感差距非常明显。还有个容易被忽略的点可定制性。自建之后 Webhook、CI、权限模型、登录对接这些都能自己说了算不用担心平台哪天改了策略或者改了免费额度。小团队真正开始用起来往往就是被某次平台改规则逼的。1.2 在几个候选方案里为什么落到 Gitea市面上能自建 git 服务的东西不止一个我大概理了一下对比最后落到 Gitea 的原因很直接它是用 Go 写的编译出来就是一个单文件可执行程序官方直接提供 Windows 的 amd64 二进制双击或者注册成服务就能跑不需要装运行时、不需要配环境变量、不需要编译。这一点在 Windows 上尤其值钱。方案资源占用Windows 友好度部署难度适合场景Gitea低空闲约 100-200MB 内存官方提供 Windows 二进制低个人、十人以内小团队GitLab CE高官方建议 4GB 内存起步不原生支持需要容器或虚拟机高中型团队、需要完整 CI裸 Git 文件共享极低能用但体验差中两三个人、纯备份其他自建面板类中等依赖运行时环境中看具体实现另一个关键点是 Gitea 的功能边界刚好合适。仓库管理、组织与团队、Issue、Pull Request、Webhook、包管理、Actions该有的都有但它不会像 GitLab 那样把一整套运维复杂度塞给你。装了之后基本不用怎么管这一点对于没有专职运维的小团队来说是决定性的。1.3 Windows 当宿主机的利与弊必须坦诚说清楚Windows 跑 Gitea 有几个天然的别扭地方。一是服务管理方式和 Linux 不一样没有 systemd得靠 NSSM 或者 WinSW 这类工具把它包成 Windows 服务否则关掉远程桌面进程就没了。二是路径分隔符、文件权限模型都不同配置里写路径要格外小心。三是 SSH 的处理Linux 上本来就是 OpenSSH 的地盘Windows 上要么用系统自带的 OpenSSH Server要么用 Gitea 内置的 SSH 服务二选一还得小心端口冲突。好处也很实在。很多中小公司的 IT 资产就是 Windows Server运维习惯、备份策略、监控工具全是围绕 Windows 建的硬上一个 Linux 反而增加维护成本。而且 Gitea 官方明确提供 Windows 二进制并且长期维护说明这条路是被支持的不是野路子。我实际跑下来除了首次配置要多花点心思日常使用和 Linux 上没什么差别。提示如果你的机器同时承担别的业务比如当文件服务器或者跑着数据库务必先把端口和磁盘 IO 规划清楚Gitea 本身很轻但仓库多了之后磁盘随机读会比较频繁。2. 安装前的环境盘点与方案选型2.1 硬件与系统版本的下限Gitea 对硬件的要求低到有点反常识。官方给的参考是 2 核 CPU、1GB 内存能支撑十几个人的小团队我实际在 2 核 2G 的虚拟机上跑过十几个人日常提交推送完全没压力。内存方面空载大概占 100 到 200MB随着并发请求和仓库数量上升会涨给到 2GB 比较从容。磁盘才是真正的大头仓库本身加上 Git 的对象压缩通常比源文件目录大 1.5 到 3 倍如果开了 LFS 存大文件那就要单独按业务量估算了。系统版本上Windows Server 2012 R2 及以上、Windows 10 及以上都能跑。这里有个坑要提前说老版本的 Windows Server 上 PowerShell 版本偏低某些脚本语法不兼容我建议至少在 Server 2016 或 Win10 1809 以上操作省得后面为了一个命令语法折腾半天。另外确认一下系统架构是 64 位官方只提供 amd64 的 Windows 包也有 arm64但桌面场景用不上。2.2 数据库怎么选别一上来就上 MySQL这是新手最容易纠结的地方。Gitea 支持 SQLite、MySQL、PostgreSQL 三种。我的建议很明确十人以内、单机部署直接用 SQLite不要犹豫。数据库优点缺点建议场景SQLite零配置、单文件、备份就是复制文件高并发写入会锁表个人、十人以内小团队MySQL生态成熟、运维熟悉需要单独安装配置、字符集容易踩坑已有 MySQL 环境、二十人以上PostgreSQL功能强、并发好安装配置相对繁琐对数据一致性要求高的团队SQLite 的写入锁在几十个人同时 push 的极端场景下确实会成为瓶颈但小团队的日常操作密度远达不到那个量级。等真的到了瓶颈再迁移数据库也不迟Gitea 官方提供了gitea dump和迁移工具路径是通的。前期把复杂度降下来比什么都重要。如果你确实要用 MySQL有两条硬性要求必须满足字符集必须是utf8mb4排序规则全库统一推荐utf8mb4_general_ci表引擎必须是 InnoDB行格式推荐 DYNAMIC。字符集不统一会导致中文仓库名、中文 Issue 标题变成乱码而且这种问题往往在用了几个月之后才暴露修起来很痛苦。2.3 目录、端口、账号的事先规划这一步很多人跳过然后装到一半发现路径里有空格、端口被占用、权限不够。花五分钟规划能省两小时排查。规划项推荐值说明安装目录D:\gitea\不要放在 C 盘用户目录不要有中文和空格数据目录D:\gitea\data\存数据库文件、附件、头像、索引仓库目录D:\gitea\repos\存所有 Git 裸仓库日志目录D:\gitea\log\应用日志和访问日志自定义目录D:\gitea\custom\配置文件、模板覆盖、自定义样式HTTP 端口3000避开 80方便后续加反向代理SSH 端口2222 或 22视系统是否已占用 22 端口而定服务运行账号本地系统 或 专用账号必须有安装目录的读写权限路径里的空格是个隐形杀手。它倒不至于让 Gitea 起不来但会在某些 Git 钩子、脚本调用、Windows 服务参数解析的时候出问题而且是偶发的排查起来极其费劲。中文路径同理编码问题会在日志和 Webhook 里随机冒出来。老老实实用D:\gitea这种最朴素的路径。提示如果磁盘是机械盘并且仓库数量超过几十个建议把repos目录单独挂一块盘或者放 SSD 上Gitea 展示仓库列表时会扫描目录机械盘上首次加载会明显卡顿。3. 手把手安装从下载到服务化3.1 下载二进制与摆放目录先去 Gitea 官网的下载页选择 Windows 版本的 amd64 二进制文件名形如gitea-1.22.x-windows-4.0-amd64.exe。下载下来之后把它重命名为gitea.exe然后放到D:\gitea\下面。重命名这一步不是必须的但强烈建议做因为后面写服务参数、写脚本的时候一个纯粹的gitea.exe比带一串版本号的文件名要好写太多。目录结构大致长这样D:\gitea\ gitea.exe custom\ conf\ app.ini (首次运行后生成) data\ repos\ log\ tmp\custom、data、repos、log、tmp这几个目录不用你手动建Gitea 首次启动时会自己创建。但如果你打算用专用账号跑服务最好提前建好并给账号授权避免服务启动时因为权限不足静默失败。3.2 先在命令行前台跑一遍做冒烟测试我最不建议的做法就是一上来就注册成服务然后盲测。先用命令行前台跑一次看输出有没有报错这样出问题能立刻看到原因。打开 PowerShell 或者 CMD切到安装目录cd /d D:\gitea gitea.exe web如果一切正常会看到它开始输出日志然后停留在监听状态。这时候浏览器打开http://localhost:3000应该会看到首次安装的配置向导页面。看到这个页面就说明二进制没问题、目录权限没问题、端口没被占用可以往下走了。测试完按Ctrl C停掉或者直接关掉窗口。这一步的意义在于把程序本身能不能跑和服务配置对不对两个问题分开验证后面出问题的时候你就知道该往哪个方向查。提示如果这一步就报端口占用用netstat -ano | findstr :3000找出占用进程的 PID再tasklist | findstr PID看是哪个程序处理掉再继续。3.3 用 NSSM 注册成 Windows 服务Windows 上没有 systemd把程序变成后台服务最通用的工具是 NSSM另一个选择是 WinSW。两者思路一样我用 NSSM 举例因为它的图形界面比较直观。下载 NSSM 后解压在里面找到你系统架构对应的nssm.exe用管理员权限的 CMD 执行nssm install Gitea这会弹出配置窗口。三个地方必须填对PathD:\gitea\gitea.exeStartup directoryD:\gitea这一项很多人漏掉导致服务找不到custom\conf\app.iniArgumentsweb然后切到I/O标签页把 stdout 和 stderr 重定向到日志文件比如D:\gitea\log\service-stdout.log和D:\gitea\log\service-stderr.log。这一步非常关键因为服务模式启动失败时你看不到任何界面提示只能靠日志。最后在Exit actions标签页把重启策略设为自动重启延迟 5 秒。Gitea 偶尔会因为磁盘满、系统更新等原因异常退出自动重启能避免半夜服务挂掉没人管。配置完成后启动服务nssm start Gitea再用nssm status Gitea确认状态是SERVICE_RUNNING。如果你更倾向于纯命令行的方式Gitea 官方文档里也给了基于sc create的写法但我不太推荐原因是sc create没法很好地指定工作目录也不能自动重启后期维护会麻烦。3.4 首次 Web 安装向导逐项填服务起来之后浏览器访问http://你的IP:3000会进入初始化配置页。这里有几个字段要留意。数据库类型选 SQLite3数据库文件路径保持默认的相对路径即可Gitea 会相对于工作目录解析最终落在data\gitea.db。应用名称随便取选个团队成员看得懂的。仓库根目录默认data/gitea-repositories我建议改成D:/gitea/repos把代码数据和数据库文件分开方便单独做备份和迁移。服务名称和域名这块最重要。应用 URL必须填成用户实际访问的地址比如http://192.168.1.50:3000/不能填localhost否则页面的静态资源、Webhook 回调地址、克隆用的 URL 全都会是 localhost别人访问就是一堆 404。管理员的第一个账号会自动成为系统管理员用户名别用admin这种太常见的密码至少 8 位并且要包含大小写和数字。管理员邮箱填真实可用的后续找回密码、接收系统通知都要用。下面的可选设置里禁止用户自助注册建议勾上。内网环境放开注册等于谁都能建账号虽然默认新建用户权限不高但没必要给自己留隐患。如果确实需要多人注册打开注册但强制邮箱验证并且配合邮件配置。填完点安装等十几秒到一分钟SQLite 建表稍微慢一点页面跳转到登录界面就算成功了。4. app.ini 里真正需要改的参数4.1 必须确认的几项Web 向导生成的配置落在D:\gitea\custom\conf\app.ini。这个文件是 Gitea 的全部配置中枢改完需要重启服务生效。我列出实际使用中必须确认的几项[server] PROTOCOL http DOMAIN 192.168.1.50 HTTP_PORT 3000 ROOT_URL http://192.168.1.50:3000/ DISABLE_SSH false START_SSH_SERVER true SSH_PORT 2222 LFS_START_SERVER true [repository] ROOT D:/gitea/repos [database] DB_TYPE sqlite3 PATH D:/gitea/data/gitea.db [service] DISABLE_REGISTRATION true [time] FORMAT 2006-01-02 15:04:05 TIME_ZONE Asia/ShanghaiROOT_URL是重灾区。它不光影响页面渲染还影响 Git 命令行输出的克隆地址、Webhook 的回调、OAuth 的重定向。只要用户是通过 IP 或域名访问的这里就必须写那个 IP 或域名。我见过太多人装完之后发现头像加载不出来、样式全丢最后查出来就是这里填了localhost。时间配置也顺手改掉默认是 UTC提交记录的时间会比本地时间早八小时看起来非常别扭。TIME_ZONE填Asia/Shanghai或者直接LOCAL。4.2 SSH 和 LFS 的处理方式Windows 上 SSH 有两条路。第一条是用 Gitea 内置的 SSH 服务也就是上面配置里的START_SSH_SERVER true加上SSH_PORT 2222。这种方式的好处是完全自包含不依赖 Windows 的 OpenSSH Server 组件克隆地址会变成ssh://git192.168.1.50:2222/user/repo.git这种形式。第二条是关闭内置服务用系统自带的 OpenSSH端口走 22克隆地址是标准的githost:user/repo.git形式看起来更清爽。我倾向于用内置的原因是 Windows 的 OpenSSH Server 在 Server 版本上未必默认安装装了之后还有授权公钥的管理问题多一个环节就多一类故障。内置服务的代价就是克隆地址里带端口号用户第一次配的时候要稍微注意一下。LFS 如果不用大文件可以直接关掉但生成二进制产物或者美术资源的团队建议开。开启后建议显式指定 LFS 存储路径避免和仓库目录混在一起[lfs] PATH D:/gitea/data/lfs4.3 邮件通知与失败重试邮件这块很多内网部署直接跳过但只要有 Issue、PR、密码找回这类需求没邮件体验会差很多。配 SMTP 的时候注意Windows 服务器如果要发外网邮件得确认出站 25 或 587 端口没有被防火墙挡掉这个坑很常见。如果公司有内部邮件中继优先用中继。[mailer] ENABLED true PROTOCOL smtp SMTP_ADDR smtp.example.com SMTP_PORT 587 FROM giteaexample.com USER giteaexample.com PASSWD 你的授权码顺带提一下[cron]段里的仓库健康检查和垃圾回收任务。默认是关的仓库多了之后建议打开让它在凌晨跑把散落的 Git 对象回收掉能省不少磁盘。提示改完 app.ini 一定要重启服务再验证。Gitea 不会热加载配置很多人改完刷新页面没变化以为配置写错了其实就是没重启。5. 日常使用从克隆到协作5.1 配置 SSH 公钥与克隆在 Windows 客户端上前提是装了 Git for Windows它自带 OpenSSH 客户端。生成密钥ssh-keygen -t ed25519 -C your_emailexample.com一路回车默认生成在C:\Users\你的用户名\.ssh\下面公钥是id_ed25519.pub。用记事本打开把内容整段复制粘贴到 Gitea 网页右上角头像 - 设置 - SSH/GPG 密钥 - 增加密钥里。如果你的 Gitea 用的是内置 SSH 且端口是 2222需要在C:\Users\你的用户名\.ssh\config里加一段Host gitea HostName 192.168.1.50 Port 2222 User git IdentityFile ~/.ssh/id_ed25519配好之后克隆就简单了git clone gitea:yourname/yourrepo.git用Host别名的好处是不用每次都写完整地址和端口而且后面换 IP 只改一个地方。我第一次搞这个的时候没写 config直接ssh://gitip:2222/repo.git也能用但命令长得让人不想敲。5.2 HTTPS 方式与凭据管理有些环境不允许开 SSH 端口那就走 HTTPS。克隆地址形如http://192.168.1.50:3000/yourname/yourrepo.git。第一次推送会提示输入用户名密码这里有个坑Gitea 默认不接受账号密码登录 Git需要在用户设置里生成一个访问令牌用它当密码。生成路径是 设置 - 应用 - 生成令牌勾选仓库读写权限。生成后那串字符只显示一次务必保存。然后在 Windows 的凭据管理器里把它存下来之后就不用反复输入了。用 Git 命令行的可以执行git config --global credential.helper manager这样 Windows 会弹出凭据管理器接管比每次手输舒服得多。5.3 组织、团队与权限模型Gitea 的权限模型是三层用户、组织、团队。用户可以建自己的仓库组织是一组用户和仓库的集合团队则是组织内部的权限分组可以分别设置对哪些仓库有读、写、管理权限。这个模型和主流的代码托管平台基本一致上手没有成本。小团队的实际用法通常是建一个组织代表公司或项目组组织下建仓库然后建两个团队一个是开发者团队所有仓库读写一个是访客团队指定仓库只读。把外包或者测试人员放进访客团队权限边界就很清楚。Issue 和 Pull Request 的流程和常见的平台一样创建分支、推送、开 PR、评审、合并。合并方式有合并提交、压缩合并、变基合并三种可选团队约定好一种就行我建议统一用压缩合并提交历史干净回滚的时候也好定位。5.4 接一个 Actions 跑自动构建Gitea 从 1.19 开始内置了 Actions功能上能覆盖大部分常见的 CI 需求。要在 Windows 宿主上跑起来需要额外跑一个 runner也就是act_runner。它是独立进程和 Gitea 主服务分开部署可以装在另一台机器上也可以同一台机器上跑。流程大致是在 Gitea 管理后台生成 runner 的注册令牌在 runner 机器上执行act_runner register填上 Gitea 地址和令牌然后act_runner daemon启动。之后在仓库里放.gitea/workflows/目录下的 YAML 文件就能触发。说实话如果你只是想跑个单元测试加打包用 runner 完全够。但如果你的构建流程复杂、需要大量缓存和多阶段并行那就得评估一下 runner 的资源消耗了毕竟 Windows 上的容器支持不如 Linux 那么顺。6. 备份、升级与迁移这三件事6.1 用 dump 命令做全量备份这是自建服务里最不能省的一环。Gitea 提供了dump命令能一次性把自己的数据库、仓库、配置、附件全打包。cd /d D:\gitea gitea.exe dump -c custom\conf\app.ini -f D:\backup\gitea-dump.zip生成的 zip 里包含了可以还原所需的全部内容。备份策略上我建议每周全量 dump 一次落到另一块物理盘或者网络存储上同时每天用文件级备份工具把repos和data目录增量同步一次。两套并行dump 保证可还原文件同步保证恢复时间短。提示dump 过程会锁住数据库SQLite 尤其明显最好安排在深夜或者使用低峰期并在执行前先停掉服务避免备份出来的数据不一致。6.2 升级的正确姿势Gitea 的升级比想象中简单因为它是单二进制。步骤是先备份再停服务替换 exe启动服务。nssm stop Gitea copy D:\gitea\gitea.exe D:\gitea\gitea.exe.bak copy D:\download\新版本.exe D:\gitea\gitea.exe nssm start Gitea替换之后首次启动会自动执行数据库迁移日志里会打印迁移进度这个过程可能持续几十秒到几分钟取决于数据量期间页面访问会报错属正常现象。等日志里出现启动完成的字样再访问。版本跨度上建议一步一步升不要从 1.18 直接跳到 1.22。中间的大版本可能包含需要按顺序执行的迁移逻辑跳着升容易出问题。另外主版本升级前一定先看官方的发布说明里面会写明破坏性变更比如某一个配置项改了名字或者默认值变了。6.3 迁移到新机器迁移其实就等于备份 还原。新机器上先装好同样版本甚至更新一点的 Gitea把安装目录准备好然后用备份包还原gitea.exe restore -c custom\conf\app.ini D:\backup\gitea-dump.zip还原之后的第二件要紧事是改ROOT_URL和DOMAIN因为新机器的 IP 大概率变了。这一步漏了用户访问到的还是旧地址表现就是页面能开但克隆不了、头像不显示。还有一件事容易被忘如果你用了内置 SSH端口可能在新机器上和别的服务冲突记得检查。7. 常见问题与排查速查表7.1 服务起不来或者起来就退出这类问题的排查顺序是固定的先看 NSSM 重定向出来的 stderr 日志再看D:\gitea\log\下的应用日志最后看 Windows 事件查看器的应用程序日志。最常见的三个原因工作目录没设对导致找不到custom\conf\app.ini运行账号对安装目录没有写权限Gitea 启动时要写日志和临时文件端口被占用。Windows 上查端口占用的命令前面提过netstat -ano | findstr :3000配合tasklist基本能定位到具体程序。7.2 页面能打开但样式丢失、接口报错九成是ROOT_URL配置和实际访问地址不一致。用 IP 访问的配置里就写 IP用域名访问的配置里就写域名加了反向代理的要写代理之后的对外地址。改完重启服务。第二个可能是反向代理的请求头没透传。如果前面挂了 Nginx必须把Host和X-Forwarded-Proto这类头带过去否则 Gitea 拼接出来的链接协议会是 http浏览器按 https 页面加载资源就会被拦。7.3 Git 操作相关的报错这块问题五花八门我挑几个高频的整理成表。报错现象可能原因处理方式Permission denied (publickey)公钥没粘贴或粘错重新复制.pub文件内容注意不要带换行Connection refusedSSH 端口未放行或被占用检查START_SSH_SERVER、防火墙规则和端口占用413 Request Entity Too Large反向代理请求体限制太小调大代理的 body 大小限制到 100M 以上repository not found用户对仓库无权限或仓库名拼错检查团队成员权限注意大小写推送大文件超时未启用 LFS 或超时设置过短开启 LFS 或调大[server]下的超时参数提交时间显示不对时区未配置修改[time]段的TIME_ZONE还有一个不那么常见但很烦人的问题Windows 上某些杀毒软件会实时扫描 Git 仓库目录导致克隆和提交时快时慢偶尔还会因为文件被锁定而失败。解决办法是把D:\gitea\repos目录加进杀软的排除列表这个改动带来的性能提升通常很明显。7.4 内存和磁盘慢慢涨起来跑几个月之后发现磁盘涨得快先别急着扩容。检查三个地方仓库里的历史大对象、data\avatars和data\attachments里的附件、以及日志目录。日志默认是滚动切割的但如果滚动配置没生效log目录能涨到几个 G看下[log]段的配置。仓库层面的清理靠后台的仓库健康检查任务它会做 Git 的 gc把松散对象打包并清理不可达对象。这个任务默认不跑得在配置里开启。开之前记得先备份虽然它本身是安全的但涉及历史重写相关的操作留一手总没错。8. 我实际用下来的一些体会先说一个最容易被低估的点Windows 上跑 Gitea真正的难点从来不在 Gitea 本身而在 Windows 的服务管理、权限和路径处理上。程序本身解压就能跑配置项也就那么几个但把它稳稳当当地变成一个开机自启、挂了能自己爬起来、出问题有日志可查的服务需要你多花点心思。我建议哪怕只是个人用也老老实实用 NSSM 包成服务并且配好日志重定向不然哪天你关了远程桌面发现服务没了又要从头排查一遍。再说数据库。我见过不少人为了显得专业一上来就上 MySQL结果装到一半卡在字符集和权限上折腾一整天。而同样的场景用 SQLite 十分钟就搞定了之后跑一年也没出过问题。工具选型和业务规模匹配才是对的不是越复杂越好。等真的撑不住了再迁移Gitea 提供的迁移路径是完整的。备份这件事我想格外强调一下。自建服务最大的风险不是被攻击而是你自己忘了备份或者备份了但从没验证过能不能还原。我现在的习惯是每季度做一次还原演练在一台闲置机器上把备份包恢复起来确认数据完整、服务能起、配置正确。这个动作每次花不到半小时但能在真正出事的时候救你一命。最后分享一个小技巧如果你有多台机器需要同时从内网和外部访问 Gitea可以把ROOT_URL和DOMAIN都设成域名而不是 IP然后在各机器的 hosts 文件里把这个域名指向对应的地址。这样换 IP、换网络环境的时候配置完全不用动改 hosts 就行。这个做法看起来土但在没有正式 DNS 的小环境里非常省事。