Windows 服务器上部署 Gitea 全面指南

Windows 服务器上部署 Gitea 全面指南

适用场景:在企业或个人内网的 Windows Server (建议 2019/2022) 上快速搭建一个轻量、易维护的自托管 Git 代码托管平台。本文覆盖从下载到上线、HTTPS、数据库选择、备份升级与排错调优。你可以按章节逐步执行。后续你的反馈将帮助我迭代本文。

目录

  1. 前置条件与规划
  2. 下载与目录布局
  3. 初次运行与基础初始化
  4. 注册为 Windows 服务(开机自启)
  5. 数据库选择与配置详解(SQLite / MySQL / PostgreSQL / MSSQL)
  6. 关键配置文件 app.ini 解读
  7. 使用 IIS 构建反向代理与启用 HTTPS
  8. 用户、组织与权限管理要点
  9. 备份、恢复与升级策略
  10. 性能与安全加固建议
  11. 常见问题与排错 (FAQ)
  12. 参考与后续改进

前置条件与规划

项目 推荐 说明
操作系统 Windows Server 2019/2022 更长支持周期,IIS/PowerShell 较新
权限 管理员账号 需要创建目录、注册服务、安装 IIS 组件
Git 客户端 已安装最新 Git for Windows 用于本地或服务器端仓库操作
域名 (可选) git.example.com 方便外部或内网统一访问
证书 有效 SSL 证书 (PFX) 保障 HTTPS 安全
数据库 视并发与规模选择 默认内置 SQLite;中长期建议外置 DB

容量规划提示:

  • 小团队 (<30 用户) + 中等仓库:SQLite 或 MySQL/PostgreSQL 均可。
  • 大团队或需要高并发:优先 PostgreSQL 或 MySQL;考虑单独磁盘挂载仓库存储。
  • 仓库与附件目录建议放入独立卷,如 D:\gitea-data 便于备份与迁移。

下载与目录布局

建议使用如下结构:

1
2
3
D:\gitea\bin\gitea.exe        # 主程序
D:\gitea\data\ # 数据(仓库、附件、索引等)
D:\gitea\log\ # 日志输出

下载方式(到官方发布页):

  1. 访问:https://dl.gitea.com 或 GitHub Releases https://github.com/go-gitea/gitea/releases
  2. 选择对应版本的 gitea-<version>-windows-amd64.exe 重命名为 gitea.exe
  3. gitea.exe 放入 D:\gitea\bin 目录。

PowerShell 快速下载示例(替换版本号):

1
2
3
$version = "1.25.2"  # 示例版本,请根据最新发布替换
New-Item -ItemType Directory -Force -Path D:\gitea\bin | Out-Null
Invoke-WebRequest -Uri "https://dl.gitea.com/gitea/$version/gitea-$version-windows-amd64.exe" -OutFile "D:\gitea\bin\gitea.exe"

创建数据与日志目录:

1
New-Item -ItemType Directory -Force -Path D:\gitea\data,D:\gitea\log | Out-Null

初次运行与基础初始化

首次运行使用内置服务器端口(默认 3000),先用 SQLite 完成图形化初始化:

1
2
3
4
5
cd D:\gitea\bin
# 若已重命名为 gitea.exe(推荐)
./gitea.exe web --port 3000 --work-path D:\gitea\data
# 若仍保留原下载文件名,可临时直接执行(示例):
# ./gitea-1.25.2-windows-4.0-amd64.exe web --port 3000 --work-path D:\gitea\data

浏览器访问 http://<服务器IP>:3000 进入初始化界面:

  • 数据库:可暂选 SQLite 自动生成。后续可迁移至外部数据库。
  • 站点标题 / 管理员账号:务必记录管理员密码。
  • 仓库根路径建议:D:/gitea/data/repositories
  • 日志路径:D:/gitea/log(若界面可配置)

初始化完成后将生成 D:\gitea\data\custom\conf\app.ini
停止临时前台进程(Ctrl + C),后续改为 Windows 服务运行。

初始化时报“没有 git 命令 / git not found”解决办法

出现此提示表示 Gitea 未能找到系统可执行的 git

常见原因:

  • 未安装 Git for Windows。
  • 已安装但其安装路径未加入系统环境变量 PATH(服务进程看不到)。
  • 使用服务方式运行而系统 PATH 修改后尚未重启服务或服务器。

处理步骤:

  1. 安装 Git(图形安装或使用 winget):
    1
    winget install --id Git.Git -e --source winget
    若无 winget,可到 https://git-scm.com 下载最新安装包,安装时勾选:
  • “Git LFS”(若需要大文件)
  • 行末转换选择 “Checkout as-is, commit as-is” 避免 CRLF 混乱。
  1. 验证安装:
    1
    2
    git --version
    where git
    典型路径:C:\Program Files\Git\cmd\git.exeC:\Program Files\Git\bin\git.exe
  2. 将路径加入系统 PATH(若未自动添加):
    1
    2
    $gitPath = 'C:\Program Files\Git\cmd'
    [Environment]::SetEnvironmentVariable('Path', $env:Path + ';' + $gitPath, 'Machine')
    注意:修改系统级 PATH 后,原有已打开的 PowerShell 或 CMD 窗口不会即时生效,必须关闭后重新打开新终端窗口。若 Gitea 已作为服务运行,也需要 Restart-Service gitea 让其新的环境变量生效;极少数情况下(服务使用本地系统账户且未刷新环境)可能需要一次注销或重启。
  3. app.ini 明确指定 Git 路径(可选,防止服务找不到):
    打开 D:\gitea\data\custom\conf\app.ini,添加或修改:
    1
    2
    [git]
    PATH = C:/Program Files/Git/bin/git.exe
  4. 重启 Gitea 服务:
    1
    Restart-Service gitea
  5. 再次访问初始化页面或(若已安装)在管理后台 -> 系统信息查看 Git 版本。

出现 FATAL:git not found: exec: "git": executable file not found in %PATH% 代表 Gitea 在启动阶段执行 git 子命令失败(与仅有 WARNING 不同,服务会直接退出)。除上述步骤外还需:

  • 确认已安装 64 位 Git 与 Gitea 架构一致(都为 amd64)。
  • 若 PATH 中含有 C:\Program Files\Git\cmd 仍失败,尝试在 app.ini 增加:
    1
    2
    [git]
    PATH = C:/Program Files/Git/cmd/git.exe
    或者使用 bin:C:/Program Files/Git/bin/git.exe,避免因 shim 重定向异常。
  • 使用诊断命令(前台):
    1
    2
    cd D:\gitea\bin
    .\gitea.exe doctor --check git --config D:\gitea\data\custom\conf\app.ini --work-path D:\gitea\data
    若显示 git 未找到,说明进程可见的 PATH 未包含 git;在当前窗口执行 echo $env:PATHwhere git 对比。
  • 若服务方式运行失败但前台正常:说明服务运行环境的 PATH 不一致;为 NSSM 可在 GUI 中“Environment”添加:PATH=C:\Program Files\Git\cmd;%PATH%;为 sc.exe 创建的服务则可改用 NSSM 或在注册表 HKLM\SYSTEM\CurrentControlSet\Services\Gitea 下添加 Environment(较复杂,推荐 NSSM)。
  • 避免放置在包含中文或空格的自定义路径(官方安装路径一般安全)。
  • 再次失败时附加前台完整启动输出与 Get-Content D:\gitea\log\gitea.log -Tail 100 给我做进一步分析。

快速验证当前会话是否已正确加载 PATH:

1
2
3
where git
git --version
[System.Environment]::GetEnvironmentVariable('Path','Process') | Select-String 'Git'

where git 无输出但系统 PATH 已改,说明当前终端仍是旧会话,重新打开即可。

如果仍失败:

  • 确认服务运行的账号(Services 中属性)是否对 C:\Program Files\Git 有读取权限。
  • 以前台方式测试:
    1
    2
    cd D:\gitea\bin
    ./gitea.exe web --work-path D:\gitea\data
    观察启动日志中是否打印 Git 路径错误。
  • 查看日志:Get-Content -Path D:\gitea\log\gitea.log -Tail 100 搜索 git 关键字。

完成后再继续下一章的服务注册或反向代理配置。

启动警告:SCRIPT_TYPE “bash” is not on the current PATH

警告含义:当前配置期望使用 bash 生成/执行仓库钩子脚本,但系统找不到 bash.exe(示例 WARNING)。不影响基本网页功能。
解决方案:

  1. 安装 Git for Windows 并确保 PATH 包含 C:\Program Files\Git\usr\binC:\Program Files\Git\bin,验证:
    1
    where bash
  2. 若纯 Windows 环境无需 bash:在 app.ini 中设置:
    1
    2
    [repository]
    SCRIPT_TYPE = batch
    然后 Restart-Service gitea
  3. 暂不使用自定义钩子可忽略该警告。
    前台验证是否消失:
    1
    2
    cd D:\gitea\bin
    ./gitea.exe web --work-path D:\gitea\data

注册为 Windows 服务(开机自启)

你的当前版本(1.25.2)不包含 service 子命令(gitea help 输出中没有)。因此无法用“内置安装”方式,需使用外部工具创建 Windows 服务。执行 ./gitea.exe service installmanager service install 报错即属正常——请改用下面两种方案之一。

使用 NSSM(推荐)

优点:易管理、可配置重启策略与日志重定向。
步骤:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1. 下载 NSSM(GitHub Release v2.25)并放置例如 C:\tools\nssm.exe
# 官方发行页: https://github.com/dkxce/NSSM/releases/tag/v2.25
# 64 位压缩包直链: https://github.com/dkxce/NSSM/releases/download/v2.25/nssm-2.25-64.zip
New-Item -ItemType Directory -Force -Path C:\tools | Out-Null
$zip = 'C:\tools\nssm.zip'
Invoke-WebRequest -Uri 'https://github.com/dkxce/NSSM/releases/download/v2.25/nssm-2.25-64.zip' -OutFile $zip
Expand-Archive -Path $zip -DestinationPath C:\tools\nssm -Force
Copy-Item C:\tools\nssm\win64\nssm.exe C:\tools\nssm.exe -Force
& C:\tools\nssm.exe --version
# (可选)加入系统 PATH 后需开新终端:
[Environment]::SetEnvironmentVariable('Path', $env:Path + ';C:\tools', 'Machine')
# where nssm
# 2. 安装服务
C:\tools\nssm.exe install Gitea "D:\gitea\bin\gitea.exe" web --work-path D:\gitea\data --config D:\gitea\data\custom\conf\app.ini
# 3. 设置工作目录与日志(可视化界面或命令行)
C:\tools\nssm.exe set Gitea AppDirectory D:\gitea\bin
C:\tools\nssm.exe set Gitea AppStdout D:\gitea\log\stdout.log
C:\tools\nssm.exe set Gitea AppStderr D:\gitea\log\stderr.log
# 4. 启动服务
Start-Service Gitea
Set-Service Gitea -StartupType Automatic

更新配置或 PATH 后:Restart-Service Gitea

升级与卸载

NSSM:Stop-Service Gitea -> 替换 gitea.exe -> Start-Service Gitea。卸载:C:\tools\nssm.exe remove Gitea confirm
sc.exe:

1
2
Stop-Service Gitea
sc.exe delete Gitea

然后重新创建。

环境变量及 PATH 更新

修改系统 PATH 或 Git 路径后:

1
Restart-Service Gitea

若仍未生效,重新打开管理终端或重启服务器。

服务启动失败排查(Cannot start service / StartServiceFailed)

常见原因:

  • 可执行路径或参数拼写错误(NSSM / sc.exe 的 binPath 不正确)。
  • 目录权限不足:服务账户(默认 LocalSystem)无权访问 D:\gitea\data 或日志目录。
  • 端口占用:3000 已被其他程序使用。
  • 配置文件语法错误:app.ini 中段名或键拼写错误导致启动直接退出。
  • 环境变量 PATH 未加载:找不到 git.exe 导致某些初始化失败(一般仅警告)。
  • SQLite 文件锁或数据库迁移异常。

排查步骤:

  1. 查看服务配置(sc.exe 安装场景):
    1
    sc.exe qc Gitea
    关注 BINARY_PATH_NAME 是否与实际路径一致。
  2. 若为 NSSM:打开 GUI 检查或命令:
    1
    C:\tools\nssm.exe edit Gitea
  3. 前台手动运行验证:
    1
    2
    cd D:\gitea\bin
    .\gitea.exe web --work-path D:\gitea\data --config D:\gitea\data\custom\conf\app.ini
    看终端输出的第一屏是否直接退出或报错。
  4. 查看日志(按你使用的方式):
    1
    2
    Get-Content D:\gitea\log\stdout.log -Tail 200 -ErrorAction SilentlyContinue
    Get-Content D:\gitea\log\gitea.log -Tail 200 -ErrorAction SilentlyContinue
  5. 检查端口占用:
    1
    netstat -ano | findstr :3000
    若已占用,修改 app.ini[server] HTTP_PORT 或停止冲突进程。
  6. 验证权限:
    1
    icacls D:\gitea\data
    确保有 SYSTEM 与需要的用户完全控制;缺失则:
    1
    icacls D:\gitea\data /grant SYSTEM:(OI)(CI)F
  7. 检查配置文件是否存在和可读:
    1
    Test-Path D:\gitea\data\custom\conf\app.ini
  8. 查询应用事件日志:
    1
    Get-WinEvent -LogName Application -MaxEvents 50 | Where-Object {$_.Message -like '*gitea*'} | Select-Object TimeCreated,Id,LevelDisplayName,Message

如果前台运行正常但服务仍失败:

  • NSSM 场景:确认 AppDirectory 与可执行文件目录一致;去除多余引号;参数不要包含非 ASCII 奇怪字符。
  • sc.exe 场景:重新创建服务时确保 binPath= 后有一个空格再跟引号,路径中不要使用正斜杠。
    1
    2
    sc.exe delete Gitea
    sc.exe create Gitea binPath= "D:\gitea\bin\gitea.exe web --work-path D:\gitea\data --config D:\gitea\data\custom\conf\app.ini" start= auto

收集信息后可在 FAQ 中补充具体错误模式;请将上述命令的关键输出发给我,我会继续分析。

数据库选择与配置详解

四种常见选择:SQLite / MySQL / PostgreSQL / MSSQL。

  • SQLite:零运维,单文件;并发高时性能下降。
  • MySQL:广泛使用,易维护;需调优 InnoDB 参数。
  • PostgreSQL:并发、复杂查询优,推荐中大型部署。
  • MSSQL:在已有 Microsoft 生态下整合方便。

切换至 MySQL 示例

创建数据库与用户:

1
2
3
4
CREATE DATABASE gitea CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'gitea'@'%' IDENTIFIED BY '强密码';
GRANT ALL PRIVILEGES ON gitea.* TO 'gitea'@'%';
FLUSH PRIVILEGES;

编辑 app.iniDATABASE 段:

1
2
3
4
5
6
7
8
[database]
DB_TYPE = mysql
HOST = 127.0.0.1:3306
NAME = gitea
USER = gitea
PASSWD = 强密码
SSL_MODE = disable
CHARSET = utf8mb4

重启服务:Restart-Service gitea

PostgreSQL 示例

1
2
3
CREATE DATABASE gitea WITH ENCODING 'UTF8';
CREATE USER gitea WITH PASSWORD '强密码';
GRANT ALL PRIVILEGES ON DATABASE gitea TO gitea;

app.ini

1
2
3
4
5
6
7
[database]
DB_TYPE = postgres
HOST = 127.0.0.1:5432
NAME = gitea
USER = gitea
PASSWD = 强密码
SSL_MODE = disable

MSSQL 示例

确保启用 TCP,使用 SQL Server Authentication。

1
2
3
4
5
6
[database]
DB_TYPE = mssql
HOST = 127.0.0.1:1433
NAME = gitea
USER = gitea
PASSWD = 强密码

关键配置文件 app.ini 解读

常见段落:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[server]
DOMAIN = git.example.com
PROTOCOL = http # 反向代理 HTTPS 时保持 http
ROOT_URL = https://git.example.com/
SSH_DOMAIN = git.example.com
HTTP_PORT = 3000
DISABLE_SSH = false
START_SSH_SERVER = false # Windows 下多数用外部 OpenSSH

[repository]
ROOT = D:/gitea/data/repositories

[log]
MODE = file
LEVEL = Info
ROOT_PATH = D:/gitea/log

[security]
INTERNAL_TOKEN = 自动生成 (勿泄露)
PASSWORD_HASH_ALGO = argon2
INSTALL_LOCK = true

调整后重启服务使其生效。

ROOT_URL 不匹配警告排查

警告内容示例:

1
2
Your ROOT_URL in app.ini is "http://localhost:3000/", it's unlikely matching the site you are visiting.
Mismatched ROOT_URL config causes wrong URL links for web UI/mail content/webhook notification/OAuth2 sign-in.

含义:当前访问站点的外部地址(浏览器实际 URL)与 app.ini[server]ROOT_URL 不一致。会导致:

  • 网页导航、头像、静态资源链接跳到错误主机或端口。
  • Webhook Payload 中的 URL 指向不可访问的内部地址。
  • 邮件通知内的链接 404 或跳回初始化端口 localhost:3000
  • OAuth2 / 单点登录回调 Redirect URI 校验失败(不匹配注册的 URL)。

常见错误配置场景:

错误值 实际访问 原因 影响
http://localhost:3000/ https://git.internal.local:8443/ 初始化使用默认未改 所有生成链接指向本地无法外部访问
http://服务器IP:3000/ https://域名:8443/ 后续加反向代理忘记更新 克隆 URL 混合端口,Webhook 错误
https://域名/ (少端口) https://域名:8443/ 使用非 443 自定义端口但未写端口 克隆显示 443,访问失败
https://域名:8443 (缺少尾部 /) https://域名:8443/ 少尾部斜杠 某些重定向拼接不正确(少斜杠)

正确配置示例(反向代理 + 自定义端口):

1
2
3
4
5
6
[server]
DOMAIN = git.internal.local
PROTOCOL = http # 仍保持 http,由 IIS 提供 TLS
ROOT_URL = https://git.internal.local:8443/
HTTP_PORT = 3000
SSH_DOMAIN = git.internal.local

要点:

  1. ROOT_URL 必须是用户实际访问的完整外部协议 + 主机名 + 端口(如果不是默认 80/443)。尾部保留 /
  2. 置于反向代理后,PROTOCOL 仍保持 http,不要改为 https(除非直接让 Gitea 监听 8443 并自己提供证书)。
  3. DOMAINSSH_DOMAIN 推荐与外部域名一致;否则 SSH 克隆 URL 可能与 Web 不一致。
  4. 仅使用 IP 访问时可以设为 ROOT_URL = http://192.168.1.10:8080/,但邮件与 OAuth 场景更建议域名;可在内部 DNS 或 hosts 文件映射。
  5. 端口从标准迁移到 8443/8080 后务必同步更新此值,否则克隆命令显示错误端口。

修改步骤:

  1. 编辑 D:\gitea\data\custom\conf\app.ini[server] 相关键。
  2. 保存后重启:
    1
    Restart-Service Gitea
  3. 刷新浏览器,访问首页与“克隆”按钮中显示的 HTTP URL 是否正确。
  4. 发送一个测试 Webhook(仓库设置 -> Webhooks -> Test delivery)观察 Payload URL。
  5. 若使用邮件:在管理员后台触发测试邮件,检查链接是否指向正确域名与端口。
  6. OAuth2(或外部登录)场景:确保第三方应用的 Redirect/Callback URI 与 ROOT_URL 前缀一致;常见格式:https://git.internal.local:8443/user/oauth2/github/callback

验证命令(快速确认当前值):

1
Select-String -Path D:\gitea\data\custom\conf\app.ini -Pattern 'ROOT_URL'

或在管理后台 -> “系统信息” 页面查看当前基础 URL。

常见坑 & 修复:

  • 修改 ROOT_URL 后未重启服务:旧 URL 仍缓存于内存;重启后才生效。
  • 代理后仍显示 3000 端口:未更新 ROOT_URL 或代理设置重写了 Host 头;确认 IIS 反代是否保留原 Host 并未强制回源主机名。
  • 访问强制跳转到 localhost:3000:说明仍有旧配置或多个 app.ini 副本;确认只编辑了 custom\conf\app.ini 而非模板。
  • 邮件模板仍旧:需清除队列或再次触发新邮件,旧邮件内容不会回写。

高级:如果代理层做了 URL 前缀(如 /gitea 子路径),则 ROOT_URL 必须包含完整路径:

1
ROOT_URL = https://git.internal.local:8443/gitea/

同时更新 IIS Rewrite 规则保留该前缀,避免资源 404。

FAQ 条目已追加(见第 11 章)。

使用 IIS 构建反向代理与启用 HTTPS

安装 IIS 必要组件

在“添加角色和功能”中勾选:

安装 URL Rewrite 与 ARR:

  1. 下载并安装:Application Request Routing (ARR) + URL Rewrite Module。
  2. 打开 IIS 管理器 -> 服务器节点 -> Application Request Routing Cache -> Server Proxy Settings 勾选“Enable proxy”。

获取与安装 URL Rewrite 与 ARR(离线安装指引)

【iisreset /restart 的具体影响与官方参考】
执行 iisreset /restart 会先停止后再启动 IIS Admin Service 及其依赖(包括 World Wide Web Publishing Service,进而终止所有当前应用池的工作进程 w3wp.exe),造成一个短暂的全站不可用窗口。主要影响:

  1. 所有当前 HTTP 连接被立即断开,正在处理的请求被终止(若使用 /noforce 则会等待超时)。
  2. InProc 会话状态与应用内存缓存(如 ASP.NET InProc、应用级缓存对象)全部丢失;使用独立 Session State Server/Redis 不受影响。
  3. 应用程序池中的启动预热(warmup)逻辑需重新执行;首次访问可能略慢。
  4. 自定义加载的模块、全局变量、动态编译内容会重新初始化。
  5. 日志(IIS 与站点应用日志)正常写入已缓冲内容后关闭文件句柄并重新建立。
  6. 若有长连接(WebSocket)全部断开,需要客户端自动重连。

生产环境注意:

  • 优先使用“回收应用程序池”或单独重启受影响站点,减少对其他站点的影响。
  • 避免在高峰时段执行;若必须,提前通知用户并缩短操作窗口。
  • 若仅修改 Rewrite 规则或 ARR 代理设置,通常通过回收对应应用池即可加载新配置。

常用相关命令:

1
2
3
4
5
6
iisreset /restart         # 停止后再启动
iisreset /noforce # 尝试正常关闭,超时后不强制杀进程
iisreset /status # 查看当前 IIS 服务状态
iisreset /stop # 停止 IIS 服务
iisreset /start # 启动 IIS 服务
iisreset /timeout:90 # 调整等待超时时间(秒)

/noforce 在超时后未完成停止,将保持原状并提示;此时需检查是否有卡住的工作进程(调试中的 w3wp 或阻塞 I/O)。

官方文档参考(建议收藏):

决策速览(再强调):

1
2
3
4
仅新增/修改 Rewrite/ARR 设置 -> 回收应用池
需释放全部内存状态或疑似模块未加载 -> iisreset /restart
高峰期 -> 延迟或仅回收受影响池
排查卡死 w3wp -> 先 /noforce ,失败再常规 /restart

在线安装可能受服务器无法访问外网或被策略阻断影响,建议提前下载离线 MSI 包。

  1. 官方下载页面(需浏览器访问):
  1. 在页面点击“Download”后选择与你系统匹配的架构(一般为 x64 / amd64)。
  2. 离线安装(双击 MSI):先安装 URL Rewrite,再安装 ARR(ARR 会依赖 Rewrite 与 Web Farm Framework 组件,缺失时会自动提示)。
  3. 静默安装(适合批量或脚本)示例(请先将 MSI 文件名替换为实际下载的名称并放在同一目录):
    1
    2
    3
    4
    5
    6
    # 进入存放 MSI 的目录
    cd C:\install\iis-ext
    # 静默安装 URL Rewrite
    msiexec /i rewrite_amd64_en-US.msi /qn /norestart
    # 静默安装 ARR(示例文件名,请与实际一致)
    msiexec /i requestRouter_amd64.msi /qn /norestart
  4. 可选:使用 PowerShell 直接下载(需确认最新文件名;若微软更新可能失效,失败则改为手动浏览器下载)。
    1
    2
    3
    4
    5
    New-Item -ItemType Directory -Force -Path C:\install\iis-ext | Out-Null
    $rewriteUrl = 'https://download.microsoft.com/download/D/D/9/DD9E4E6B-511B-4F2D-9B73-1F6262B42C04/rewrite_amd64_en-US.msi'
    $arrUrl = 'https://download.microsoft.com/download/5/1/F/51F682F7-16F0-4B75-BAF5-69BE3D0A88D8/requestRouter_amd64.msi'
    Invoke-WebRequest -Uri $rewriteUrl -OutFile C:\install\iis-ext\rewrite_amd64_en-US.msi
    Invoke-WebRequest -Uri $arrUrl -OutFile C:\install\iis-ext\requestRouter_amd64.msi
    若上述直链下载失败请改用官方页面手动获取;链接可能随版本调整。
  5. 安装后验证:
  • 打开 IIS 管理器,站点或服务器节点下应看到“URL Rewrite”。
  • 服务器节点功能视图中出现“Application Request Routing Cache”。
  • 在“Application Request Routing Cache” -> “Server Proxy Settings” 能进入设置页面且可勾选“Enable proxy”。
  1. 若功能未出现:
  • 确认是否在不同架构(x86)下安装到 64 位系统。
  • 重新运行 MSI,去掉静默参数观察错误提示。
  • 查看事件查看器应用日志或 C:\Windows\Temp 中 MSI 安装日志(搜索 rewriterequestRouter)。
  1. 更新 / 卸载:
  • 控制面板 -> 程序和功能 -> 选择 “IIS URL Rewrite Module” / “Microsoft Application Request Routing” 卸载或升级。
  • 升级前无需停止 IIS,安装程序会自动覆盖;完成后建议 iisreset
    1
    iisreset /restart
  1. 常见问题:
    问题 现象 解决
    缺少 Rewrite 功能 ARR 安装报依赖 先安装 URL Rewrite 模块再运行 ARR MSI
    反代 502 返回 Bad Gateway 确认已勾选 Enable proxy 并放行本机端口 3000
    WebSocket 不工作 Issue/PR 无实时刷新 ARR Server Proxy Settings 中启用代理后无需额外头阻断;检查 URL Rewrite 规则未强制移除 Upgrade 头
    下载直链失效 404 或超时 回到官方页面重新获取最新下载链接
    Mixed Content 警告 控制台报非安全资源 确认 ROOT_URL 已使用 https 并正确端口

完成后再继续 7.2 创建站点与证书绑定。

创建站点与绑定证书

  1. 创建站点根目录:D:\iissites\gitea(可空)。
  2. 新建网站:名称 Gitea, 物理路径上述目录, 绑定 https 到域名,端口 443,选择已导入的 PFX 证书。

添加反向代理规则

在站点根双击“URL Rewrite” -> Add Rule(s) -> “Inbound Rule”。
示例:

  • Match URL: Requested URL: Matches PatternUsing: Regular ExpressionsPattern: (.*)
  • Conditions: 可选
  • Action: Action Type: RewriteRewrite URL: http://127.0.0.1:3000/{R:1},勾选“Append query string”。

为防止 WebSocket 问题:确保在 ARR Server Proxy Settings 中勾选“Enable proxy”后同时配置:

  • “Preserve client IP” 视需求
  • 在站点的 请求筛选 (Request Filtering) 中允许 TRACE (可忽略);核心是确保没有阻断 Upgrade 头。

502.3 Bad Gateway(无法解析服务器名称或地址)排错

错误页面示例:HTTP 错误 502.3 - Bad Gateway 无法解析服务器的名称或地址

常见触发原因:

原因 说明 快速识别 解决措施
未启用 Proxy ARR 未勾选 Enable proxy 502.3 且日志无后端连接条目 在服务器节点“Application Request Routing Cache” -> “Server Proxy Settings” 勾选 Enable proxy
后端未监听 Gitea 服务未启动或端口变更 netstat 无 0.0.0.0/127.0.0.1:3000 启动服务或同步 app.ini 中 HTTP_PORT 与规则端口
重写目标域名解析失败 规则使用域名而该域名无 DNS/hosts 记录 目标使用 http://git.internal.local:3000/... 改用 http://127.0.0.1:3000/{R:1} 或添加 hosts 解析
防火墙拦截本地环回 极少见,出站/入站规则阻断 Windows 日志显示阻断 临时关闭相关规则或放行 127.0.0.1 -> 3000
应用池权限不足 自定义身份访问不到 D:\gitea\bin 或端口 EventLog 出现访问被拒绝 改为 ApplicationPoolIdentity + 赋予目录读取/执行权限
规则写错或多重匹配冲突 多条规则抢先重写到错误地址 Failed Request Tracing 显示重复重写 暂时禁用其它规则,仅保留一条通配规则测试
SSL 与非 SSL 混用 使用 https://127.0.0.1:3000/ 后端没 TLS 浏览器 502.3,后端无握手 使用纯 http 回源;IIS 终端处理 TLS
超时 后端响应缓慢超过默认超时 大仓库操作或初始化延迟 在 ARR Proxy Settings 提高 Timeouts (Proxy timeout / response timeout)

排查步骤(推荐顺序):

  1. 验证后端服务是否正常:
    1
    2
    3
    Get-Service Gitea
    netstat -ano | findstr :3000
    Invoke-WebRequest -Uri http://127.0.0.1:3000/ -UseBasicParsing | Select-Object StatusCode
    StatusCode 为 200 表示后端 OK。
  2. 检查规则是否使用本地 IP:打开站点“URL Rewrite”查看目标为 http://127.0.0.1:3000/{R:1}。若为域名改为本地 IP 再测。
  3. 确认已启用代理:服务器节点 -> Application Request Routing Cache -> Server Proxy Settings 是否勾选“Enable proxy”。
  4. 查看 Failed Request Tracing(若已启用):是否有 MODULE_SET_RESPONSE_ERROR_STATUS 指向 rewrite/arr。
  5. 使用 Event Viewer -> Application 日志搜索关键字 ARRrewritew3wp
  6. 若使用自定义应用池身份:赋权:
    1
    2
    icacls D:\gitea\bin /grant 'IIS AppPool\\GiteaPool':(RX)
    icacls D:\gitea\data /grant 'IIS AppPool\\GiteaPool':(OI)(CI)R
  7. 调高超时(大操作上游慢):Server Proxy Settings 中增加 Time-out (secs)
  8. 重启应用池或执行 iisreset /restart(仅模块加载异常时)。

快速对比测试脚本(一次性排查核心项):

1
2
3
4
5
6
7
8
Write-Host '== 检查 Gitea 服务 ==' -ForegroundColor Cyan
Get-Service Gitea | Format-Table Status,Name
Write-Host '== 端口监听 ==' -ForegroundColor Cyan
netstat -ano | findstr :3000
Write-Host '== 回源 HTTP 测试 ==' -ForegroundColor Cyan
try { (Invoke-WebRequest http://127.0.0.1:3000/ -UseBasicParsing).StatusCode } catch { $_.Exception.Message }
Write-Host '== Rewrite 规则人工核对 ==' -ForegroundColor Cyan
Write-Host '确认: 仅一条通配 (.*) -> http://127.0.0.1:3000/{R:1}'

若仍报 502.3:

  • 开启 Failed Request Tracing (FRT) 针对状态码 502,查看详细模块调用顺序。
  • 用 Procmon 过滤 w3wp.exe 端口和文件访问是否被拒绝。
  • 将目标临时改为其它本地端口测试(排除特定端口被安全软件拦截)。

最佳实践:

  • 始终使用本地 127.0.0.1 回源而非同名域名,减少 DNS 依赖。
  • 仅在确认后端支持 TLS 时使用 https 回源,否则保持 http。
  • 规则简化:单条 (.*) 即可;复杂路径匹配先验证后再扩展。
  • 将排错脚本保存为 Check-GiteaProxy.ps1 方便重复使用。

FRT 启用简述:IIS 管理器 -> 站点 -> Failed Request Tracing -> Enable,再在“Failed Request Tracing Rules”创建捕获 502 状态的规则。日志默认写入站点目录下 Logs\FailedReqLogFiles

强制 HTTPS 与安全响应头

在 URL Rewrite 添加一条 HTTP->HTTPS 301 重定向(若另建 80 端口绑定)。
添加自定义响应头:

  • X-Frame-Options: SAMEORIGIN
  • X-Content-Type-Options: nosniff
  • Referrer-Policy: strict-origin-when-cross-origin
  • Content-Security-Policy: default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob: (根据实际前端脚本调整)

使用自签名证书(测试 / 内网)

生产建议使用受信任 CA。若需快速在内网测试 HTTPS,可创建自签名证书并在客户端导入信任。

生成自签名证书(含私钥)

在服务器管理员 PowerShell 中执行:

1
2
$dnsName = 'git.internal.local'   # 使用你的内网域名或主机名
$cert = New-SelfSignedCertificate -DnsName $dnsName -CertStoreLocation Cert:\LocalMachine\My -FriendlyName "Gitea Self-Signed" -KeyLength 2048 -HashAlgorithm SHA256 -NotAfter (Get-Date).AddYears(2)

导出 PFX(供 IIS 绑定):

1
2
3
4
$pfxPath = "C:\certs\gitea-selfsigned.pfx"
New-Item -ItemType Directory -Force -Path (Split-Path $pfxPath) | Out-Null
$pwd = Read-Host -AsSecureString -Prompt '输入导出 PFX 密码'
Export-PfxCertificate -Cert $cert -FilePath $pfxPath -Password $pwd

导出根证书(供客户端安装信任):

1
2
$cerPath = "C:\certs\gitea-selfsigned-root.cer"
Export-Certificate -Cert $cert -FilePath $cerPath

(可选)若使用自签名链式根 + 签发证书:自行创建 Root CA 再签发。单一自签名即可满足简单测试。

在 IIS 绑定自签名证书

  1. IIS 管理器 -> 服务器节点 -> “Server Certificates” -> Import -> 选择 gitea-selfsigned.pfx 输入密码。
  2. 在站点“Bindings”中新增或编辑 HTTPS 绑定,端口自定义(见 7.6),Host name 使用 $dnsName,选择刚导入的证书。

分发与安装客户端信任(Windows)

gitea-selfsigned-root.cer 分发给同事,指导其:

  1. 双击文件 -> 安装证书。
  2. 选择“本地计算机”(需管理员)或“当前用户”(仅该用户生效)。
  3. 证书存储选择“受信任的根证书颁发机构”。
  4. 完成后用浏览器访问 https://git.internal.local:<端口>,不再出现安全警告。

批量脚本(管理员运行):

1
Import-Certificate -FilePath C:\certs\gitea-selfsigned-root.cer -CertStoreLocation Cert:\LocalMachine\Root

macOS / Linux 客户端信任

macOS:双击 .cer -> 钥匙串访问 -> 拖入 “系统” 或 “登录”钥匙串,打开后设置“始终信任”。
Linux(Debian/Ubuntu):

1
2
sudo cp gitea-selfsigned-root.cer /usr/local/share/ca-certificates/gitea-selfsigned.crt
sudo update-ca-certificates

Linux(CentOS/RHEL):

1
2
sudo cp gitea-selfsigned-root.cer /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust

Gitea 配置注意点

使用自签名不需要修改 Gitea 的 PROTOCOL(仍为 http 通过反代),但 ROOT_URL 应使用实际外部访问的 https 地址与端口:

1
2
[server]
ROOT_URL = https://git.internal.local:8443/

确保浏览器访问与仓库克隆 URL 一致,否则可能出现重定向或 Mixed Content。

端口占用时的替代端口方案(80/443 已占用)

若现有服务器已有站点占用 80/443,可为 Gitea 站点使用例如:HTTP 8080 / HTTPS 8443。

IIS 绑定示例

  1. 在 IIS 站点“Bindings”添加:
  • 类型:http 端口:8080 Host name:git.internal.local(可选)
  • 类型:https 端口:8443 Host name:git.internal.local 证书:自签名或正式证书
  1. 若仅启用 HTTPS,可省略 8080 并只开放 8443;添加一个 HTTP 8080 -> HTTPS 8443 重定向规则(参见 7.4)。

URL Rewrite 规则(端口保持不变)

反向代理至内部 Gitea 3000 端口保持不变:

1
2
Pattern: (.*)
Rewrite URL: http://127.0.0.1:3000/{R:1}

无需在规则中显式端口 8080/8443,它们由站点绑定决定。

Gitea ROOT_URL 与仓库克隆地址

app.ini

1
2
3
[server]
ROOT_URL = https://git.internal.local:8443/
HTTP_PORT = 3000

注意:

  • 外部端口(8443)不需要在 Gitea 启动端口中配置,仅使用代理端口。
  • 若使用 SSH 克隆并自定义端口(例如 2222),还需:SSH_PORT = 2222 并在防火墙开放。

防火墙与开放端口

开放 8080(若需要)与 8443:

1
2
New-NetFirewallRule -DisplayName "Gitea HTTPS 8443" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8443
New-NetFirewallRule -DisplayName "Gitea HTTP 8080" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8080

客户端访问与证书信任验证

访问:https://git.internal.local:8443/ -> 查看浏览器锁图标是否正常;若仍提示不安全,确认根证书已导入“受信任根”而不是“个人”或“中间证书”。

常见问题

问题 现象 解决
仍跳转到 443 浏览器自动改端口 清理浏览器缓存,确认 ROOT_URL 已带 8443
证书不可信 红色叉或警告 客户端未导入根证书或主机名不匹配(生成时需正确 DNSName)
克隆 URL 错误 显示 3000 端口 检查 ROOT_URL 设置并重启服务
WebSocket 失败 事件不刷新 ARR 代理设置是否保留 Upgrade 头,端口更换不影响需保持规则

自签名仅用于测试,转生产请使用可信 CA 并恢复标准 443 端口或发布统一反代策略。

用户、组织与权限管理要点

  • 关闭任意注册:在管理后台 -> Authentication 关闭自助注册或启用邮件白名单。
  • 启用 CAPTCHA:降低机器人注册风险。
  • 使用组织 (Organization) 分组仓库与团队。团队设置针对读/写/管理员粒度权限。
  • SSH Key 管理:鼓励用户使用个人 SSH;可集中审计公钥变更。

备份、恢复与升级策略

备份内容:

  1. repositories 目录:核心代码与 Git 元数据。
  2. 数据库:使用数据库自身备份机制(mysqldump / pg_dump / SQL Server Agent)。
  3. app.inilog 重要日志。

示例 PowerShell 每日增量备份(简化):

1
2
3
$date = (Get-Date -Format 'yyyyMMdd')
Compress-Archive -Path D:\gitea\data\repositories -DestinationPath D:\backup\gitea-repos-$date.zip
mysqldump -u gitea -p强密码 gitea > D:\backup\gitea-mysql-$date.sql # 若使用 MySQL

升级流程:

  1. 备份上述数据。
  2. 停止服务:Stop-Service gitea
  3. 下载新版本 gitea.exe 覆盖旧文件。
  4. 启动:Start-Service gitea 并查看日志确认无迁移异常。

性能与安全加固建议

  • 打开 Gitea 内置缓存与索引(默认即可)。
  • 将附件与 LFS 大文件单独存储并限制大小(在管理设置设定)。
  • 定期清理未使用仓库、过期附件,降低备份体积。
  • 数据库层调优:连接池、慢查询日志要开启并评估。
  • 使用 Windows 防火墙限制仅 80/443/SSH 开放;后台 3000 仅本机访问。
  • 启用 Fail2ban 类似机制需借助外部(Windows 原生不含),可用日志 + 脚本封禁恶意 IP。

常见问题与排错 (FAQ)

问题 现象 解决
访问超时 直接访问域名无响应 检查 IIS 反向代理规则是否指向 127.0.0.1:3000
WebSocket 推送失败 PR / Issue 事件无实时刷新 ARR 设置里开启代理,保留 Upgrade
SSH 克隆失败 connection refused 确认 Windows OpenSSH 服务运行且端口 22 开放;app.ini 中 DOMAIN 与 ROOT_URL 正确
数据库编码异常 中文显示乱码 确保 MySQL 使用 utf8mb4,PostgreSQL UTF8
升级后 500 日志迁移错误 检查日志中 migration 关键字,回滚或手动修复表结构
服务无法启动 Service status: Stopped ./gitea.exe web 前台运行观察错误日志定位配置拼写
ROOT_URL 警告 访问时提示 mismatch 修改 [server] ROOT_URL 为外部实际地址 + 端口 + 尾斜杠并重启;确认 PROTOCOL 与反代策略一致
502.3 Bad Gateway 无法解析服务器名称或地址 启用 Enable proxy;规则使用 127.0.0.1;确认端口监听与回源 200;参考 7.3.1 排错步骤

日志查看:Get-Content -Path D:\gitea\log\gitea.log -Tail 200 -Wait

参考