cockpit-source/DEPLOYMENT.md
2026-04-02 14:12:43 +08:00

9.8 KiB
Raw Blame History

部署文档JessieGem.zeotaki.com / backend:2088 / frontend:2099

本文档假设目标服务器为 LinuxUbuntu/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 示例:

sudo apt update
sudo apt install -y nginx git

Go/Node 的安装方式你可按服务器习惯来官方包、nvm、asdf 都可),但要满足版本要求:

  • Gogo version >= 1.22
  • Nodenode -v >= 20

0.2 端口规划与防火墙

  • 对公网开放80/443
  • 仅本机监听2088/2099不要直接暴露公网

如使用 UFW

sudo ufw allow 80
sudo ufw allow 443
sudo ufw enable

1. 后端部署Go / 2088

1.1 创建运行用户与目录

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

创建配置:

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

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

启动:

sudo systemctl daemon-reload
sudo systemctl enable --now cockpit-backend
sudo systemctl status cockpit-backend --no-pager

日志查看:

journalctl -u cockpit-backend -f

2. 前端部署Vite preview / 2099

前端推荐构建后用 vite preview 在本机端口提供服务,再由 Nginx 反代。这样部署简单,但注意 Node 进程稳定性要交给 systemd 管理。

2.1 构建环境变量(非常重要)

前端生产构建时需要 VITE_API_BASE 指向站点域名(同域走 Nginx /api 反代):

export VITE_API_BASE="https://JessieGem.zeotaki.com"

2.2 systemd 服务frontend

创建目录:

sudo mkdir -p /opt/jessiegem-cockpit/frontend
sudo chown -R cockpit:cockpit /opt/jessiegem-cockpit/frontend

创建 /etc/systemd/system/cockpit-frontend.service

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

启动:

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

创建站点配置:

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

启用并检查:

sudo ln -sf /etc/nginx/sites-available/jessiegem-cockpit.conf /etc/nginx/sites-enabled/jessiegem-cockpit.conf
sudo nginx -t
sudo systemctl reload nginx

证书(如未配置):

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d JessieGem.zeotaki.com

4. 手工发布流程(不使用 Jenkins

4.1 拉取代码

在服务器上:

cd /opt/jessiegem-cockpit
sudo -u cockpit git clone <你的-gitea-仓库-url> repo

后续更新:

cd /opt/jessiegem-cockpit/repo
sudo -u cockpit git pull

4.2 构建并发布后端

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 构建并发布前端

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 配置以下内容:

  • 凭据 1Gitea 访问令牌/账号(用于拉取仓库)
  • 凭据 2SSH 私钥(用于从 Jenkins 服务器 SSH 到部署服务器)
  • 在 Gitea 仓库配置 Webhook -> Jenkinspush 触发构建)

5.2 服务器准备(用于 Jenkins 部署)

保证 Jenkins 可以 SSH 到服务器,并且服务器上已创建:

  • /opt/jessiegem-cockpit/backend
  • /opt/jessiegem-cockpit/frontend
  • systemd 服务:cockpit-backendcockpit-frontend

5.3 Jenkinsfile 示例Pipeline

把下面内容保存为仓库根目录 Jenkinsfile(或在 Jenkins Pipeline 脚本里粘贴):

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 服务状态

sudo systemctl status cockpit-backend --no-pager
sudo systemctl status cockpit-frontend --no-pager

6.2 端口监听(应仅 127.0.0.1

sudo ss -lntp | egrep '2088|2099'

6.3 站点验证

  • 打开:https://JessieGem.zeotaki.com
  • 登录:admin / admin123
  • Network 面板确认 API 请求是:https://JessieGem.zeotaki.com/api/...(同域)