8.0 KiB
04-部署运行文档
本文说明如何在服务器上把项目跑起来。项目共三端:服务端(FastAPI,无需编译)、管理后台(Vue3,构建为静态文件)、App(Flutter,必须编译出 APK/IPA)。
1. 组成与依赖
| 端 | 目录 | 技术栈 | 运行/构建产物 |
|---|---|---|---|
| 服务端 | server/ |
Python ≥ 3.11 + FastAPI + MySQL 8 + Redis 7 | 直接运行,无需编译 |
| 管理后台 | admin/ |
Node ≥ 18 + Vue3 + Vite | npm run build → admin/dist/ 静态文件 |
| App | app/ |
Flutter 3.x(Dart ≥ 3.9) | flutter build apk / flutter build ipa |
服务器需先装好:MySQL 8(utf8mb4)、Redis 7、Python 3.11+、Nginx(托管后台 + 反向代理)。
2. 服务端部署(server/)
2.1 安装依赖
cd server
python3.11 -m venv .venv
source .venv/bin/activate
pip install . # 核心依赖
pip install ".[pay]" # 可选:支付渠道 SDK(支付宝/微信/Tron),不接支付可跳过
2.2 准备数据库与 .env
CREATE DATABASE video CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
在 server/.env 配置环境项(不入库的连接串/密钥):
APP_ENV=prod # prod 时 /docs 自动关闭
APP_HOST=0.0.0.0
APP_PORT=8000
DATABASE_URL=mysql+aiomysql://user:pass@127.0.0.1:3306/video?charset=utf8mb4
REDIS_URL=redis://127.0.0.1:6379/0
JWT_SECRET=换成足够长的随机串 # 生产必须更换
# 以下按需配置(不配置则对应功能自动降级:短信/邮件发不出去、支付走 dev_mock、USDT 不启用)
# ALIPAY_APP_ID / ALIPAY_PRIVATE_KEY / ALIPAY_PUBLIC_KEY / ALIPAY_NOTIFY_URL
# WECHAT_MCHID / WECHAT_APP_ID / WECHAT_API_V3_KEY / WECHAT_PRIVATE_KEY / WECHAT_CERT_SERIAL_NO / WECHAT_PLATFORM_CERT / WECHAT_NOTIFY_URL
# TRON_API_KEY(USDT 链上查账)
# SMS_ACCESS_KEY_ID / SMS_ACCESS_KEY_SECRET / SMS_SIGN_NAME(短信验证码)
# SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASSWORD(邮箱验证码)
业务参数(积分/会员/激励/提现规则)在 server/config.yaml,其中部分项上线后可在管理后台「系统配置」热修改。
2.3 初始化表结构 + 首个管理员
cd server
.venv/bin/alembic upgrade head # 建 27 张表
# 创建后台管理员(代码不自动播种,需手动执行一次)
.venv/bin/python - <<'EOF'
import asyncio
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
from app.config import settings
from app.core.security import hash_password
from app.models.admin import AdminUser
async def main():
engine = create_async_engine(settings.database_url)
async with async_sessionmaker(engine)() as s:
s.add(AdminUser(username="admin",
password_hash=hash_password("请设置强密码"),
name="超管", role="super"))
await s.commit()
await engine.dispose()
asyncio.run(main())
EOF
2.4 启动
cd server
.venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000
- 健康检查:
curl http://127.0.0.1:8000/health→{"status":"ok"} - 生产请单 worker 运行(不要加
--workers > 1):结算周期任务(推荐激活/创作收益/超时关单)随进程内 lifespan 启动,多 worker 会重复执行。 - 生产建议用 systemd/supervisor 托管进程。
服务暴露的路径(Nginx 反代时用):
| 路径 | 说明 |
|---|---|
/api/v1/* |
App 全部业务接口 |
/api/v1/admin/* |
管理后台接口 |
/r/{code} |
推广 H5 落地页(邀请链接) |
/static/* |
本地文件存储(头像/封面/视频,未接 OSS 时) |
/health |
健康检查 |
3. 管理后台部署(admin/)
cd admin
npm ci
npm run build # 产物在 admin/dist/
Nginx 参考配置(同一站点托管后台 + 反代 API):
server {
listen 443 ssl;
server_name admin.example.com;
# ssl_certificate / ssl_certificate_key ...
root /path/to/video/admin/dist;
index index.html;
location / { try_files $uri $uri/ /index.html; } # SPA 回退
location /api/ { proxy_pass http://127.0.0.1:8000; } # 后台接口
location /static/ { proxy_pass http://127.0.0.1:8000; } # 媒体文件
location /r/ { proxy_pass http://127.0.0.1:8000; } # 推广落地页
}
浏览器访问 https://admin.example.com,用 2.3 创建的账号登录。
4. App 编译(app/)—— 需要编译
App 是 Flutter 工程,必须编译出安装包分发给用户,服务器上不运行 App。
4.1 关键:App 如何找到服务器(不硬编码域名)
启动时按优先级确定 API Base URL(api_domain.dart):
--dart-define=API_BASE编译期指定(测试/自建最简单);- 本地缓存的上次成功域名;
- DNS TXT 发现:解析
txt.256kb.top的 TXT 记录,记录内容即 Base URL 主体; - 兜底域名:
md5(yyyyMM) + "_jsnbhh.vip"(每月变化)。
注意:客户端业务路径不带
/api/v1前缀,因此 Base URL 必须包含前缀,例如https://api.example.com/api/v1(TXT 记录内容写api.example.com/api/v1即可,客户端自动补https://)。
上线二选一:
- 方式 A(推荐,免改代码):把
txt.256kb.top的 TXT 记录指到你的 API 入口(内容:api.example.com/api/v1),并按第 3 节方式用 Nginx 把/api/v1/反代到 uvicorn。 - 方式 B(自己的域名体系):修改 app_config.dart 的
dnsTxtHost/fallbackDomainSuffix为你控制的域名后重新编译。
4.2 Android
cd app
flutter pub get
# 联调/内测:直连服务器
flutter build apk --release --dart-define=API_BASE=https://api.example.com/api/v1
# 正式(走 TXT 域名发现):不带 dart-define 直接构建
flutter build apk --release
产物:build/app/outputs/flutter-apk/app-release.apk,直接分发安装即可。
4.3 iOS
flutter build ipa --release
需要 macOS + Xcode + Apple 开发者证书签名(本机未装 Xcode 时可只交付 Android)。iOS 端上架前在管理后台「系统配置」确认 ios_payment.enabled 开关(规避苹果虚拟支付审核)。
4.4 支付渠道打包注意
app/pubspec.yaml 中 tobias.url_scheme、fluwx.app_id、两处 universal_link 是占位值,正式支付上线前必须替换为商户申请的真实值并重新编译;未接真实支付时服务端返回 dev_mock,App 自动走轮询查单兜底。
5. 上线后必改的后台配置
登录管理后台「系统配置」:
| 配置 key | 说明 |
|---|---|
app.invite_base_url |
推广落地页地址,改为 https://你的域名/r/(影响 App 邀请链接) |
app.version.android / app.version.ios |
JSON:latest_version / latest_version_code / min_version_code / update_url / notice,控制版本检查与强制更新 |
ios_payment.enabled |
iOS 支付开关(审核期可关闭) |
| 敏感词、轮播公告等 | 按需 |
6. 端到端验证清单
# 服务端
curl http://127.0.0.1:8000/health # ok
curl "http://127.0.0.1:8000/api/v1/videos/feed?type=hot&limit=1" # code:0
curl "http://127.0.0.1:8000/api/v1/search/hot" # code:0
# 管理后台:浏览器打开 → 登录 → 视频审核/用户列表有数据
# App:安装 APK → 启动页过版本检查 → Feed 出视频 → 注册/登录 → 观看计费
7. 已知限制(当前版本)
- 媒体存储为本地文件(
server/uploads,经/static访问),接口返回相对路径;生产接入 OSS/CDN 使服务端返回绝对 URL 需二次开发(storage_service已按此边界隔离)。 - 短信/邮件/USDT/支付宝/微信未配置密钥时自动降级(验证码发不出、支付走 dev_mock),不影响其余功能。
- CORS 当前为
*,生产可在app/main.py按需收紧。 - 结算周期任务在 API 进程内运行,见 2.4 单 worker 说明。