CareerBot/OPS_MANUAL.md
ln0422 f0c4134edd Document dual-domain deployment (trunk + branch1)
- DESIGN.md: add branching strategy table, update online addresses
  with both trunk (career.ityb.me) and branch1 (www.ityb.me) URLs
- OPS_MANUAL.md: update service architecture diagram, ports table
  (add :8001), file structure (add CareerBot-branch1), systemd
  services (add careerbot-branch1.service with env-based DB sharing),
  nginx config (three server blocks + certbot HTTPS)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-21 13:11:14 +08:00

18 KiB
Raw Blame History

CareerBot 线上运维手册

1. 服务器信息

项目 详情
云服务商 阿里云 ECS
公网 IP 39.106.14.107
域名 ityb.me / www.ityb.me
操作系统 Alibaba Cloud Linux 3 (OpenAnolis Edition)
配置 2 核 CPU / 2GB 内存 / 40GB 磁盘
Python 版本 3.11.13
Nginx 版本 1.20.1
Gitea 版本 1.22.6

2. 账号信息

2.1 服务器账号

账号 用途 登录方式
root 系统管理 SSH 密钥 (~/.ssh/id_ed25519)
deploy 应用部署和运行 SSH 密钥同上sudo 免密
gitea Gitea 服务运行 系统用户,不可直接登录
nginx Nginx 服务运行 系统用户,不可直接登录

本地 SSH 快捷连接(已配置在 ~/.ssh/config

ssh ecs          # 以 deploy 用户连接
ssh root@ecs     # 以 root 用户连接(需将 config 中 User 临时改为 root或直接用 IP
ssh root@39.106.14.107   # root 直连

2.2 应用账号

系统 地址 账号 密码
CareerBot 展示版branch1 https://www.ityb.me/ (访问令牌或匿名) -
CareerBot 完整版trunk https://career.ityb.me/careerbot/ (访问令牌或匿名) -
CareerBot 管理后台 https://career.ityb.me/careerbot/admin/login ln0422@gmail.com qshs123456
Gitea 代码管理 https://git.ityb.me ln0422 Qshs123456_

2.3 ECS 用户密码

用户 密码
deploy CareerBot2026!

注意:日常运维通过 SSH 密钥登录,密码仅在密钥不可用时作为备用。


3. 服务架构

外部访问
   │
   ▼
┌────────────────────────────────────────────────────────────────┐
│  Nginx (:80 / :443)                                            │
│  配置: /etc/nginx/sites-enabled/                               │
│  日志: /var/log/nginx/                                         │
├────────────────────────────────────────────────────────────────┤
│  https://www.ityb.me/        (主域,展示版 branch1)            │
│  https://ityb.me/            ┤                                 │
│    → proxy_pass http://127.0.0.1:8001/                         │
│    → CareerBot branch1 (uvicorn, BASE_PATH="", FAB 隐藏)       │
│                                                                │
│  https://www.ityb.me/careerbot/*  (向后兼容)                   │
│    → 301 redirect https://career.ityb.me/careerbot/...         │
├────────────────────────────────────────────────────────────────┤
│  https://career.ityb.me/careerbot/   (完整版 trunk)             │
│    → proxy_pass http://127.0.0.1:8000/careerbot/                │
│    → CareerBot main (uvicorn, BASE_PATH="/careerbot", 完整功能) │
├────────────────────────────────────────────────────────────────┤
│  https://git.ityb.me                                           │
│    → proxy_pass http://127.0.0.1:3000                          │
│    → Gitea                                                     │
│                                                                │
│  http://39.106.14.107/careerbot/     (IP 直连兼容 trunk)        │
│  http://39.106.14.107:3000           (IP 直连兼容 Gitea)        │
└────────────────────────────────────────────────────────────────┘

两个 CareerBot 实例共享同一 DB + uploads
  /home/deploy/apps/CareerBot/careerbot.db    ← 权威数据源
  /home/deploy/apps/CareerBot/uploads/        ← 权威上传目录
  branch1 通过 systemd 环境变量 DATABASE_URL / UPLOAD_DIR 指向这里

端口使用

端口 服务 监听地址 防火墙 安全组
22 SSH 0.0.0.0 已放行 已放行
80 Nginx (HTTP → HTTPS) 0.0.0.0 已放行 已放行
443 Nginx (HTTPS) 0.0.0.0 已放行 已放行
3000 Gitea 0.0.0.0 已放行 已放行
8000 CareerBot trunk (uvicorn) 127.0.0.1 内部 无需
8001 CareerBot branch1 (uvicorn) 127.0.0.1 内部 无需

4. 文件目录结构

/home/deploy/apps/CareerBot/        ← Trunk 项目根目录main 分支,:8000
├── venv/                           ← Python 虚拟环境
├── app/                            ← 应用代码
├── templates/                      ← 页面模板
├── careerbot.db                    ← SQLite 数据库主数据源branch1 也读写这里)
├── uploads/                        ← 用户上传文件主目录branch1 也访问这里)
├── requirements.txt
├── init_data.py
├── DESIGN.md                       ← 设计文档
└── OPS_MANUAL.md                   ← 本文档

/home/deploy/apps/CareerBot-branch1/ ← Branch1 项目根目录branch1 分支,:8001
├── venv/                           ← 独立虚拟环境
├── app/                            ← BASE_PATH="" 的代码
├── templates/                      ← 隐藏 FAB 的 index.html
└── (无独立 careerbot.db通过环境变量指向 trunk 的)

/etc/systemd/system/
├── careerbot.service               ← CareerBot trunk systemd 服务
├── careerbot-branch1.service       ← CareerBot branch1 systemd 服务
└── gitea.service                   ← Gitea systemd 服务

/etc/nginx/
├── nginx.conf                      ← Nginx 主配置
├── sites-available/
│   ├── careerbot.conf              ← CareerBot 站点配置
│   └── gitea.conf                  ← Gitea 站点配置
└── sites-enabled/
    ├── careerbot.conf → ../sites-available/careerbot.conf
    └── gitea.conf → ../sites-available/gitea.conf

/usr/local/bin/gitea                ← Gitea 二进制文件
/etc/gitea/app.ini                  ← Gitea 配置文件
/var/lib/gitea/                     ← Gitea 数据目录(仓库、数据库)

5. 常用运维命令

5.1 服务管理

# ── CareerBot ──
sudo systemctl status careerbot     # 查看状态
sudo systemctl restart careerbot    # 重启
sudo systemctl stop careerbot       # 停止
sudo systemctl start careerbot      # 启动
sudo journalctl -u careerbot -f     # 实时查看日志
sudo journalctl -u careerbot --since "1 hour ago"  # 查看最近1小时日志

# ── Nginx ──
sudo systemctl status nginx
sudo systemctl reload nginx         # 重载配置(不中断连接)
sudo systemctl restart nginx        # 重启
sudo nginx -t                       # 测试配置文件语法

# ── Gitea ──
sudo systemctl status gitea
sudo systemctl restart gitea
sudo journalctl -u gitea -f

5.2 代码更新部署

从本地推送代码并部署到线上(标准流程):

# 1. 本地:提交并推送到 Gitea
cd D:/Files/Projects/VibeCoding/CareerBot
git add .
git commit -m "描述改动"
git push origin main

# 2. 线上:拉取并重启
ssh ecs "cd ~/apps/CareerBot && git pull && sudo systemctl restart careerbot"

一键部署脚本(在本地执行):

ssh ecs "cd ~/apps/CareerBot && git pull origin main && sudo systemctl restart careerbot && sleep 2 && sudo systemctl is-active careerbot"

5.3 数据库操作

# 连接到 SQLite 数据库
ssh ecs "cd ~/apps/CareerBot && sqlite3 careerbot.db"

# 常用 SQL
.tables                              # 查看所有表
SELECT * FROM admin_user;            # 查看管理员
SELECT token, note, max_questions, used_questions, is_active FROM access_token;  # 查看令牌
SELECT * FROM recruiter_message ORDER BY created_at DESC LIMIT 10;  # 最近招聘消息
SELECT COUNT(*) FROM chat_history;   # 对话记录总数
.quit                                # 退出

5.4 系统监控

# 查看内存使用
ssh ecs "free -h"

# 查看磁盘使用
ssh ecs "df -h /"

# 查看各服务内存占用
ssh ecs "ps aux --sort=-rss | head -10"

# 查看端口监听
ssh ecs "ss -tlnp"

6. 配置文件详情

6.1 CareerBot systemd 服务

Trunkmain 分支)/etc/systemd/system/careerbot.service

[Unit]
Description=CareerBot Web Application
After=network.target

[Service]
Type=simple
User=deploy
WorkingDirectory=/home/deploy/apps/CareerBot
ExecStart=/home/deploy/apps/CareerBot/venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000
Restart=always
RestartSec=5
Environment=PATH=/home/deploy/apps/CareerBot/venv/bin:/usr/bin

[Install]
WantedBy=multi-user.target

Branch1branch1 分支,共享 trunk 数据)/etc/systemd/system/careerbot-branch1.service

[Unit]
Description=CareerBot branch1 (display-only, shared DB with trunk)
After=network.target

[Service]
Type=simple
User=deploy
WorkingDirectory=/home/deploy/apps/CareerBot-branch1
ExecStart=/home/deploy/apps/CareerBot-branch1/venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8001
Restart=always
Environment=PATH=/home/deploy/apps/CareerBot-branch1/venv/bin:/usr/bin
Environment=DATABASE_URL=sqlite:////home/deploy/apps/CareerBot/careerbot.db
Environment=UPLOAD_DIR=/home/deploy/apps/CareerBot/uploads
Environment=BASE_PATH=

[Install]
WantedBy=multi-user.target

关键差异:

  • 端口trunk 用 8000branch1 用 8001
  • 数据共享branch1 通过 DATABASE_URLUPLOAD_DIR 环境变量指向 trunk 的数据库和上传目录
  • BASE_PATHbranch1 设置为空串,应用部署在根路径
  • FAB 显示branch1 的 templates/index.html 已修改,对话按钮 style="display:none;"
  • Restart=always:崩溃后自动重启

6.2 Nginx 站点配置

文件:/etc/nginx/sites-available/careerbot.conf(含三段 server block + certbot 自动追加的 HTTPS 块)

# ===== TRUNK: career.ityb.me (完整版,/careerbot/ 子路径) =====
server {
    server_name career.ityb.me;
    client_max_body_size 10M;

    location /careerbot/ {
        proxy_pass http://127.0.0.1:8000/careerbot/;
        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;
        proxy_buffering off; proxy_cache off; proxy_read_timeout 300s;
    }
    location = / { return 302 /careerbot/; }

    listen 443 ssl;  # by certbot
    ssl_certificate     /etc/letsencrypt/live/career.ityb.me/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/career.ityb.me/privkey.pem;
}

# ===== BRANCH1: www.ityb.me + ityb.me (展示版,根路径) =====
server {
    listen 80;
    server_name www.ityb.me ityb.me;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl;
    server_name www.ityb.me ityb.me;
    client_max_body_size 10M;

    ssl_certificate     /etc/letsencrypt/live/www.ityb.me/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.ityb.me/privkey.pem;

    # 向后兼容:旧的 /careerbot/ URL 跳转到 career 子域名
    location /careerbot/ {
        return 301 https://career.ityb.me$request_uri;
    }

    location / {
        proxy_pass http://127.0.0.1:8001/;   # branch1
        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;
        proxy_buffering off; proxy_cache off; proxy_read_timeout 300s;
    }
}

# ===== IP 直连向后兼容HTTP only =====
server {
    listen 80 default_server;
    server_name 39.106.14.107;
    client_max_body_size 10M;

    location /careerbot/ {
        proxy_pass http://127.0.0.1:8000/careerbot/;
        # ... 同 trunk ...
    }
    location = / { return 302 /careerbot/; }
}

关键配置说明:

  • 双域双实例career 子域名走 trunk:8000主域名走 branch1:8001
  • SSL 证书career.ityb.mewww.ityb.me+ityb.me 分别独立证书(均由 certbot 自动申请续期)
  • 向后兼容www.ityb.me/careerbot/* 自动 301 到 career.ityb.me/careerbot/*,老链接不会失效
  • proxy_buffering off + proxy_cache off必须关闭,否则 SSE 流式对话无法实时返回
  • proxy_read_timeout 300sLLM 长回复可能需要较长时间

6.3 Gitea 站点配置

文件:/etc/nginx/sites-available/gitea.confHTTPS 部分由 certbot 自动生成)

server {
    listen 80;
    server_name git.ityb.me;
    client_max_body_size 512M;

    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;
        proxy_read_timeout 300s;
    }

    # certbot 自动追加 443 监听块 + 80→443 重定向
    listen 443 ssl;
    ssl_certificate /etc/letsencrypt/live/git.ityb.me/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/git.ityb.me/privkey.pem;
}

关键说明:

  • client_max_body_size 512M:支持大仓库 push/pull
  • Gitea 仍在本机 3000 端口监听Nginx 反向代理到 443HTTPS
  • 端口 3000 保持对外开放作为备用访问方式
  • 对应 Gitea 配置 /etc/gitea/app.iniROOT_URL=https://git.ityb.me/DOMAIN=git.ityb.meSSH_DOMAIN=git.ityb.me

6.3 防火墙规则

# 查看当前规则
sudo firewall-cmd --list-ports
# 输出: 22/tcp 80/tcp 443/tcp 3000/tcp

# 添加新端口(如未来部署新项目)
sudo firewall-cmd --permanent --add-port=PORT/tcp
sudo firewall-cmd --reload

注意:开放端口还需要在阿里云控制台的安全组中同步添加入方向规则,否则外部仍无法访问。


7. 备份策略

7.1 数据库备份

CareerBot 的所有业务数据存储在 SQLite 文件中:

# 手动备份
ssh ecs "cp ~/apps/CareerBot/careerbot.db ~/apps/CareerBot/careerbot.db.bak.$(date +%Y%m%d)"

# 下载到本地
scp ecs:~/apps/CareerBot/careerbot.db ./careerbot_backup_$(date +%Y%m%d).db

7.2 Gitea 数据备份

# Gitea 数据和仓库
ssh ecs "sudo tar czf /tmp/gitea-backup.tar.gz /var/lib/gitea /etc/gitea"
scp ecs:/tmp/gitea-backup.tar.gz ./gitea-backup.tar.gz

7.3 需要备份的关键文件

文件/目录 说明 重要程度
~/apps/CareerBot/careerbot.db CareerBot 全部业务数据 极高
~/apps/CareerBot/uploads/ 用户上传的文件
/var/lib/gitea/ Gitea 所有仓库和数据 极高
/etc/gitea/app.ini Gitea 配置
/etc/nginx/sites-available/ Nginx 站点配置
/etc/systemd/system/careerbot.service 服务配置 低(可重建)

8. 故障排查

8.1 CareerBot 无法访问

# 1. 检查服务状态
sudo systemctl status careerbot

# 2. 查看错误日志
sudo journalctl -u careerbot --since "10 min ago"

# 3. 检查端口
ss -tlnp | grep 8000

# 4. 检查 Nginx
sudo nginx -t
sudo systemctl status nginx

# 5. 手动启动测试
cd ~/apps/CareerBot
source venv/bin/activate
uvicorn app.main:app --host 127.0.0.1 --port 8000

8.2 AI 对话不工作

  • 检查管理后台(http://www.ityb.me/careerbot/admin/llm-configLLM Config 是否已配置API URL、API Key、Model Name
  • 点击 "Test Connection" 测试连通性
  • 确认 ECS 能访问外网:curl https://api.deepseek.com

8.3 Gitea 无法访问

sudo systemctl status gitea
sudo journalctl -u gitea --since "10 min ago"
# 检查 3000 端口和安全组

8.4 磁盘/内存不足

# 查看磁盘
df -h /

# 清理日志
sudo journalctl --vacuum-time=7d

# 查看内存
free -h

# 查看占用最多的进程
ps aux --sort=-rss | head -10

9. 新项目部署指南

后续在同一台 ECS 上部署新项目的标准流程:

  1. Gitea 上创建仓库https://git.ityb.me → New Repository

  2. 本地推送代码

  3. ECS 上克隆并配置

    cd ~/apps
    git clone https://git.ityb.me/ln0422/新项目.git
    # 安装依赖、初始化等
    
  4. 创建 systemd 服务(参考 careerbot.service注意更换端口号

  5. 添加 Nginx 站点配置(在同一个 careerbot.conf 文件或新建独立 conf 文件中,添加新的 location /新路径/ 块):

    sudo vim /etc/nginx/sites-available/新项目.conf
    sudo ln -s /etc/nginx/sites-available/新项目.conf /etc/nginx/sites-enabled/
    sudo nginx -t && sudo systemctl reload nginx
    

    建议参考 CareerBot 的子路径部署模式:location /新路径/ { proxy_pass http://127.0.0.1:新端口/新路径/; }

  6. 如需新端口:防火墙 + 阿里云安全组同步放行


10. 安全注意事项

  1. SSH 密钥:本地私钥 ~/.ssh/id_ed25519 请妥善保管,丢失需重新生成并更新服务器
  2. Gitea 端口3000 端口对外开放,建议设置强密码,或后续通过 Nginx 代理并限制访问
  3. 数据库文件careerbot.db 不应对外暴露uvicorn 仅监听 127.0.0.1 已确保安全
  4. 定期更新:定期执行 sudo dnf update -y 更新系统安全补丁
  5. HTTPS:域名 ityb.me 已绑定,建议配置 Let's Encrypt SSL 证书(certbot --nginx -d www.ityb.me -d ityb.me