Ferrit Explore
中文·繁體·EN·日本語 Sign in Register
cielxl / ferrit / DEPLOY.md
# Ferrit 部署手册

适用版本:Ferrit 0.1.0
覆盖平台:**Windows** · **CentOS (7 / Stream)** · **Ubuntu (20.04+)**

---

## 0. 通用说明

### 0.1 运行原理 / 依赖

Ferrit 是一个纯 Rust 编写的自托管 Git 服务。运行时它只依赖两样东西:

1. **编译好的 `ferrit` 可执行文件**(无任何动态库依赖,单文件即可运行);
2. 系统中已安装的 **`git`**(克隆/推送通过调用 git 自带的 `git http-backend` 完成,浏览代码也依赖 `git`)。

> ⚠️ 运行环境必须能在 `PATH` 中找到 `git`,否则建仓、克隆、推送都会失败。

### 0.2 配置项(环境变量)

| 变量名         | 默认值              | 说明                                       |
| -------------- | ------------------- | ------------------------------------------ |
| `FERRIT_ADDR`  | `127.0.0.1:3000`    | 监听地址。对外直连需改为 `0.0.0.0:3000`    |
| `FERRIT_DATA`  | `data`              | 数据目录(相对启动目录或写绝对路径)       |

### 0.3 数据目录结构

```
<FERRIT_DATA>/
  db.json                       # 用户 + 仓库元数据(JSON)
  repos/<用户名>/<仓库名>.git/  # 裸 git 仓库(真正的代码对象)
```

备份只需备份整个 `FERRIT_DATA` 目录即可(见第 5 节)。

### 0.4 安全建议

- **默认只监听 `127.0.0.1`**,生产环境建议保持如此,前面挂 Nginx 反向代理并启用 HTTPS(见第 4 节),不要把 3000 端口直接暴露公网。
- 口令使用加盐多轮 SHA-256 存储,不保存明文。
- 推送(push)与私有仓库访问强制要求 HTTP Basic 认证,且仅仓库属主可写。

---

## 1. Windows 部署

### 1.1 安装依赖

1. **Git for Windows** — https://git-scm.com/download/win
   安装后确认:
   ```powershell
   git --version
   ```
2. **Rust 工具链**(仅编译时需要)— https://rustup.rs 下载 `rustup-init.exe`,或:
   ```powershell
   winget install --id Rustlang.Rustup -e
   ```
3. **MSVC C++ 生成工具**(Rust 在 Windows 上链接需要 `link.exe`):
   ```powershell
   winget install --id Microsoft.VisualStudio.2022.BuildTools -e
   ```
   安装时勾选 “使用 C++ 的桌面开发”。

### 1.2 编译

```powershell
cd E:\work\tools\git
cargo build --release
# 产物:E:\work\tools\git\target\release\ferrit.exe
```

### 1.3 手动运行(验证)

```powershell
$env:FERRIT_ADDR = "127.0.0.1:3000"
$env:FERRIT_DATA = "E:\ferrit-data"
.\target\release\ferrit.exe
```
浏览器打开 http://127.0.0.1:3000 ,Ctrl+C 停止。

### 1.4 注册为 Windows 服务(开机自启,使用 NSSM)

1. 下载 NSSM:https://nssm.cc/download ,解压取 `win64\nssm.exe`。
2. 以**管理员** PowerShell 安装服务:
   ```powershell
   # 拷贝二进制到固定目录
   New-Item -ItemType Directory -Force C:\ferrit\bin, C:\ferrit\data | Out-Null
   Copy-Item .\target\release\ferrit.exe C:\ferrit\bin\

   # 安装服务
   nssm install Ferrit "C:\ferrit\bin\ferrit.exe"
   nssm set Ferrit AppDirectory "C:\ferrit"
   nssm set Ferrit AppEnvironmentExtra FERRIT_ADDR=127.0.0.1:3000 FERRIT_DATA=C:\ferrit\data
   nssm set Ferrit AppStdout C:\ferrit\ferrit.log
   nssm set Ferrit AppStderr C:\ferrit\ferrit.log
   nssm set Ferrit Start SERVICE_AUTO_START

   # 启动
   nssm start Ferrit
   ```
3. 常用管理:
   ```powershell
   nssm restart Ferrit
   nssm stop Ferrit
   nssm remove Ferrit confirm     # 卸载服务
   ```

> 不想装 NSSM 也可用任务计划程序(Task Scheduler)创建“计算机启动时运行”的任务,操作设为运行 `ferrit.exe`,并在“起始于”里填工作目录。

### 1.5 防火墙(仅当需要局域网/外网直连时)

```powershell
New-NetFirewallRule -DisplayName "Ferrit 3000" -Direction Inbound -Protocol TCP -LocalPort 3000 -Action Allow
```
直连还需把 `FERRIT_ADDR` 改成 `0.0.0.0:3000`。

---

## 2. CentOS 部署(CentOS 7 / CentOS Stream 8/9)

### 2.1 安装依赖

```bash
sudo yum install -y git gcc        # CentOS 7
# 或 CentOS Stream:sudo dnf install -y git gcc

git --version

# 安装 Rust(仅编译用)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source "$HOME/.cargo/env"
```

> 也可在一台开发机上编译好 `ferrit` 二进制,再拷到生产服务器(同为 x86_64-linux 即可),生产机只需装 `git`。

### 2.2 编译

```bash
cd /path/to/ferrit-source
cargo build --release
# 产物:target/release/ferrit
```

### 2.3 部署文件与专用用户

```bash
sudo useradd --system --create-home --home-dir /var/lib/ferrit --shell /sbin/nologin ferrit
sudo install -m 0755 target/release/ferrit /usr/local/bin/ferrit
sudo mkdir -p /var/lib/ferrit/data
sudo chown -R ferrit:ferrit /var/lib/ferrit
```

### 2.4 创建 systemd 服务

```bash
sudo tee /etc/systemd/system/ferrit.service >/dev/null <<'EOF'
[Unit]
Description=Ferrit Git Service
After=network.target

[Service]
User=ferrit
Group=ferrit
WorkingDirectory=/var/lib/ferrit
Environment=FERRIT_ADDR=127.0.0.1:3000
Environment=FERRIT_DATA=/var/lib/ferrit/data
ExecStart=/usr/local/bin/ferrit
Restart=on-failure
RestartSec=3
NoNewPrivileges=true
ProtectSystem=full
ProtectHome=true
ReadWritePaths=/var/lib/ferrit

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now ferrit
sudo systemctl status ferrit
journalctl -u ferrit -f          # 查看日志
```

### 2.5 SELinux(CentOS 默认开启)

若让 Nginx 反代到本机 3000,需放行:
```bash
sudo setsebool -P httpd_can_network_connect 1
```

### 2.6 防火墙(firewalld)

```bash
# 仅当对外直连 3000(一般不建议,推荐走 80/443 反代)
sudo firewall-cmd --permanent --add-port=3000/tcp
sudo firewall-cmd --reload
```

---

## 3. Ubuntu 部署(20.04 / 22.04 / 24.04)

### 3.1 安装依赖

```bash
sudo apt update
sudo apt install -y git build-essential

git --version

# 安装 Rust(仅编译用)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source "$HOME/.cargo/env"
```

### 3.2 编译

```bash
cd /path/to/ferrit-source
cargo build --release
```

### 3.3 部署文件与专用用户

```bash
sudo useradd --system --create-home --home-dir /var/lib/ferrit --shell /usr/sbin/nologin ferrit
sudo install -m 0755 target/release/ferrit /usr/local/bin/ferrit
sudo mkdir -p /var/lib/ferrit/data
sudo chown -R ferrit:ferrit /var/lib/ferrit
```

### 3.4 创建 systemd 服务

> 与 CentOS 完全一致(注意 Ubuntu 的 nologin 路径是 `/usr/sbin/nologin`)。

```bash
sudo tee /etc/systemd/system/ferrit.service >/dev/null <<'EOF'
[Unit]
Description=Ferrit Git Service
After=network.target

[Service]
User=ferrit
Group=ferrit
WorkingDirectory=/var/lib/ferrit
Environment=FERRIT_ADDR=127.0.0.1:3000
Environment=FERRIT_DATA=/var/lib/ferrit/data
ExecStart=/usr/local/bin/ferrit
Restart=on-failure
RestartSec=3
NoNewPrivileges=true
ProtectSystem=full
ProtectHome=true
ReadWritePaths=/var/lib/ferrit

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now ferrit
sudo systemctl status ferrit
journalctl -u ferrit -f
```

### 3.5 防火墙(ufw)

```bash
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# 直连 3000(不推荐):sudo ufw allow 3000/tcp
```

---

## 4. 反向代理 + HTTPS(CentOS / Ubuntu 推荐)

Ferrit 自身只提供 HTTP,生产环境建议用 Nginx 终止 TLS。

### 4.1 安装 Nginx

```bash
# Ubuntu
sudo apt install -y nginx
# CentOS
sudo dnf install -y nginx && sudo systemctl enable --now nginx
```

### 4.2 站点配置

```bash
sudo tee /etc/nginx/conf.d/ferrit.conf >/dev/null <<'EOF'
server {
    listen 80;
    server_name git.example.com;

    # git push 可能上传较大的 pack,放开请求体大小限制
    client_max_body_size 2048m;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 大仓库 push/clone 友好设置
        proxy_request_buffering off;
        proxy_read_timeout      600s;
        proxy_send_timeout      600s;
    }
}
EOF

sudo nginx -t && sudo systemctl reload nginx
```

### 4.3 申请 HTTPS 证书(Let's Encrypt)

```bash
# Ubuntu
sudo apt install -y certbot python3-certbot-nginx
# CentOS
sudo dnf install -y certbot python3-certbot-nginx

sudo certbot --nginx -d git.example.com
```
certbot 会自动改写上面的 server 块为 443 + 自动续期。

> **已知限制**:当前版本仓库页展示的 `git clone` 地址固定以 `http://` 拼接(取自 `Host` 头)。在 HTTPS 反代下,页面显示的 clone 地址前缀会是 `http://`,但通过反代实际克隆/推送均正常。介意的话可在前端手动改成 `https://`,或后续在 `src/web.rs` 的 `host_base()` 里读取 `X-Forwarded-Proto` 做适配。

---

## 5. 备份与恢复

整个服务的状态都在 `FERRIT_DATA` 目录里。

**备份:**
```bash
# Linux
sudo systemctl stop ferrit        # 可选:停服保证一致性
sudo tar czf ferrit-backup-$(date +%F).tar.gz -C /var/lib/ferrit data
sudo systemctl start ferrit
```
```powershell
# Windows
Compress-Archive -Path C:\ferrit\data\* -DestinationPath C:\ferrit\backup-$(Get-Date -Format yyyyMMdd).zip
```

**恢复:** 停服 → 用备份覆盖 `FERRIT_DATA` 目录 → 启服。

---

## 6. 升级

```bash
# 1. 拉取新代码并编译
cargo build --release
# 2. 替换二进制
sudo systemctl stop ferrit
sudo install -m 0755 target/release/ferrit /usr/local/bin/ferrit
sudo systemctl start ferrit
```
Windows:`nssm stop Ferrit` → 覆盖 `ferrit.exe` → `nssm start Ferrit`。

数据格式(`db.json` + 裸仓库)保持兼容,升级无需迁移。

---

## 7. 验证部署

部署完成后做一次端到端自测:

```bash
# 1. 服务存活
curl -I http://127.0.0.1:3000/            # 期望 200

# 2. 网页注册一个用户、建一个仓库(浏览器操作),然后:
git clone http://用户名@<服务器地址>/用户名/仓库名.git
cd 仓库名
echo "# hello" > README.md
git add README.md && git commit -m "init"
git push -u origin main                    # 输入 Ferrit 口令
# 刷新仓库页面应能看到文件与提交记录
```

---

## 8. 常见问题排查

| 现象 | 排查方向 |
| ---- | -------- |
| 建仓/克隆/推送报错 `cannot start git` | 服务进程的 `PATH` 找不到 `git`;确认已安装 git,Linux 服务用绝对路径或保证 `/usr/bin/git` 存在 |
| push 返回 401 | 正常的认证要求;用 `http://用户名@host/...` 形式克隆并输入口令;只有仓库属主可推送 |
| push 返回 403 | 认证用户与仓库属主不一致 |
| 私有仓库网页 404 | 预期行为:未登录或非属主不可见 |
| Nginx 502 | 后端未启动或 SELinux 拦截(CentOS 执行 `setsebool -P httpd_can_network_connect 1`) |
| 大仓库 push 被中断 | 调大 Nginx `client_max_body_size` 与 `proxy_read_timeout` |
| 外网无法访问 | 确认 `FERRIT_ADDR=0.0.0.0:3000`(或走反代)并放行防火墙 |

---

*Ferrit — 一个用 Rust 编写的极简自托管 Git 服务。*