CareerBot/OPS_MANUAL.md
ln0422 87dc77f9d8 Remove www.ityb.me/careerbot 301 redirect; document 404 behavior
The backward-compat redirect from www.ityb.me/careerbot/* to
career.ityb.me/careerbot/* has been removed per user request.
Now all /careerbot paths on the main domain return 404, except
/careerbot/uploads/* which is served by branch1's secondary mount
so trunk-uploaded photo URLs still render on branch1 pages.

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

519 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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`
```bash
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/* → 404已主动屏蔽
│ 仅 /careerbot/uploads/* 由 branch1 后端兜底(供 trunk 上传 │
│ 的头像 URL 在 branch1 页面正常显示) │
├────────────────────────────────────────────────────────────────┤
│ 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 服务管理
```bash
# ── 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 代码更新部署
**从本地推送代码并部署到线上(标准流程):**
```bash
# 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"
```
**一键部署脚本(在本地执行):**
```bash
ssh ecs "cd ~/apps/CareerBot && git pull origin main && sudo systemctl restart careerbot && sleep 2 && sudo systemctl is-active careerbot"
```
### 5.3 数据库操作
```bash
# 连接到 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 系统监控
```bash
# 查看内存使用
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`
```ini
[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`
```ini
[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_URL``UPLOAD_DIR` 环境变量指向 trunk 的数据库和上传目录
- **BASE_PATH**branch1 设置为空串,应用部署在根路径
- **FAB 显示**branch1 的 `templates/index.html` 已修改,对话按钮 `style="display:none;"`
- `Restart=always`:崩溃后自动重启
### 6.2 Nginx 站点配置
文件:`/etc/nginx/sites-available/careerbot.conf`(含三段 server block + certbot 自动追加的 HTTPS 块)
```nginx
# ===== 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;
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.me` 和 `www.ityb.me+ityb.me` 分别独立证书(均由 certbot 自动申请续期)
- **主域路径隔离**`www.ityb.me/careerbot/*` 返回 404nginx 层不做任何特殊处理,请求透传到 branch1 后端branch1 没有 /careerbot 前缀路由因此 404`/careerbot/uploads/*` 能命中 branch1 的二级挂载,用于显示 trunk 管理员上传的头像
- `proxy_buffering off` + `proxy_cache off`**必须关闭**,否则 SSE 流式对话无法实时返回
- `proxy_read_timeout 300s`LLM 长回复可能需要较长时间
### 6.3 Gitea 站点配置
文件:`/etc/nginx/sites-available/gitea.conf`HTTPS 部分由 certbot 自动生成)
```nginx
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.ini``ROOT_URL=https://git.ityb.me/`、`DOMAIN=git.ityb.me`、`SSH_DOMAIN=git.ityb.me`
### 6.3 防火墙规则
```bash
# 查看当前规则
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 文件中:
```bash
# 手动备份
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 数据备份
```bash
# 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 无法访问
```bash
# 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-config`LLM Config 是否已配置API URL、API Key、Model Name
- 点击 "Test Connection" 测试连通性
- 确认 ECS 能访问外网:`curl https://api.deepseek.com`
### 8.3 Gitea 无法访问
```bash
sudo systemctl status gitea
sudo journalctl -u gitea --since "10 min ago"
# 检查 3000 端口和安全组
```
### 8.4 磁盘/内存不足
```bash
# 查看磁盘
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 上克隆并配置**
```bash
cd ~/apps
git clone https://git.ityb.me/ln0422/新项目.git
# 安装依赖、初始化等
```
4. **创建 systemd 服务**(参考 careerbot.service注意更换端口号
5. **添加 Nginx 站点配置**(在同一个 `careerbot.conf` 文件或新建独立 conf 文件中,添加新的 `location /新路径/` 块):
```bash
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`