初次提交,gitea
This commit is contained in:
58
gitea/.env.example
Normal file
58
gitea/.env.example
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# ============================================
|
||||||
|
# Gitea 部署环境变量配置
|
||||||
|
# 复制此文件为 .env 并修改对应值
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# ---- 域名配置(必改!)----
|
||||||
|
# 你的域名,需提前解析 A 记录到服务器 IP
|
||||||
|
GITEA_DOMAIN=git.example.com
|
||||||
|
# 用于申请 SSL 证书的邮箱
|
||||||
|
CERTBOT_EMAIL=admin@example.com
|
||||||
|
|
||||||
|
# ---- 服务器目录配置 ----
|
||||||
|
# 部署目录(docker-compose.yml、脚本、.env 所在目录)
|
||||||
|
INSTALL_DIR=/opt/gitea
|
||||||
|
# Gitea 应用数据(仓库、LFS、附件、头像、SSH/GPG 密钥)
|
||||||
|
GITEA_DATA_DIR=/var/lib/gitea
|
||||||
|
# MySQL 数据库文件
|
||||||
|
MYSQL_DATA_DIR=/var/lib/mysql/gitea
|
||||||
|
# 备份文件存放目录
|
||||||
|
BACKUP_DIR=/var/backups/gitea
|
||||||
|
|
||||||
|
# ---- Gitea 镜像配置 ----
|
||||||
|
# 官方最新镜像地址: docker.gitea.com/gitea:1.25.5
|
||||||
|
# Docker Hub 镜像: gitea/gitea:1.25 (默认,可被国内加速源加速)
|
||||||
|
# 如果服务器在海外或不需要加速,可切换为官方地址
|
||||||
|
GITEA_IMAGE=gitea/gitea:1.25
|
||||||
|
|
||||||
|
# ---- Docker 镜像加速(国内服务器建议配置)----
|
||||||
|
# 多个镜像用逗号分隔,留空则不配置加速
|
||||||
|
# 常用镜像源(2026 年可用,按稳定性排序):
|
||||||
|
# https://docker.1ms.run — 1ms 公益加速
|
||||||
|
# https://docker.m.daocloud.io — DaoCloud 公开镜像
|
||||||
|
# https://docker.xuanyuan.me — 轩辕镜像
|
||||||
|
# https://dockerpull.org — DockerPull 公益
|
||||||
|
# https://docker.rainbond.cc — Rainbond 社区
|
||||||
|
# https://docker.udayun.com — 优达云
|
||||||
|
# https://docker.211678.top — 211678 加速
|
||||||
|
# https://hub.rat.dev — RatDev 公益
|
||||||
|
# 提示: 镜像源可能随时失效,部署前可 curl 测试连通性
|
||||||
|
DOCKER_REGISTRY_MIRRORS=https://docker.1ms.run,https://docker.m.daocloud.io,https://dockerpull.org,https://docker.rainbond.cc,https://docker.udayun.com,https://hub.rat.dev
|
||||||
|
|
||||||
|
# ---- 数据库密码(deploy.sh 自动生成,无需手动填)----
|
||||||
|
DB_PASSWORD=请替换为强密码
|
||||||
|
DB_ROOT_PASSWORD=请替换为ROOT强密码
|
||||||
|
|
||||||
|
# ---- 端口配置 ----
|
||||||
|
# SSH 克隆端口(对外暴露)
|
||||||
|
SSH_PORT=2222
|
||||||
|
|
||||||
|
# ---- GPG 签名配置 ----
|
||||||
|
GPG_SIGNING_NAME=Gitea
|
||||||
|
GPG_SIGNING_EMAIL=gitea@example.com
|
||||||
|
|
||||||
|
# ---- 安全设置 ----
|
||||||
|
# 部署完成并创建管理员账户后,建议设为 true 关闭公开注册
|
||||||
|
DISABLE_REGISTRATION=false
|
||||||
|
# 是否要求登录才能浏览(私有部署建议 true)
|
||||||
|
REQUIRE_SIGNIN=false
|
||||||
3
gitea/.gitignore
vendored
Normal file
3
gitea/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
data/
|
||||||
|
backups/
|
||||||
|
.env
|
||||||
368
gitea/README.md
Normal file
368
gitea/README.md
Normal file
@@ -0,0 +1,368 @@
|
|||||||
|
# Gitea 云服务器部署指南
|
||||||
|
|
||||||
|
> 全新服务器从零搭建,含 Docker + MySQL + Nginx HTTPS + Git LFS + SSH 密钥 + GPG 签名
|
||||||
|
|
||||||
|
## 架构概览
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────┐
|
||||||
|
│ 云服务器 │
|
||||||
|
用户 ───HTTPS───→ │ Nginx:443 ──→ Gitea:3000 │
|
||||||
|
用户 ───SSH────→ │ 端口:2222 ──→ Gitea SSH │
|
||||||
|
│ ↓ │
|
||||||
|
│ MySQL:3306 │
|
||||||
|
│ │
|
||||||
|
│ /opt/gitea/ 部署文件 (compose等) │
|
||||||
|
│ /var/lib/gitea/ 仓库+LFS+附件+密钥 │
|
||||||
|
│ /var/lib/mysql/gitea/ MySQL 数据 │
|
||||||
|
│ /var/backups/gitea/ 备份文件 │
|
||||||
|
└──────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
| 组件 | 版本 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| Gitea | 1.25 | Git 托管服务(含内置 SSH 服务器) |
|
||||||
|
| MySQL | 8.0 | 数据库(utf8mb4) |
|
||||||
|
| Nginx | 系统包 | HTTPS 反向代理 |
|
||||||
|
| Certbot | 系统包 | Let's Encrypt 自动 SSL 证书 |
|
||||||
|
| Docker | 最新 | 容器运行时 |
|
||||||
|
|
||||||
|
### 已启用功能
|
||||||
|
|
||||||
|
- **HTTPS**:Nginx + Let's Encrypt 免费 SSL,自动续期
|
||||||
|
- **Git LFS**:大文件存储,支持最大 4GB 单文件上传
|
||||||
|
- **SSH 密钥**:内置 SSH 服务器,支持 Ed25519/RSA 等密钥
|
||||||
|
- **GPG 签名**:提交签名验证,显示 "Verified" 徽标
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、前置条件
|
||||||
|
|
||||||
|
| 项目 | 要求 |
|
||||||
|
|------|------|
|
||||||
|
| 服务器 | 2核 2GB+ 内存,50GB+ SSD |
|
||||||
|
| 系统 | Ubuntu 20.04+ / Debian 11+ |
|
||||||
|
| 域名 | 已解析 A 记录到服务器 IP |
|
||||||
|
| 端口 | 80、443、2222 可从外网访问 |
|
||||||
|
|
||||||
|
> 如果使用云厂商(阿里云/腾讯云/AWS),需要在**安全组**中放行上述端口。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、一键部署(全新服务器)
|
||||||
|
|
||||||
|
### 步骤 1:上传部署文件
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 在本地执行,将文件上传到服务器
|
||||||
|
scp -r gitea/ root@服务器IP:/opt/gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
### 步骤 2:首次运行,生成配置
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh root@服务器IP
|
||||||
|
cd /opt/gitea
|
||||||
|
chmod +x deploy.sh backup.sh
|
||||||
|
|
||||||
|
# 首次运行 → 自动安装系统依赖 + Docker + Nginx
|
||||||
|
# 然后生成 .env 配置文件(密码已随机生成)并退出
|
||||||
|
bash deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 步骤 3:修改域名配置
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vi .env
|
||||||
|
```
|
||||||
|
|
||||||
|
**必须修改的字段:**
|
||||||
|
|
||||||
|
```ini
|
||||||
|
GITEA_DOMAIN=git.yourdomain.com # ← 你的实际域名
|
||||||
|
CERTBOT_EMAIL=you@yourdomain.com # ← 你的邮箱(证书通知用)
|
||||||
|
```
|
||||||
|
|
||||||
|
可选修改:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
SSH_PORT=2222 # Git SSH 端口
|
||||||
|
GPG_SIGNING_NAME=Gitea # GPG 签名显示名称
|
||||||
|
GPG_SIGNING_EMAIL=git@xxx.com # GPG 签名邮箱
|
||||||
|
DISABLE_REGISTRATION=false # 部署完成后改为 true
|
||||||
|
REQUIRE_SIGNIN=false # 私有部署改为 true
|
||||||
|
```
|
||||||
|
|
||||||
|
### 步骤 4:执行部署
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
脚本会自动完成以下 8 个步骤:
|
||||||
|
|
||||||
|
| 步骤 | 操作 |
|
||||||
|
|------|------|
|
||||||
|
| 1/8 | 系统更新,安装基础工具(curl, git, openssl 等)|
|
||||||
|
| 2/8 | 安装 Docker + Docker Compose V2 |
|
||||||
|
| 3/8 | 安装 Nginx |
|
||||||
|
| 4/8 | 验证 .env 配置 |
|
||||||
|
| 5/8 | 创建数据目录 |
|
||||||
|
| 6/8 | 配置防火墙(UFW/Firewalld)|
|
||||||
|
| 7/8 | 申请 SSL 证书 + 配置 Nginx HTTPS 反向代理 |
|
||||||
|
| 8/8 | 拉取镜像,启动 Gitea + MySQL 容器 |
|
||||||
|
|
||||||
|
### 步骤 5:初始化 Gitea
|
||||||
|
|
||||||
|
1. 浏览器打开 `https://git.yourdomain.com`
|
||||||
|
2. 进入安装向导(数据库已自动配置好)
|
||||||
|
3. **创建管理员账户**(务必设置强密码)
|
||||||
|
4. 点击 "安装 Gitea"
|
||||||
|
|
||||||
|
### 步骤 6:安装后加固
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/gitea
|
||||||
|
|
||||||
|
# 关闭公开注册
|
||||||
|
sed -i 's/DISABLE_REGISTRATION=false/DISABLE_REGISTRATION=true/' .env
|
||||||
|
# 要求登录才能浏览
|
||||||
|
sed -i 's/REQUIRE_SIGNIN=false/REQUIRE_SIGNIN=true/' .env
|
||||||
|
|
||||||
|
# 重启生效
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、功能使用指南
|
||||||
|
|
||||||
|
### SSH 密钥认证
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 本地生成密钥(如果还没有)
|
||||||
|
ssh-keygen -t ed25519 -C "your@email.com"
|
||||||
|
|
||||||
|
# 2. 复制公钥
|
||||||
|
cat ~/.ssh/id_ed25519.pub
|
||||||
|
|
||||||
|
# 3. 在 Gitea 中添加
|
||||||
|
# → 头像 → 设置 → SSH/GPG 密钥 → 添加密钥 → 粘贴公钥
|
||||||
|
|
||||||
|
# 4. 测试连接
|
||||||
|
ssh -T git@git.yourdomain.com -p 2222
|
||||||
|
|
||||||
|
# 5. 克隆仓库
|
||||||
|
git clone ssh://git@git.yourdomain.com:2222/用户名/仓库.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### GPG 签名提交
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 生成 GPG 密钥
|
||||||
|
gpg --full-generate-key
|
||||||
|
# 选择 RSA and RSA → 4096 → 填写名字和邮箱
|
||||||
|
|
||||||
|
# 2. 查看密钥 ID
|
||||||
|
gpg --list-secret-keys --keyid-format=long
|
||||||
|
# 输出中 sec 行的 XXXXXXXXXXXXXXXX 就是密钥 ID
|
||||||
|
|
||||||
|
# 3. 导出公钥
|
||||||
|
gpg --armor --export XXXXXXXXXXXXXXXX
|
||||||
|
|
||||||
|
# 4. 在 Gitea 中添加
|
||||||
|
# → 头像 → 设置 → SSH/GPG 密钥 → 添加 GPG 密钥 → 粘贴公钥
|
||||||
|
|
||||||
|
# 5. 配置 Git 使用 GPG 签名
|
||||||
|
git config --global user.signingkey XXXXXXXXXXXXXXXX
|
||||||
|
git config --global commit.gpgsign true
|
||||||
|
|
||||||
|
# 6. 签名提交(之后所有 commit 自动签名)
|
||||||
|
git commit -S -m "signed commit"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Git LFS 大文件
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 安装 Git LFS(本地)
|
||||||
|
git lfs install
|
||||||
|
|
||||||
|
# 2. 跟踪大文件类型
|
||||||
|
git lfs track "*.psd"
|
||||||
|
git lfs track "*.zip"
|
||||||
|
git lfs track "*.bin"
|
||||||
|
|
||||||
|
# 3. 提交
|
||||||
|
git add .gitattributes
|
||||||
|
git add large-file.psd
|
||||||
|
git commit -m "add large file via LFS"
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、日常运维
|
||||||
|
|
||||||
|
### 查看状态与日志
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/gitea
|
||||||
|
|
||||||
|
# 容器状态
|
||||||
|
docker compose ps
|
||||||
|
|
||||||
|
# 实时日志
|
||||||
|
docker compose logs -f # 所有
|
||||||
|
docker compose logs -f server # 仅 Gitea
|
||||||
|
docker compose logs -f db # 仅 MySQL
|
||||||
|
```
|
||||||
|
|
||||||
|
### 重启 / 停止 / 启动
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose restart # 重启所有
|
||||||
|
docker compose restart server # 仅重启 Gitea
|
||||||
|
docker compose down # 停止并移除容器
|
||||||
|
docker compose up -d # 启动
|
||||||
|
```
|
||||||
|
|
||||||
|
### 升级 Gitea
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/gitea
|
||||||
|
|
||||||
|
# 1. 先备份
|
||||||
|
bash backup.sh
|
||||||
|
|
||||||
|
# 2. 拉取新镜像
|
||||||
|
docker compose pull
|
||||||
|
|
||||||
|
# 3. 重启
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
# 4. 检查日志
|
||||||
|
docker compose logs -f server
|
||||||
|
```
|
||||||
|
|
||||||
|
### 定时自动备份
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 每天凌晨 3 点自动备份
|
||||||
|
crontab -e
|
||||||
|
# 添加:
|
||||||
|
0 3 * * * /opt/gitea/backup.sh >> /var/backups/gitea/cron.log 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
备份内容:
|
||||||
|
- `db_日期.sql.gz` — MySQL 完整转储
|
||||||
|
- `gitea_data_日期.tar.gz` — 仓库 + LFS + 附件 + 头像 (`/var/lib/gitea/`)
|
||||||
|
- `config_日期.tar.gz` — .env + docker-compose.yml + nginx 配置
|
||||||
|
|
||||||
|
### 恢复备份
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/gitea
|
||||||
|
|
||||||
|
# 1. 停止服务
|
||||||
|
docker compose down
|
||||||
|
|
||||||
|
# 2. 恢复 Gitea 数据目录
|
||||||
|
tar xzf /var/backups/gitea/gitea_data_20260406_030000.tar.gz -C /var/lib/
|
||||||
|
|
||||||
|
# 3. 恢复配置
|
||||||
|
tar xzf /var/backups/gitea/config_20260406_030000.tar.gz -C /opt/gitea/
|
||||||
|
|
||||||
|
# 4. 启动 MySQL
|
||||||
|
docker compose up -d db
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
# 5. 恢复数据库
|
||||||
|
gunzip < /var/backups/gitea/db_20260406_030000.sql.gz | \
|
||||||
|
docker compose exec -T db mysql -u root -p"${DB_ROOT_PASSWORD}"
|
||||||
|
|
||||||
|
# 6. 启动全部
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、安全加固清单
|
||||||
|
|
||||||
|
- [ ] 域名已启用 HTTPS(deploy.sh 自动完成)
|
||||||
|
- [ ] SSL 证书自动续期(deploy.sh 自动配置 cron)
|
||||||
|
- [ ] 关闭公开注册(`DISABLE_REGISTRATION=true`)
|
||||||
|
- [ ] 启用登录才能浏览(`REQUIRE_SIGNIN=true`)
|
||||||
|
- [ ] 配置防火墙仅开放 80/443/2222(deploy.sh 自动完成)
|
||||||
|
- [ ] 云安全组已放行对应端口
|
||||||
|
- [ ] 服务器 SSH 改为密钥登录,禁用密码
|
||||||
|
- [ ] 定时备份已配置
|
||||||
|
- [ ] MySQL root 密码为随机强密码(deploy.sh 自动生成)
|
||||||
|
- [ ] Gitea HTTP 端口仅监听 127.0.0.1(不对外暴露)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、常见问题
|
||||||
|
|
||||||
|
**Q: SSL 证书申请失败?**
|
||||||
|
- 确认域名 A 记录已解析到服务器 IP(用 `dig git.yourdomain.com` 验证)
|
||||||
|
- 确认 80 端口可从外网访问(云安全组 + 防火墙)
|
||||||
|
- 等 DNS 生效后重新运行 `bash deploy.sh`
|
||||||
|
|
||||||
|
**Q: 忘记管理员密码?**
|
||||||
|
```bash
|
||||||
|
docker compose exec server gitea admin user change-password -u 管理员用户名 -p 新密码
|
||||||
|
```
|
||||||
|
|
||||||
|
**Q: Git LFS push 失败 / 超时?**
|
||||||
|
- Nginx 已配置 `client_max_body_size 4G`(LFS 路径单独配置)
|
||||||
|
- 如仍超时,检查服务器带宽和磁盘空间
|
||||||
|
|
||||||
|
**Q: GPG 签名的提交不显示 "Verified"?**
|
||||||
|
- 确认 GPG 公钥已添加到 Gitea 用户设置
|
||||||
|
- 确认 Git 提交邮箱与 GPG 密钥邮箱一致
|
||||||
|
|
||||||
|
**Q: 如何迁移到新服务器?**
|
||||||
|
1. 旧服务器执行 `bash backup.sh`
|
||||||
|
2. 复制部署目录 `/opt/gitea/`、数据 `/var/lib/gitea/`、备份 `/var/backups/gitea/` 到新服务器
|
||||||
|
3. 新服务器执行 `bash deploy.sh`
|
||||||
|
4. 修改域名 DNS 指向新服务器 IP
|
||||||
|
5. 重新申请 SSL 证书:`certbot certonly --webroot -w /var/www/certbot -d 域名`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 服务器目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
/opt/gitea/ # 部署目录(INSTALL_DIR)
|
||||||
|
├── docker-compose.yml # Gitea + MySQL 容器编排
|
||||||
|
├── .env.example # 环境变量模板
|
||||||
|
├── .env # 运行时配置(自动生成)
|
||||||
|
├── deploy.sh # 全新服务器一键部署脚本
|
||||||
|
├── backup.sh # MySQL + 数据备份脚本
|
||||||
|
├── .gitignore
|
||||||
|
├── README.md
|
||||||
|
└── nginx/
|
||||||
|
└── gitea.conf # Nginx HTTPS 反向代理模板
|
||||||
|
|
||||||
|
/var/lib/gitea/ # Gitea 应用数据(GITEA_DATA_DIR)
|
||||||
|
├── gitea/
|
||||||
|
│ ├── conf/app.ini # Gitea 运行配置(首次安装后生成)
|
||||||
|
│ ├── repositories/ # Git 仓库文件
|
||||||
|
│ ├── lfs/ # Git LFS 对象存储
|
||||||
|
│ ├── attachments/ # Issue / Release 附件
|
||||||
|
│ ├── avatars/ # 用户头像
|
||||||
|
│ └── ... # 其他运行时数据
|
||||||
|
├── git/ # Git 用户 home
|
||||||
|
└── ssh/ # SSH 密钥
|
||||||
|
|
||||||
|
/var/lib/mysql/gitea/ # MySQL 数据文件(MYSQL_DATA_DIR)
|
||||||
|
|
||||||
|
/var/backups/gitea/ # 备份文件(BACKUP_DIR)
|
||||||
|
├── db_日期.sql.gz # MySQL 转储
|
||||||
|
├── gitea_data_日期.tar.gz # Gitea 数据快照
|
||||||
|
├── config_日期.tar.gz # 配置备份
|
||||||
|
└── cron.log # 定时备份日志
|
||||||
|
|
||||||
|
/etc/nginx/sites-available/gitea # Nginx HTTPS 配置(由 deploy.sh 生成)
|
||||||
|
/etc/letsencrypt/live/域名/ # SSL 证书(由 Certbot 管理)
|
||||||
|
```
|
||||||
67
gitea/backup.sh
Normal file
67
gitea/backup.sh
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Gitea 备份脚本 (MySQL 版)
|
||||||
|
# 备份内容:MySQL 数据库 + Gitea 数据(含 LFS) + 配置
|
||||||
|
# 定时执行: crontab -e → 0 3 * * * /opt/gitea/backup.sh
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
# 加载配置
|
||||||
|
if [ ! -f .env ]; then
|
||||||
|
echo "[ERROR] .env 文件不存在" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
set -a
|
||||||
|
source .env
|
||||||
|
set +a
|
||||||
|
|
||||||
|
BACKUP_DIR="${BACKUP_DIR:-/var/backups/gitea}"
|
||||||
|
GITEA_DATA_DIR="${GITEA_DATA_DIR:-/var/lib/gitea}"
|
||||||
|
DATE=$(date +%Y%m%d_%H%M%S)
|
||||||
|
KEEP_DAYS=30
|
||||||
|
|
||||||
|
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
|
||||||
|
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
|
||||||
|
# 1. 备份 MySQL 数据库
|
||||||
|
log "正在备份 MySQL 数据库..."
|
||||||
|
docker compose exec -T db mysqldump \
|
||||||
|
-u root -p"${DB_ROOT_PASSWORD}" \
|
||||||
|
--single-transaction \
|
||||||
|
--routines \
|
||||||
|
--triggers \
|
||||||
|
--databases gitea \
|
||||||
|
| gzip > "${BACKUP_DIR}/db_${DATE}.sql.gz"
|
||||||
|
log "数据库备份完成: db_${DATE}.sql.gz ($(du -h "${BACKUP_DIR}/db_${DATE}.sql.gz" | cut -f1))"
|
||||||
|
|
||||||
|
# 2. 备份 Gitea 数据(仓库、LFS、附件、头像等)
|
||||||
|
log "正在备份 Gitea 数据目录(含 LFS)..."
|
||||||
|
tar czf "${BACKUP_DIR}/gitea_data_${DATE}.tar.gz" \
|
||||||
|
-C "$(dirname "$GITEA_DATA_DIR")" \
|
||||||
|
"$(basename "$GITEA_DATA_DIR")"
|
||||||
|
log "数据目录备份完成: gitea_data_${DATE}.tar.gz ($(du -h "${BACKUP_DIR}/gitea_data_${DATE}.tar.gz" | cut -f1))"
|
||||||
|
|
||||||
|
# 3. 备份配置文件
|
||||||
|
log "正在备份配置文件..."
|
||||||
|
tar czf "${BACKUP_DIR}/config_${DATE}.tar.gz" \
|
||||||
|
-C "$SCRIPT_DIR" \
|
||||||
|
.env docker-compose.yml nginx/
|
||||||
|
log "配置备份完成: config_${DATE}.tar.gz"
|
||||||
|
|
||||||
|
# 4. 清理过期备份
|
||||||
|
log "清理 ${KEEP_DAYS} 天前的备份..."
|
||||||
|
deleted=$(find "$BACKUP_DIR" -type f -mtime +${KEEP_DAYS} -print -delete | wc -l)
|
||||||
|
log "已清理 ${deleted} 个过期文件"
|
||||||
|
|
||||||
|
# 5. 输出备份摘要
|
||||||
|
echo ""
|
||||||
|
log "===== 备份完成 ====="
|
||||||
|
log "备份目录: ${BACKUP_DIR}/"
|
||||||
|
ls -lh "${BACKUP_DIR}/"*"${DATE}"* 2>/dev/null || true
|
||||||
|
echo ""
|
||||||
|
log "总备份空间占用: $(du -sh "${BACKUP_DIR}" | cut -f1)"
|
||||||
479
gitea/deploy.sh
Normal file
479
gitea/deploy.sh
Normal file
@@ -0,0 +1,479 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Gitea 全新服务器一键部署脚本
|
||||||
|
# 适用于 Ubuntu 20.04+ / Debian 11+
|
||||||
|
# 包含:系统更新 → Docker → Nginx → Certbot → Gitea + MySQL
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
CYAN='\033[0;36m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
log() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||||
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||||
|
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||||
|
step() { echo -e "\n${CYAN}========== $* ==========${NC}"; }
|
||||||
|
|
||||||
|
# ===== 检查 root 权限 =====
|
||||||
|
check_root() {
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
error "请使用 root 用户运行此脚本: sudo bash deploy.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===== 1. 系统初始化 =====
|
||||||
|
init_system() {
|
||||||
|
step "1/8 系统初始化"
|
||||||
|
|
||||||
|
# 检测包管理器
|
||||||
|
if command -v apt-get &> /dev/null; then
|
||||||
|
PKG_MGR="apt"
|
||||||
|
elif command -v dnf &> /dev/null; then
|
||||||
|
PKG_MGR="dnf"
|
||||||
|
elif command -v yum &> /dev/null; then
|
||||||
|
PKG_MGR="yum"
|
||||||
|
else
|
||||||
|
error "不支持的系统,需要 apt/dnf/yum 包管理器"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "检测到包管理器: $PKG_MGR"
|
||||||
|
log "正在更新系统软件包..."
|
||||||
|
|
||||||
|
case "$PKG_MGR" in
|
||||||
|
apt)
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get upgrade -y -qq
|
||||||
|
apt-get install -y -qq curl wget git gnupg2 ca-certificates \
|
||||||
|
lsb-release software-properties-common openssl cron
|
||||||
|
;;
|
||||||
|
dnf|yum)
|
||||||
|
$PKG_MGR update -y -q
|
||||||
|
$PKG_MGR install -y -q curl wget git gnupg2 ca-certificates openssl cronie
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# 设置时区
|
||||||
|
if [ ! -f /etc/timezone ] || [ "$(cat /etc/timezone 2>/dev/null)" != "Asia/Shanghai" ]; then
|
||||||
|
timedatectl set-timezone Asia/Shanghai 2>/dev/null || true
|
||||||
|
log "时区已设置为 Asia/Shanghai"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "系统初始化完成"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===== 配置 Docker 镜像加速 =====
|
||||||
|
configure_docker_mirrors() {
|
||||||
|
local mirrors="${DOCKER_REGISTRY_MIRRORS:-}"
|
||||||
|
if [ -z "$mirrors" ]; then
|
||||||
|
log "未配置 DOCKER_REGISTRY_MIRRORS,跳过镜像加速"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p /etc/docker
|
||||||
|
|
||||||
|
# 将逗号分隔的镜像列表转为 JSON 数组
|
||||||
|
local json_array
|
||||||
|
json_array=$(echo "$mirrors" | tr ',' '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep -v '^$' | awk '{printf "\"%s\",", $0}' | sed 's/,$//')
|
||||||
|
|
||||||
|
local need_restart=0
|
||||||
|
|
||||||
|
if [ -f /etc/docker/daemon.json ]; then
|
||||||
|
# 已有配置文件,检查是否需要更新
|
||||||
|
if ! grep -q "registry-mirrors" /etc/docker/daemon.json; then
|
||||||
|
need_restart=1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
need_restart=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$need_restart" -eq 1 ]; then
|
||||||
|
# 生成或覆盖 daemon.json(保留 log 配置)
|
||||||
|
cat > /etc/docker/daemon.json <<EOF
|
||||||
|
{
|
||||||
|
"registry-mirrors": [${json_array}],
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": {
|
||||||
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
log "Docker 镜像加速已配置:"
|
||||||
|
echo "$mirrors" | tr ',' '\n' | sed 's/^/ → /'
|
||||||
|
# 重启 Docker 使配置生效
|
||||||
|
systemctl restart docker
|
||||||
|
log "Docker 已重启以应用镜像加速"
|
||||||
|
else
|
||||||
|
log "Docker 镜像加速已存在,跳过"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===== 2. 安装 Docker =====
|
||||||
|
install_docker() {
|
||||||
|
step "2/8 安装 Docker"
|
||||||
|
|
||||||
|
if command -v docker &> /dev/null; then
|
||||||
|
log "Docker 已安装: $(docker --version)"
|
||||||
|
else
|
||||||
|
log "正在安装 Docker..."
|
||||||
|
curl -fsSL https://get.docker.com | bash
|
||||||
|
log "Docker 安装完成: $(docker --version)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 确保 Docker 服务运行
|
||||||
|
systemctl enable --now docker
|
||||||
|
log "Docker 服务已启动"
|
||||||
|
|
||||||
|
# 检查 Docker Compose V2
|
||||||
|
if ! docker compose version &> /dev/null; then
|
||||||
|
error "Docker Compose V2 不可用"
|
||||||
|
error "请手动安装: apt install docker-compose-plugin"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
log "Docker Compose 已就绪: $(docker compose version --short)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===== 3. 安装 Nginx =====
|
||||||
|
install_nginx() {
|
||||||
|
step "3/8 安装 Nginx"
|
||||||
|
|
||||||
|
if command -v nginx &> /dev/null; then
|
||||||
|
log "Nginx 已安装: $(nginx -v 2>&1)"
|
||||||
|
else
|
||||||
|
log "正在安装 Nginx..."
|
||||||
|
case "$PKG_MGR" in
|
||||||
|
apt)
|
||||||
|
apt-get install -y -qq nginx
|
||||||
|
;;
|
||||||
|
dnf|yum)
|
||||||
|
$PKG_MGR install -y -q nginx
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
log "Nginx 安装完成"
|
||||||
|
fi
|
||||||
|
|
||||||
|
systemctl enable --now nginx
|
||||||
|
|
||||||
|
# 确保 Nginx 配置目录结构存在
|
||||||
|
mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled /var/www/certbot
|
||||||
|
|
||||||
|
# 确保 nginx.conf 包含 sites-enabled
|
||||||
|
if ! grep -q "sites-enabled" /etc/nginx/nginx.conf; then
|
||||||
|
# 在 http { } 块内添加 include
|
||||||
|
sed -i '/^http {/a \ include /etc/nginx/sites-enabled/*;' /etc/nginx/nginx.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Nginx 配置就绪"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===== 4. 初始化 .env =====
|
||||||
|
init_env() {
|
||||||
|
step "4/8 初始化配置"
|
||||||
|
|
||||||
|
if [ ! -f .env ]; then
|
||||||
|
if [ ! -f .env.example ]; then
|
||||||
|
error "缺少 .env.example 模板文件"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cp .env.example .env
|
||||||
|
|
||||||
|
# 自动生成随机密码
|
||||||
|
DB_PASS=$(openssl rand -base64 24 | tr -d '/+=\n' | head -c 32)
|
||||||
|
DB_ROOT_PASS=$(openssl rand -base64 24 | tr -d '/+=\n' | head -c 32)
|
||||||
|
|
||||||
|
sed -i "s/请替换为强密码/${DB_PASS}/" .env
|
||||||
|
sed -i "s/请替换为ROOT强密码/${DB_ROOT_PASS}/" .env
|
||||||
|
|
||||||
|
log "已生成 .env 文件,数据库密码已随机生成"
|
||||||
|
echo ""
|
||||||
|
warn "┌─────────────────────────────────────────────┐"
|
||||||
|
warn "│ 请编辑 .env 文件,至少修改以下配置: │"
|
||||||
|
warn "│ │"
|
||||||
|
warn "│ GITEA_DOMAIN=你的域名 │"
|
||||||
|
warn "│ CERTBOT_EMAIL=你的邮箱 │"
|
||||||
|
warn "│ │"
|
||||||
|
warn "│ 编辑命令: vi $SCRIPT_DIR/.env │"
|
||||||
|
warn "│ 编辑完成后重新运行: bash deploy.sh │"
|
||||||
|
warn "└─────────────────────────────────────────────┘"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 加载并验证配置
|
||||||
|
set -a
|
||||||
|
source .env
|
||||||
|
set +a
|
||||||
|
|
||||||
|
local has_error=0
|
||||||
|
|
||||||
|
if [[ -z "${GITEA_DOMAIN:-}" ]] || [[ "${GITEA_DOMAIN}" == "git.example.com" ]]; then
|
||||||
|
error "请在 .env 中将 GITEA_DOMAIN 修改为你的实际域名"
|
||||||
|
has_error=1
|
||||||
|
fi
|
||||||
|
if [[ -z "${CERTBOT_EMAIL:-}" ]] || [[ "${CERTBOT_EMAIL}" == "admin@example.com" ]]; then
|
||||||
|
error "请在 .env 中将 CERTBOT_EMAIL 修改为你的实际邮箱"
|
||||||
|
has_error=1
|
||||||
|
fi
|
||||||
|
if [[ "${DB_PASSWORD:-}" == *"请替换"* ]] || [[ -z "${DB_PASSWORD:-}" ]]; then
|
||||||
|
error "DB_PASSWORD 未正确设置"
|
||||||
|
has_error=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$has_error" -eq 1 ]; then
|
||||||
|
error "请修改 .env 后重新运行: vi $SCRIPT_DIR/.env"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "配置检查通过: 域名=${GITEA_DOMAIN}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===== 5. 创建数据目录 =====
|
||||||
|
create_dirs() {
|
||||||
|
step "5/8 创建数据目录"
|
||||||
|
|
||||||
|
local gitea_data="${GITEA_DATA_DIR:-/var/lib/gitea}"
|
||||||
|
local mysql_data="${MYSQL_DATA_DIR:-/var/lib/mysql/gitea}"
|
||||||
|
local backup_dir="${BACKUP_DIR:-/var/backups/gitea}"
|
||||||
|
|
||||||
|
mkdir -p "$gitea_data" "$mysql_data" "$backup_dir"
|
||||||
|
|
||||||
|
# Gitea 容器以 UID=1000 运行,确保数据目录归属正确
|
||||||
|
chown -R 1000:1000 "$gitea_data"
|
||||||
|
# MySQL 容器以 mysql(999) 运行
|
||||||
|
chown -R 999:999 "$mysql_data"
|
||||||
|
|
||||||
|
log "数据目录已就绪:"
|
||||||
|
log " Gitea 数据: $gitea_data"
|
||||||
|
log " MySQL 数据: $mysql_data"
|
||||||
|
log " 备份目录: $backup_dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===== 6. 配置防火墙 =====
|
||||||
|
setup_firewall() {
|
||||||
|
step "6/8 配置防火墙"
|
||||||
|
|
||||||
|
local ssh_port="${SSH_PORT:-2222}"
|
||||||
|
|
||||||
|
if command -v ufw &> /dev/null; then
|
||||||
|
ufw --force enable 2>/dev/null || true
|
||||||
|
ufw allow ssh comment "SSH" 2>/dev/null || true
|
||||||
|
ufw allow 80/tcp comment "HTTP" 2>/dev/null || true
|
||||||
|
ufw allow 443/tcp comment "HTTPS" 2>/dev/null || true
|
||||||
|
ufw allow "$ssh_port"/tcp comment "Gitea SSH" 2>/dev/null || true
|
||||||
|
ufw reload 2>/dev/null || true
|
||||||
|
log "UFW 防火墙规则已添加 (22, 80, 443, $ssh_port)"
|
||||||
|
elif command -v firewall-cmd &> /dev/null; then
|
||||||
|
systemctl enable --now firewalld 2>/dev/null || true
|
||||||
|
firewall-cmd --permanent --add-service=ssh 2>/dev/null || true
|
||||||
|
firewall-cmd --permanent --add-service=http 2>/dev/null || true
|
||||||
|
firewall-cmd --permanent --add-service=https 2>/dev/null || true
|
||||||
|
firewall-cmd --permanent --add-port="$ssh_port"/tcp 2>/dev/null || true
|
||||||
|
firewall-cmd --reload 2>/dev/null || true
|
||||||
|
log "Firewalld 规则已添加 (22, 80, 443, $ssh_port)"
|
||||||
|
else
|
||||||
|
warn "未检测到防火墙工具,请手动开放端口: 22, 80, 443, $ssh_port"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===== 7. 配置 Nginx + SSL =====
|
||||||
|
setup_ssl() {
|
||||||
|
step "7/8 配置 HTTPS (Nginx + Let's Encrypt)"
|
||||||
|
|
||||||
|
local domain="${GITEA_DOMAIN}"
|
||||||
|
local email="${CERTBOT_EMAIL}"
|
||||||
|
|
||||||
|
# 安装 certbot
|
||||||
|
if ! command -v certbot &> /dev/null; then
|
||||||
|
log "正在安装 Certbot..."
|
||||||
|
case "$PKG_MGR" in
|
||||||
|
apt)
|
||||||
|
apt-get install -y -qq certbot python3-certbot-nginx
|
||||||
|
;;
|
||||||
|
dnf)
|
||||||
|
dnf install -y -q certbot python3-certbot-nginx
|
||||||
|
;;
|
||||||
|
yum)
|
||||||
|
yum install -y -q certbot python3-certbot-nginx
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
log "Certbot 已就绪"
|
||||||
|
|
||||||
|
# 部署临时 Nginx 配置(仅 HTTP,用于证书验证)
|
||||||
|
cat > /etc/nginx/sites-available/gitea <<NGINX_TEMP
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name ${domain};
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
return 200 'Gitea is being configured...';
|
||||||
|
add_header Content-Type text/plain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NGINX_TEMP
|
||||||
|
|
||||||
|
ln -sf /etc/nginx/sites-available/gitea /etc/nginx/sites-enabled/gitea
|
||||||
|
# 移除默认站点避免冲突
|
||||||
|
rm -f /etc/nginx/sites-enabled/default
|
||||||
|
nginx -t && systemctl reload nginx
|
||||||
|
|
||||||
|
# 申请 SSL 证书
|
||||||
|
if [ ! -d "/etc/letsencrypt/live/${domain}" ]; then
|
||||||
|
log "正在申请 SSL 证书: ${domain} ..."
|
||||||
|
if ! certbot certonly --webroot \
|
||||||
|
-w /var/www/certbot \
|
||||||
|
-d "${domain}" \
|
||||||
|
--email "${email}" \
|
||||||
|
--agree-tos \
|
||||||
|
--non-interactive \
|
||||||
|
--no-eff-email; then
|
||||||
|
error "SSL 证书申请失败!"
|
||||||
|
error "请确认:"
|
||||||
|
error " 1. 域名 ${domain} 已解析到本服务器 IP"
|
||||||
|
error " 2. 服务器 80 端口可从外网访问"
|
||||||
|
error "解决后重新运行 deploy.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
log "SSL 证书申请成功"
|
||||||
|
else
|
||||||
|
log "SSL 证书已存在,跳过申请"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 部署正式 Nginx 配置
|
||||||
|
cp "$SCRIPT_DIR/nginx/gitea.conf" /etc/nginx/sites-available/gitea
|
||||||
|
sed -i "s/__GITEA_DOMAIN__/${domain}/g" /etc/nginx/sites-available/gitea
|
||||||
|
|
||||||
|
nginx -t
|
||||||
|
systemctl reload nginx
|
||||||
|
log "Nginx HTTPS 反向代理配置完成"
|
||||||
|
|
||||||
|
# 设置证书自动续期
|
||||||
|
if ! crontab -l 2>/dev/null | grep -q "certbot renew"; then
|
||||||
|
(crontab -l 2>/dev/null; echo "0 3 * * * certbot renew --quiet --post-hook 'systemctl reload nginx'") | crontab -
|
||||||
|
log "已配置 SSL 证书自动续期 (每天 03:00 检查)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===== 8. 启动服务 =====
|
||||||
|
start_services() {
|
||||||
|
step "8/8 启动 Gitea 服务"
|
||||||
|
|
||||||
|
log "正在拉取镜像(首次可能较慢)..."
|
||||||
|
docker compose pull
|
||||||
|
|
||||||
|
log "正在启动容器..."
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
log "等待 MySQL 就绪..."
|
||||||
|
local max_wait=60
|
||||||
|
for i in $(seq 1 $max_wait); do
|
||||||
|
if docker compose exec -T db mysqladmin ping -h localhost -u root -p"${DB_ROOT_PASSWORD}" --silent &> /dev/null; then
|
||||||
|
log "MySQL 已就绪"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if [ "$i" -eq "$max_wait" ]; then
|
||||||
|
warn "MySQL 启动超时,请检查日志: docker compose logs db"
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
log "等待 Gitea 就绪..."
|
||||||
|
for i in $(seq 1 30); do
|
||||||
|
if curl -sf http://127.0.0.1:3000/api/v1/version &> /dev/null; then
|
||||||
|
log "Gitea 启动成功!"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if [ "$i" -eq 30 ]; then
|
||||||
|
warn "Gitea 可能仍在初始化,请稍后检查"
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===== 输出完成信息 =====
|
||||||
|
show_info() {
|
||||||
|
set -a
|
||||||
|
source .env
|
||||||
|
set +a
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}╔══════════════════════════════════════════════════════╗${NC}"
|
||||||
|
echo -e "${GREEN}║ Gitea 部署完成! ║${NC}"
|
||||||
|
echo -e "${GREEN}╠══════════════════════════════════════════════════════╣${NC}"
|
||||||
|
echo -e "${GREEN}║${NC}"
|
||||||
|
echo -e "${GREEN}║${NC} Web 访问: ${CYAN}https://${GITEA_DOMAIN}${NC}"
|
||||||
|
echo -e "${GREEN}║${NC} SSH 克隆: ${CYAN}ssh://git@${GITEA_DOMAIN}:${SSH_PORT:-2222}/用户名/仓库.git${NC}"
|
||||||
|
echo -e "${GREEN}║${NC} HTTPS 克隆: ${CYAN}https://${GITEA_DOMAIN}/用户名/仓库.git${NC}"
|
||||||
|
echo -e "${GREEN}║${NC}"
|
||||||
|
echo -e "${GREEN}║${NC} 已启用功能:"
|
||||||
|
echo -e "${GREEN}║${NC} ✓ HTTPS (Let's Encrypt 自动续期)"
|
||||||
|
echo -e "${GREEN}║${NC} ✓ Git LFS 大文件存储"
|
||||||
|
echo -e "${GREEN}║${NC} ✓ SSH 密钥认证"
|
||||||
|
echo -e "${GREEN}║${NC} ✓ GPG 签名验证"
|
||||||
|
echo -e "${GREEN}║${NC} ✓ MySQL 8.0 数据库"
|
||||||
|
echo -e "${GREEN}║${NC}"
|
||||||
|
echo -e "${GREEN}║${NC} 首次访问说明:"
|
||||||
|
echo -e "${GREEN}║${NC} 1. 浏览器打开 https://${GITEA_DOMAIN}"
|
||||||
|
echo -e "${GREEN}║${NC} 2. 进入安装向导(数据库配置已自动填写)"
|
||||||
|
echo -e "${GREEN}║${NC} 3. 创建管理员账户"
|
||||||
|
echo -e "${GREEN}║${NC} 4. 完成安装"
|
||||||
|
echo -e "${GREEN}║${NC}"
|
||||||
|
echo -e "${GREEN}║${NC} 常用命令:"
|
||||||
|
echo -e "${GREEN}║${NC} 查看日志: cd ${INSTALL_DIR:-/opt/gitea} && docker compose logs -f"
|
||||||
|
echo -e "${GREEN}║${NC} 重启服务: cd ${INSTALL_DIR:-/opt/gitea} && docker compose restart"
|
||||||
|
echo -e "${GREEN}║${NC} 备份数据: bash ${INSTALL_DIR:-/opt/gitea}/backup.sh"
|
||||||
|
echo -e "${GREEN}║${NC}"
|
||||||
|
echo -e "${GREEN}║${NC} 服务器目录:"
|
||||||
|
echo -e "${GREEN}║${NC} 部署文件: ${INSTALL_DIR:-/opt/gitea}"
|
||||||
|
echo -e "${GREEN}║${NC} Gitea 数据: ${GITEA_DATA_DIR:-/var/lib/gitea}"
|
||||||
|
echo -e "${GREEN}║${NC} MySQL 数据: ${MYSQL_DATA_DIR:-/var/lib/mysql/gitea}"
|
||||||
|
echo -e "${GREEN}║${NC} 备份目录: ${BACKUP_DIR:-/var/backups/gitea}"
|
||||||
|
echo -e "${GREEN}║${NC} SSL 证书: /etc/letsencrypt/live/${GITEA_DOMAIN}"
|
||||||
|
echo -e "${GREEN}║${NC} Nginx 配置: /etc/nginx/sites-available/gitea"
|
||||||
|
echo -e "${GREEN}║${NC}"
|
||||||
|
echo -e "${GREEN}╚══════════════════════════════════════════════════════╝${NC}"
|
||||||
|
echo ""
|
||||||
|
warn "重要:创建管理员后请编辑 .env 将 DISABLE_REGISTRATION 改为 true 并重启"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===== 主流程 =====
|
||||||
|
main() {
|
||||||
|
echo -e "${CYAN}"
|
||||||
|
echo " ____ _ _"
|
||||||
|
echo " / ___|(_) |_ ___ __ _"
|
||||||
|
echo "| | _ | | __/ _ \\/ _\` |"
|
||||||
|
echo "| |_| || | || __/ (_| |"
|
||||||
|
echo " \\____|_|\\__\\___|\\__,_| Deploy Script"
|
||||||
|
echo -e "${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
check_root
|
||||||
|
init_system
|
||||||
|
install_docker
|
||||||
|
install_nginx
|
||||||
|
init_env
|
||||||
|
configure_docker_mirrors
|
||||||
|
create_dirs
|
||||||
|
setup_firewall
|
||||||
|
setup_ssl
|
||||||
|
start_services
|
||||||
|
show_info
|
||||||
|
|
||||||
|
log "===== 全部部署完成 ====="
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
82
gitea/docker-compose.yml
Normal file
82
gitea/docker-compose.yml
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
networks:
|
||||||
|
gitea:
|
||||||
|
external: false
|
||||||
|
|
||||||
|
services:
|
||||||
|
server:
|
||||||
|
image: ${GITEA_IMAGE:-gitea/gitea:1.25}
|
||||||
|
container_name: gitea
|
||||||
|
environment:
|
||||||
|
- USER_UID=1000
|
||||||
|
- USER_GID=1000
|
||||||
|
# ---- 数据库 (MySQL) ----
|
||||||
|
- GITEA__database__DB_TYPE=mysql
|
||||||
|
- GITEA__database__HOST=db:3306
|
||||||
|
- GITEA__database__NAME=gitea
|
||||||
|
- GITEA__database__USER=gitea
|
||||||
|
- GITEA__database__PASSWD=${DB_PASSWORD}
|
||||||
|
# ---- 域名与访问 ----
|
||||||
|
- GITEA__server__DOMAIN=${GITEA_DOMAIN}
|
||||||
|
- GITEA__server__SSH_DOMAIN=${GITEA_DOMAIN}
|
||||||
|
- GITEA__server__ROOT_URL=https://${GITEA_DOMAIN}
|
||||||
|
- GITEA__server__HTTP_PORT=3000
|
||||||
|
- GITEA__server__SSH_PORT=${SSH_PORT:-2222}
|
||||||
|
- GITEA__server__SSH_LISTEN_PORT=2222
|
||||||
|
- GITEA__server__LFS_START_SERVER=true
|
||||||
|
# ---- Git LFS ----
|
||||||
|
- GITEA__lfs__STORAGE_TYPE=local
|
||||||
|
# ---- SSH 密钥 ----
|
||||||
|
- GITEA__server__START_SSH_SERVER=true
|
||||||
|
- GITEA__server__DISABLE_SSH=false
|
||||||
|
# ---- GPG 签名 ----
|
||||||
|
- GITEA__repository__ENABLE_PUSH_CREATE_USER=true
|
||||||
|
- GITEA__repository_0X2E_signing__SIGNING_KEY=default
|
||||||
|
- GITEA__repository_0X2E_signing__SIGNING_NAME=${GPG_SIGNING_NAME:-Gitea}
|
||||||
|
- GITEA__repository_0X2E_signing__SIGNING_EMAIL=${GPG_SIGNING_EMAIL:-gitea@localhost}
|
||||||
|
- GITEA__repository_0X2E_signing__INITIAL_COMMIT=always
|
||||||
|
- GITEA__repository_0X2E_signing__DEFAULT_TRUST_MODEL=committer
|
||||||
|
# ---- 安全 ----
|
||||||
|
- GITEA__service__DISABLE_REGISTRATION=${DISABLE_REGISTRATION:-false}
|
||||||
|
- GITEA__service__REQUIRE_SIGNIN_VIEW=${REQUIRE_SIGNIN:-false}
|
||||||
|
- GITEA__service__DEFAULT_KEEP_EMAIL_PRIVATE=true
|
||||||
|
- GITEA__openid__ENABLE_OPENID_SIGNIN=false
|
||||||
|
- GITEA__mailer__ENABLED=false
|
||||||
|
restart: always
|
||||||
|
networks:
|
||||||
|
- gitea
|
||||||
|
volumes:
|
||||||
|
- ${GITEA_DATA_DIR:-/var/lib/gitea}:/data
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:3000:3000"
|
||||||
|
- "0.0.0.0:${SSH_PORT:-2222}:2222"
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: mysql:8.0
|
||||||
|
container_name: gitea-db
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
|
||||||
|
- MYSQL_USER=gitea
|
||||||
|
- MYSQL_PASSWORD=${DB_PASSWORD}
|
||||||
|
- MYSQL_DATABASE=gitea
|
||||||
|
command: >
|
||||||
|
--character-set-server=utf8mb4
|
||||||
|
--collation-server=utf8mb4_unicode_ci
|
||||||
|
--mysql-native-password=ON
|
||||||
|
--innodb-buffer-pool-size=256M
|
||||||
|
--max-allowed-packet=256M
|
||||||
|
networks:
|
||||||
|
- gitea
|
||||||
|
volumes:
|
||||||
|
- ${MYSQL_DATA_DIR:-/var/lib/mysql/gitea}:/var/lib/mysql
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${DB_ROOT_PASSWORD}"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
start_period: 30s
|
||||||
80
gitea/nginx/gitea.conf
Normal file
80
gitea/nginx/gitea.conf
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# Gitea Nginx 反向代理配置
|
||||||
|
# 由 deploy.sh 自动部署到 /etc/nginx/sites-available/gitea
|
||||||
|
# __GITEA_DOMAIN__ 会被脚本替换为实际域名
|
||||||
|
|
||||||
|
# HTTP → HTTPS 重定向
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name __GITEA_DOMAIN__;
|
||||||
|
|
||||||
|
# Let's Encrypt 证书验证
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# HTTPS 主站点
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
listen [::]:443 ssl http2;
|
||||||
|
server_name __GITEA_DOMAIN__;
|
||||||
|
|
||||||
|
# SSL 证书(Certbot 自动管理)
|
||||||
|
ssl_certificate /etc/letsencrypt/live/__GITEA_DOMAIN__/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/__GITEA_DOMAIN__/privkey.pem;
|
||||||
|
|
||||||
|
# SSL 安全配置
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
|
||||||
|
# HSTS(启用后浏览器会强制使用 HTTPS)
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
|
||||||
|
|
||||||
|
# 安全头
|
||||||
|
add_header X-Frame-Options SAMEORIGIN always;
|
||||||
|
add_header X-Content-Type-Options nosniff always;
|
||||||
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
|
add_header Referrer-Policy strict-origin-when-cross-origin always;
|
||||||
|
|
||||||
|
# Git LFS 和大仓库推送需要足够大的 body 限制
|
||||||
|
client_max_body_size 512M;
|
||||||
|
|
||||||
|
# 代理超时(大仓库 clone/push 可能较慢)
|
||||||
|
proxy_connect_timeout 300;
|
||||||
|
proxy_send_timeout 300;
|
||||||
|
proxy_read_timeout 300;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
# WebSocket 支持(Gitea 实时通知)
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $http_connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Git LFS 大文件upload需要特殊处理
|
||||||
|
location ~ ^/.*\.git/info/lfs/ {
|
||||||
|
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;
|
||||||
|
|
||||||
|
# LFS 上传可能很大
|
||||||
|
client_max_body_size 4G;
|
||||||
|
proxy_request_buffering off;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user