368 lines
9.8 KiB
Markdown
368 lines
9.8 KiB
Markdown
# 部署文档(JessieGem.zeotaki.com / backend:2088 / frontend:2099)
|
||
|
||
本文档假设目标服务器为 Linux(Ubuntu/Debian 系)。部署目标:
|
||
- 后端 Go 服务监听 `127.0.0.1:2088`
|
||
- 前端 Vite 预览服务监听 `127.0.0.1:2099`
|
||
- Nginx 对外提供 `https://JessieGem.zeotaki.com`,并转发:
|
||
- `/` -> 前端 `2099`
|
||
- `/api/` -> 后端 `2088`
|
||
|
||
> 这样前端请求 `/api/*` 仍然同域,不需要浏览器跨域。
|
||
|
||
---
|
||
|
||
## 0. 服务器前置
|
||
|
||
### 0.1 依赖软件
|
||
在服务器安装:
|
||
- Nginx
|
||
- MySQL(或可访问的 MySQL 实例)
|
||
- Go 1.22+
|
||
- Node.js 20+(用于构建与运行 `vite preview`)
|
||
|
||
Ubuntu 示例:
|
||
```bash
|
||
sudo apt update
|
||
sudo apt install -y nginx git
|
||
```
|
||
|
||
Go/Node 的安装方式你可按服务器习惯来(官方包、nvm、asdf 都可),但要满足版本要求:
|
||
- Go:`go version` >= 1.22
|
||
- Node:`node -v` >= 20
|
||
|
||
### 0.2 端口规划与防火墙
|
||
- 对公网开放:80/443
|
||
- 仅本机监听:2088/2099(不要直接暴露公网)
|
||
|
||
如使用 UFW:
|
||
```bash
|
||
sudo ufw allow 80
|
||
sudo ufw allow 443
|
||
sudo ufw enable
|
||
```
|
||
|
||
---
|
||
|
||
## 1. 后端部署(Go / 2088)
|
||
|
||
### 1.1 创建运行用户与目录
|
||
```bash
|
||
sudo useradd -r -s /usr/sbin/nologin cockpit || true
|
||
sudo mkdir -p /opt/jessiegem-cockpit/backend
|
||
sudo mkdir -p /etc/jessiegem-cockpit
|
||
sudo chown -R cockpit:cockpit /opt/jessiegem-cockpit
|
||
```
|
||
|
||
### 1.2 准备后端配置
|
||
后端读取 `backend/configs/config.yaml`(相对工作目录 `./configs`),同时也支持环境变量覆盖(`COCKPIT_` 前缀)。
|
||
|
||
推荐在服务器用独立配置目录 `/etc/jessiegem-cockpit/config.yaml`,然后 systemd 的 `WorkingDirectory` 指向 `/opt/jessiegem-cockpit/backend`,并把配置复制到 `./configs/config.yaml`。
|
||
|
||
创建配置:
|
||
```bash
|
||
sudo mkdir -p /opt/jessiegem-cockpit/backend/configs
|
||
sudo tee /opt/jessiegem-cockpit/backend/configs/config.yaml >/dev/null <<'YAML'
|
||
server:
|
||
addr: "127.0.0.1:2088"
|
||
|
||
db:
|
||
driver: "mysql"
|
||
# 按你的服务器实际 MySQL 修改
|
||
dsn: "root:root@tcp(127.0.0.1:3306)/cockpit?charset=utf8mb4&parseTime=True&loc=Local"
|
||
|
||
auth:
|
||
# 必须替换为强随机串
|
||
accessTokenSecret: "REPLACE_ME_ACCESS"
|
||
refreshTokenSecret: "REPLACE_ME_REFRESH"
|
||
accessTokenTtl: "15m"
|
||
refreshTokenTtl: "720h"
|
||
|
||
cors:
|
||
allowOrigins:
|
||
- "https://JessieGem.zeotaki.com"
|
||
YAML
|
||
|
||
sudo chown -R cockpit:cockpit /opt/jessiegem-cockpit/backend
|
||
sudo chmod 600 /opt/jessiegem-cockpit/backend/configs/config.yaml
|
||
```
|
||
|
||
> 注意:后端启动会自动 AutoMigrate + Seed(包含默认管理员 `admin/admin123`)。生产环境建议你首次登录后立即改密码。
|
||
|
||
### 1.3 systemd 服务(backend)
|
||
创建 `/etc/systemd/system/cockpit-backend.service`:
|
||
```bash
|
||
sudo tee /etc/systemd/system/cockpit-backend.service >/dev/null <<'UNIT'
|
||
[Unit]
|
||
Description=Cockpit Backend (Go)
|
||
After=network.target
|
||
|
||
[Service]
|
||
User=cockpit
|
||
Group=cockpit
|
||
WorkingDirectory=/opt/jessiegem-cockpit/backend
|
||
ExecStart=/opt/jessiegem-cockpit/backend/cockpit-server
|
||
Restart=always
|
||
RestartSec=2
|
||
Environment=GIN_MODE=release
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
UNIT
|
||
```
|
||
|
||
启动:
|
||
```bash
|
||
sudo systemctl daemon-reload
|
||
sudo systemctl enable --now cockpit-backend
|
||
sudo systemctl status cockpit-backend --no-pager
|
||
```
|
||
|
||
日志查看:
|
||
```bash
|
||
journalctl -u cockpit-backend -f
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 前端部署(Vite preview / 2099)
|
||
|
||
前端推荐构建后用 `vite preview` 在本机端口提供服务,再由 Nginx 反代。这样部署简单,但注意 Node 进程稳定性要交给 systemd 管理。
|
||
|
||
### 2.1 构建环境变量(非常重要)
|
||
前端生产构建时需要 `VITE_API_BASE` 指向站点域名(同域走 Nginx `/api` 反代):
|
||
```bash
|
||
export VITE_API_BASE="https://JessieGem.zeotaki.com"
|
||
```
|
||
|
||
### 2.2 systemd 服务(frontend)
|
||
创建目录:
|
||
```bash
|
||
sudo mkdir -p /opt/jessiegem-cockpit/frontend
|
||
sudo chown -R cockpit:cockpit /opt/jessiegem-cockpit/frontend
|
||
```
|
||
|
||
创建 `/etc/systemd/system/cockpit-frontend.service`:
|
||
```bash
|
||
sudo tee /etc/systemd/system/cockpit-frontend.service >/dev/null <<'UNIT'
|
||
[Unit]
|
||
Description=Cockpit Frontend (Vite preview)
|
||
After=network.target
|
||
|
||
[Service]
|
||
User=cockpit
|
||
Group=cockpit
|
||
WorkingDirectory=/opt/jessiegem-cockpit/frontend
|
||
Environment=NODE_ENV=production
|
||
Environment=HOST=127.0.0.1
|
||
Environment=PORT=2099
|
||
ExecStart=/usr/bin/npm run preview -- --host 127.0.0.1 --port 2099 --strictPort
|
||
Restart=always
|
||
RestartSec=2
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
UNIT
|
||
```
|
||
|
||
启动:
|
||
```bash
|
||
sudo systemctl daemon-reload
|
||
sudo systemctl enable --now cockpit-frontend
|
||
sudo systemctl status cockpit-frontend --no-pager
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Nginx 配置(JessieGem.zeotaki.com)
|
||
|
||
目标:
|
||
- `/` -> `http://127.0.0.1:2099`
|
||
- `/api/` -> `http://127.0.0.1:2088`
|
||
|
||
创建站点配置:
|
||
```bash
|
||
sudo tee /etc/nginx/sites-available/jessiegem-cockpit.conf >/dev/null <<'NGINX'
|
||
server {
|
||
listen 80;
|
||
server_name JessieGem.zeotaki.com;
|
||
|
||
# 如果你使用 certbot,建议这里仅用于 http->https 跳转
|
||
location / {
|
||
return 301 https://$host$request_uri;
|
||
}
|
||
}
|
||
|
||
server {
|
||
listen 443 ssl http2;
|
||
server_name JessieGem.zeotaki.com;
|
||
|
||
# 证书路径按你服务器实际情况填写(certbot 默认示例)
|
||
ssl_certificate /etc/letsencrypt/live/JessieGem.zeotaki.com/fullchain.pem;
|
||
ssl_certificate_key /etc/letsencrypt/live/JessieGem.zeotaki.com/privkey.pem;
|
||
|
||
client_max_body_size 50m;
|
||
|
||
# 前端
|
||
location / {
|
||
proxy_pass http://127.0.0.1:2099;
|
||
proxy_http_version 1.1;
|
||
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;
|
||
}
|
||
|
||
# 后端 API
|
||
location /api/ {
|
||
proxy_pass http://127.0.0.1:2088;
|
||
proxy_http_version 1.1;
|
||
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;
|
||
}
|
||
}
|
||
NGINX
|
||
```
|
||
|
||
启用并检查:
|
||
```bash
|
||
sudo ln -sf /etc/nginx/sites-available/jessiegem-cockpit.conf /etc/nginx/sites-enabled/jessiegem-cockpit.conf
|
||
sudo nginx -t
|
||
sudo systemctl reload nginx
|
||
```
|
||
|
||
证书(如未配置):
|
||
```bash
|
||
sudo apt install -y certbot python3-certbot-nginx
|
||
sudo certbot --nginx -d JessieGem.zeotaki.com
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 手工发布流程(不使用 Jenkins)
|
||
|
||
### 4.1 拉取代码
|
||
在服务器上:
|
||
```bash
|
||
cd /opt/jessiegem-cockpit
|
||
sudo -u cockpit git clone <你的-gitea-仓库-url> repo
|
||
```
|
||
|
||
后续更新:
|
||
```bash
|
||
cd /opt/jessiegem-cockpit/repo
|
||
sudo -u cockpit git pull
|
||
```
|
||
|
||
### 4.2 构建并发布后端
|
||
```bash
|
||
cd /opt/jessiegem-cockpit/repo/backend
|
||
sudo -u cockpit go build -o /opt/jessiegem-cockpit/backend/cockpit-server ./cmd/server
|
||
sudo systemctl restart cockpit-backend
|
||
```
|
||
|
||
### 4.3 构建并发布前端
|
||
```bash
|
||
cd /opt/jessiegem-cockpit/repo/frontend
|
||
sudo -u cockpit npm ci
|
||
sudo -u cockpit VITE_API_BASE="https://JessieGem.zeotaki.com" npm run build
|
||
|
||
# vite preview 需要 dist,所以把 dist 与 package 相关文件同步到运行目录
|
||
sudo -u cockpit rsync -a --delete dist/ /opt/jessiegem-cockpit/frontend/dist/
|
||
sudo -u cockpit rsync -a package.json package-lock.json vite.config.ts /opt/jessiegem-cockpit/frontend/
|
||
|
||
cd /opt/jessiegem-cockpit/frontend
|
||
sudo -u cockpit npm ci
|
||
sudo systemctl restart cockpit-frontend
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Jenkins + Gitea 自动部署(推荐)
|
||
|
||
### 5.1 Jenkins 准备
|
||
在 Jenkins 配置以下内容:
|
||
- 凭据 1:Gitea 访问令牌/账号(用于拉取仓库)
|
||
- 凭据 2:SSH 私钥(用于从 Jenkins 服务器 SSH 到部署服务器)
|
||
- 在 Gitea 仓库配置 Webhook -> Jenkins(push 触发构建)
|
||
|
||
### 5.2 服务器准备(用于 Jenkins 部署)
|
||
保证 Jenkins 可以 SSH 到服务器,并且服务器上已创建:
|
||
- `/opt/jessiegem-cockpit/backend`
|
||
- `/opt/jessiegem-cockpit/frontend`
|
||
- systemd 服务:`cockpit-backend`、`cockpit-frontend`
|
||
|
||
### 5.3 Jenkinsfile 示例(Pipeline)
|
||
把下面内容保存为仓库根目录 `Jenkinsfile`(或在 Jenkins Pipeline 脚本里粘贴):
|
||
|
||
```groovy
|
||
pipeline {
|
||
agent any
|
||
environment {
|
||
DEPLOY_HOST = '你的服务器IP或域名'
|
||
DEPLOY_USER = 'root' // 或具备 sudo 权限的用户
|
||
VITE_API_BASE = 'https://JessieGem.zeotaki.com'
|
||
}
|
||
stages {
|
||
stage('Checkout') {
|
||
steps { checkout scm }
|
||
}
|
||
stage('Build Backend') {
|
||
steps {
|
||
dir('backend') {
|
||
sh 'go version'
|
||
sh 'go build -o cockpit-server ./cmd/server'
|
||
}
|
||
}
|
||
}
|
||
stage('Build Frontend') {
|
||
steps {
|
||
dir('frontend') {
|
||
sh 'node -v && npm -v'
|
||
sh 'npm ci'
|
||
sh "VITE_API_BASE=${VITE_API_BASE} npm run build"
|
||
}
|
||
}
|
||
}
|
||
stage('Deploy') {
|
||
steps {
|
||
sshagent(credentials: ['你的-jenkins-ssh-credential-id']) {
|
||
sh '''
|
||
set -e
|
||
rsync -avz --delete backend/cockpit-server ${DEPLOY_USER}@${DEPLOY_HOST}:/opt/jessiegem-cockpit/backend/cockpit-server
|
||
rsync -avz --delete frontend/dist/ ${DEPLOY_USER}@${DEPLOY_HOST}:/opt/jessiegem-cockpit/frontend/dist/
|
||
rsync -avz frontend/package.json frontend/package-lock.json ${DEPLOY_USER}@${DEPLOY_HOST}:/opt/jessiegem-cockpit/frontend/
|
||
ssh ${DEPLOY_USER}@${DEPLOY_HOST} "cd /opt/jessiegem-cockpit/frontend && npm ci && sudo systemctl restart cockpit-frontend"
|
||
ssh ${DEPLOY_USER}@${DEPLOY_HOST} "sudo systemctl restart cockpit-backend"
|
||
'''
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
> 如果 Jenkins 机器不是 Linux(例如 Windows),上面 `sh` 需要改成对应的 `bat/powershell`,或者让 Jenkins agent 跑在 Linux 节点上。
|
||
|
||
---
|
||
|
||
## 6. 验收清单
|
||
|
||
### 6.1 服务状态
|
||
```bash
|
||
sudo systemctl status cockpit-backend --no-pager
|
||
sudo systemctl status cockpit-frontend --no-pager
|
||
```
|
||
|
||
### 6.2 端口监听(应仅 127.0.0.1)
|
||
```bash
|
||
sudo ss -lntp | egrep '2088|2099'
|
||
```
|
||
|
||
### 6.3 站点验证
|
||
- 打开:`https://JessieGem.zeotaki.com`
|
||
- 登录:`admin / admin123`
|
||
- Network 面板确认 API 请求是:`https://JessieGem.zeotaki.com/api/...`(同域)
|
||
|