- backend: FastAPI + SQLAlchemy 2.0(async) + asyncpg + Alembic - 7 API routes: auth/me/articles/sources/bookmarks/subscriptions/admin - models: User/Source/Article/Bookmark/Subscription/ApiToken - services: RSS fetcher (feedparser) + Tencent TMT translator with quota + cache + local NLLB fallback - workers: APScheduler + asyncio pipeline (fetch -> dedupe -> insert -> translate) - seed scripts: create_user, seed_sources (5 RSS: Reuters/BBC/Al Jazeera/NHK/DW) - frontend: Vue 3 + Vite + Naive UI + Pinia + vue-router - pages: Login, Feed (24h), ArticleDetail, Sources, Bookmarks, AdminSources - deploy: docker-compose (postgres/redis/api/worker/frontend/caddy) - docs: README, DEPLOY, architecture, acceptance
4.1 KiB
4.1 KiB
部署指南 · DEPLOY
目标:从一台全新的 Ubuntu 24 香港 VPS,到能访问的私人新闻系统。
0. 准备
- 香港 VPS(最低 2C2G 30G)
- 域名(可选,没域名走 IP + 自签证书)
- 腾讯云账号 + 已开通「文本翻译 TMT」
1. 服务器初始化
# SSH 登录
ssh root@YOUR_SERVER_IP
# 创建非 root 用户
adduser news
usermod -aG sudo news
# 基础包
apt update && apt -y upgrade
apt -y install curl git ufw fail2ban
# 防火墙
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
# Docker
curl -fsSL https://get.docker.com | sh
usermod -aG docker news
# 退出 root,切换到 news
exit
ssh news@YOUR_SERVER_IP
2. 拉代码
sudo mkdir -p /srv/news
sudo chown news:news /srv/news
cd /srv/news
git clone <你的仓库地址> .
# 或者 scp 上传
3. 配置环境变量
cp .env.example .env
nano .env
必填字段:
| 字段 | 怎么填 |
|---|---|
POSTGRES_PASSWORD |
openssl rand -hex 24 |
REDIS_PASSWORD |
openssl rand -hex 24 |
JWT_SECRET |
openssl rand -hex 64 |
TENCENTCLOUD_SECRET_ID |
腾讯云控制台 → 访问管理 → API 密钥 |
TENCENTCLOUD_SECRET_KEY |
同上 |
TENCENTCLOUD_REGION |
ap-hongkong |
DOMAIN |
域名(可选,留空走 IP) |
4. 启动
docker compose up -d --build
# 等 30 秒
docker compose ps
# 全部 healthy 即可
5. 初始化
# 5.1 数据库迁移
docker compose exec api alembic upgrade head
# 5.2 创建 owner 账号
docker compose exec api python -m app.scripts.create_user \
--username owner --password YOUR_STRONG_PASS
# 5.3 导入 5 个种子源
docker compose exec api python -m app.scripts.seed_sources
# 5.4 手动触发一次抓取(看效果)
docker compose exec worker python -c "import asyncio; from app.workers.pipeline import run_once; asyncio.run(run_once())"
# 等 1~3 分钟,刷一下
docker compose exec postgres psql -U $POSTGRES_USER -d $POSTGRES_DB -c "SELECT count(*) FROM articles;"
6. 验证清单
- 浏览器打开
http://YOUR_IP/看到登录页 - 用 owner 登录成功
- Feed 列表显示 24h 内新闻(标题中英对照)
- 详情页原文+译文并列
/admin/sources能看到 5 个源- 翻译配额仪表盘显示已用字符
- 等到凌晨,worker 自动跑批,文章数持续增长
7. 域名 + HTTPS(可选)
- 域名 A 记录指向服务器 IP
- 编辑
.env填DOMAIN=news.example.com+ACME_EMAIL=you@example.com - 编辑
Caddyfile,把http://{$DOMAIN}改成{$DOMAIN}(取消注释下面块) docker compose restart caddy- Caddy 自动申请 Let's Encrypt 证书
8. 备份
# 每天凌晨 4 点备份到本地
cat > /srv/news/scripts/backup.sh <<'EOF'
#!/bin/bash
set -e
BACKUP_DIR=/srv/news/backups/$(date +%Y%m%d)
mkdir -p "$BACKUP_DIR"
docker compose exec -T postgres pg_dump -U $POSTGRES_USER $POSTGRES_DB | gzip > "$BACKUP_DIR/db.sql.gz"
# 保留 7 天
find /srv/news/backups -type d -mtime +7 -exec rm -rf {} +
EOF
chmod +x /srv/news/scripts/backup.sh
# 加 cron
crontab -e
# 添加一行:
# 0 4 * * * /srv/news/scripts/backup.sh
强烈建议:把 /srv/news/backups/ 同步到腾讯云 COS / 阿里云 OSS,做异地灾备。
9. 升级
cd /srv/news
git pull
docker compose pull
docker compose up -d --build
docker compose exec api alembic upgrade head
10. 常见问题
Q: 某个源一直 fail?
A: 看 docker compose logs worker | grep <source_slug>,90% 是 RSS URL 失效或者被反爬。在 sources 表里 enabled=false 暂停。
Q: 翻译字符超 500 万?
A: 配 .env 的 TENCENT_TMT_QUOTA_BUFFER=0.05,系统在 475 万字符后自动切本地 NLLB(需启用 LOCAL_TRANSLATE_ENABLED=true)。
未启用本地翻译时,系统会在原文末尾标 [本条未翻译]。
Q: 30G 硬盘快满了? A: 执行冷热分层 cron:
DELETE FROM articles WHERE published_at < now() - interval '90 day' AND duplicate_of IS NULL;
Q: 怎么加新源?
A: 网页登录 owner → /admin/sources → 新增。填 name / kind=rss / url=RSS 链接 / 优先级 / 抓取频率。保存后 worker 下个轮询周期自动拉。