一、整体架构
┌──────────────────────────────────────────────────────────┐
│ Gitea (47.115.231.200) │
│ 代码仓库: admin-api / front-api / admin-web │
│ Gitea Actions CI/CD │
├──────────────────────────────────────────────────────────┤
│ Runner (47.122.125.216) │
│ Maven 构建 → npm 构建 → 停服 → 替换 JAR → 启服 │
├──────────────────────────────────────────────────────────┤
│ 部署目标 (47.122.125.216) │
│ /opt/crmeb/admin/ ← admin-api JAR │
│ /opt/crmeb/front/ ← front-api JAR │
│ /opt/crmeb/web/dist/ ← admin-web 静态文件 │
└──────────────────────────────────────────────────────────┘
三台服务器分工:
| 服务器 | 角色 |
| 47.115.231.200 | Gitea 代码托管 + CI 调度 |
| 47.122.125.216 | Runner(构建+部署)+ 生产运行 |
| 39.100.114.100 | Nginx 入口(已有,不变) |
二、Gitea 安装(47.115.231.200)
ssh root@47.115.231.200
# Docker 已装,直接部署
docker run -d \
--name gitea \
--restart always \
-p 3000:3000 \
-p 2222:22 \
-v /data/gitea:/data \
-e GITEA__server__DOMAIN=gitea.ycbat.com \
-e GITEA__server__ROOT_URL=https://gitea.ycbat.com \
-e GITEA__actions__ENABLED=true \
gitea/gitea:latest
# DNS: gitea.ycbat.com → 47.115.231.200
# Nginx 反代在 39.100.114.100 上加一条
Nginx 反代(39.100.114.100 /etc/nginx/conf.d/gitea.ycbat.com.conf):
server {
listen 80;
server_name gitea.ycbat.com;
client_max_body_size 100m;
location / {
proxy_pass http://47.115.231.200: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;
}
}
三、NPM 私服(Verdaccio)
前端依赖统一走私有 NPM 仓库,加速安装并缓存上游包。
3.1 架构
| 层 | IP | 角色 | 配置 |
| Nginx 入口 | 39.100.114.100 | 反向代理 | /etc/nginx/conf.d/npm.ycbat.com.conf |
| Verdaccio | 47.115.231.200 | 私服 | 端口 4873,/data/verdaccio/config.yaml |
3.2 Nginx 反代
# 39.100.114.100 — /etc/nginx/conf.d/npm.ycbat.com.conf
server {
listen 80;
server_name npm.ycbat.com;
client_max_body_size 100m;
location / {
proxy_pass http://47.115.231.200:4873;
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;
}
}
3.3 Verdaccio 配置
# 47.115.231.200 — /data/verdaccio/config.yaml
storage: /data/verdaccio/storage
uplinks:
npmjs:
url: https://registry.npmmirror.com/ # 阿里云镜像
packages:
'@mycompany/*':
access: $all
publish: $authenticated
'**':
access: $all
proxy: npmjs
logs: { type: stdout, format: pretty, level: info }
3.4 客户端配置
# 项目根目录 .npmrc
registry=http://npm.ycbat.com/
3.5 发布私有包
# 首次登录(只需一次)
npm login --registry=http://npm.ycbat.com/
# 发布 @mycompany 作用域包
npm publish --registry=http://npm.ycbat.com/
Verdaccio 进程通过 pm2 守护:pm2 start verdaccio。
四、Runner 安装(47.122.125.216)
Runner 负责执行构建任务,装在生产服务器上,省去跨服务器传 JAR 的步骤。
ssh root@47.122.125.216
# 1. 安装 Maven
apt install -y maven
# 2. 下载 Gitea Actions Runner
curl -L -o /usr/local/bin/act_runner \
https://gitea.com/gitea/act_runner/releases/download/v0.2.11/act_runner-0.2.11-linux-amd64
chmod +x /usr/local/bin/act_runner
# 3. 注册 Runner(先去 Gitea → Site Admin → Runners → 获取 token)
act_runner register \
--instance https://gitea.ycbat.com \
--token <RUNNER_TOKEN> \
--name "prod-runner" \
--labels "prod,ubuntu,maven"
# 4. systemd 守护
cat > /etc/systemd/system/gitea-runner.service << 'EOF'
[Unit]
Description=Gitea Actions Runner
After=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/act_runner daemon
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable gitea-runner
systemctl start gitea-runner
五、代码仓库结构
在 Gitea 上创建 3 个仓库,推送源码:
gitea.ycbat.com/crmeb/
├── admin-api/ # 管理后台 API(Java)
│ ├── src/
│ ├── pom.xml
│ ├── .gitea/workflows/deploy.yml
│ └── .gitea/settings.xml # Maven 私服配置
│
├── front-api/ # 小程序 API(Java)
│ ├── src/
│ ├── pom.xml
│ └── .gitea/workflows/deploy.yml
│
└── admin-web/ # 管理后台前端(Vue.js)
├── src/
├── package.json
├── .npmrc # registry=http://npm.ycbat.com/
└── .gitea/workflows/deploy.yml
六、CI/CD 流水线配置
5.1 admin-api(Java 后端)
# .gitea/workflows/deploy.yml
name: Build & Deploy Admin API
on:
push:
branches: [main]
jobs:
deploy:
runs-on: prod
steps:
- uses: actions/checkout@v4
- name: Build JAR
run: mvn clean package -DskipTests -s .gitea/settings.xml
- name: Stop Service
run: /opt/crmeb/admin/ctl.sh stop || true
- name: Deploy JAR
run: |
cp target/Crmeb-admin.jar /opt/crmeb/admin/
cp target/classes/application-prod.yml /opt/crmeb/admin/ 2>/dev/null || true
- name: Start Service
run: /opt/crmeb/admin/ctl.sh start
- name: Health Check
run: |
sleep 10
curl -sf -o /dev/null https://adminapi.hblj.asia/ && echo "OK" || echo "FAIL"
5.2 front-api(Java 后端)
# .gitea/workflows/deploy.yml
name: Build & Deploy Front API
on:
push:
branches: [main]
jobs:
deploy:
runs-on: prod
steps:
- uses: actions/checkout@v4
- name: Build JAR
run: mvn clean package -DskipTests -s .gitea/settings.xml
- name: Stop Service
run: /opt/crmeb/front/ctl.sh stop || true
- name: Deploy JAR
run: |
cp target/Crmeb-front.jar /opt/crmeb/front/
- name: Start Service
run: /opt/crmeb/front/ctl.sh start
- name: Health Check
run: |
sleep 10
curl -sf -o /dev/null https://miniappapi.hblj.asia/ && echo "OK" || echo "FAIL"
5.3 admin-web(Vue.js 前端)
# .gitea/workflows/deploy.yml
name: Build & Deploy Admin Web
on:
push:
branches: [main]
jobs:
deploy:
runs-on: prod
steps:
- uses: actions/checkout@v4
- name: Install Dependencies
run: npm ci --registry=http://npm.ycbat.com/
- name: Build
run: npm run build:prod
- name: Deploy
run: |
rm -rf /opt/crmeb/web/dist/*
cp -r dist/* /opt/crmeb/web/dist/
- name: Health Check
run: curl -sf -o /dev/null https://admin.hblj.asia/ && echo "OK"
七、Gitea Secrets 配置
仓库 → Settings → Secrets,添加:
| Secret 名 | 值 | 用途 |
| (不需 secrets) | — | Runner 在本机执行,直接读写本地文件 |
因为 Runner 和部署目标在同一台机器,不需要 SCP/SSH 密码。构建产物直接 cp 到目标目录。
八、Maven settings.xml(私服配置)
<!-- .gitea/settings.xml — 仓库根目录 -->
<settings>
<mirrors>
<mirror>
<id>aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Aliyun Maven</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
</settings>
九、实施步骤
Phase 1: 基础设施(1 小时)
├── 47.115.231.200 安装 Gitea
├── 39.100.114.100 配置 gitea.ycbat.com 反代
├── 47.122.125.216 安装 Maven + Runner
└── Gitea 创建组织 crmeb + 3 个仓库
Phase 2: 代码入库(2 小时)
├── 从生产服务器提取源码(反编译或从原始开发环境)
├── admin-api 源码 → git push
├── front-api 源码 → git push
├── admin-web 源码 → git push
└── 每个仓库配置 .gitea/workflows/deploy.yml
Phase 3: 验证(30 分钟)
├── 修改一个无害的改动(如版本号)
├── git push → 观察 Gitea Actions 自动构建
├── 确认服务自动重启
└── 确认 health check 通过
十、Gitea 分支保护
每个仓库 Settings → Branches → 添加规则:
| 规则 | 值 |
| 分支 | main |
| 禁止直接 push | ✅ |
| PR 必须 Approve | 1 人 |
| PR 必须 CI 通过 | ✅ |
日常开发流程:
feature 分支 → 开发 → git push → 创建 PR
→ Gitea Actions 自动测试(不部署)
→ Code Review
→ Merge to main
→ Gitea Actions 自动部署到生产
十一、回滚
# 在 47.122.125.216 上
cd /opt/crmeb/admin
cp Crmeb-admin.jar Crmeb-admin.jar.bak # 部署前 Runner 自动备份
# 回滚
cp Crmeb-admin.jar.bak Crmeb-admin.jar && ./ctl.sh restart
在 deploy.yml 中加入自动备份:
- name: Backup
run: cp /opt/crmeb/admin/Crmeb-admin.jar /opt/crmeb/admin/Crmeb-admin.jar.bak