This commit is contained in:
lz_db
2026-10-25 11:46:44 +08:00
parent 893dfed0ed
commit 494f667719
63 changed files with 5213 additions and 239 deletions
+247 -17
View File
@@ -207,35 +207,249 @@ npm run build # 产物直接覆盖 admin/dist/,即 vm 站点根目录
## 6. nginx 配置(宝塔管理)
配置文件:`/www/server/panel/vhost/nginx/{h5,vm,vapi,codeserver}.256kb.top.conf`。
配置文件:`/www/server/panel/vhost/nginx/{h5,vm,vapi}.256kb.top.conf`。
改配置在宝塔面板「网站 → 设置 → 配置文件」编辑,或改文件后 `nginx -t && nginx -s reload`。
关键规则摘要:
证书路径(acme.sh ECC 证书,自动续期):
- `/www/server/panel/vhost/cert/<域名>/fullchain.pem`
- `/www/server/panel/vhost/cert/<域名>/privkey.pem`
**h5.256kb.top**
站点日志在 `/www/wwwlogs/<域名>.log` 和 `/www/wwwlogs/<域名>.error.log`(排查 App 接口 401/500 时非常管用)。
### 6.1 h5.256kb.top(用户下载页 + HLS 资源)
```nginx
root /root/project/video/h5; # index.html 下载页
location /downloads/ { alias /root/project/video/runtime/downloads/; } # APK
location /videos/ { alias /root/project/video/runtime/videos/; }
location /uploads/ { alias /root/project/video/runtime/uploads/; }
location /r/ { proxy_pass http://127.0.0.1:8000; } # 邀请落地
location /api/v1/invite/ { proxy_pass http://127.0.0.1:8000; }
server {
listen 80;
server_name h5.256kb.top;
# ACME 验证保留在 80,其余跳 HTTPS
location ^~ /.well-known/acme-challenge/ {
root /www/wwwroot/acme-challenge/;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
server_name h5.256kb.top;
ssl_certificate /www/server/panel/vhost/cert/h5.256kb.top/fullchain.pem;
ssl_certificate_key /www/server/panel/vhost/cert/h5.256kb.top/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:!MD5;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
index index.html;
root /root/project/video/h5;
location ^~ /.well-known/acme-challenge/ {
root /www/wwwroot/acme-challenge/;
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
}
# APK 下载
location /downloads/ {
alias /root/project/video/runtime/downloads/;
autoindex off;
}
# HLS 视频(hls.js 需要跨域 + 正确 MIME)
location /videos/ {
alias /root/project/video/runtime/videos/;
autoindex off;
add_header Access-Control-Allow-Origin *;
location ~* \.m3u8$ {
add_header Content-Type application/vnd.apple.mpegurl;
add_header Cache-Control "no-cache";
}
location ~* \.ts$ {
add_header Content-Type video/mp2t;
add_header Cache-Control "max-age=86400";
}
}
# 上传资源
location /uploads/ {
alias /root/project/video/runtime/uploads/;
autoindex off;
}
# 邀请注册落地页 → 后端
location /r/ {
proxy_pass http://127.0.0.1:8000;
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/v1/invite/ {
proxy_pass http://127.0.0.1:8000;
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;
}
access_log /www/wwwlogs/h5.256kb.top.log;
error_log /www/wwwlogs/h5.256kb.top.error.log;
}
```
**vm.256kb.top**
### 6.2 vm.256kb.top(管理后台 Vue SPA + 后端 API)
```nginx
root /root/project/video/admin/dist;
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; }
server {
listen 80;
server_name vm.256kb.top;
location ^~ /.well-known/acme-challenge/ {
root /www/wwwroot/acme-challenge/;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
server_name vm.256kb.top;
ssl_certificate /www/server/panel/vhost/cert/vm.256kb.top/fullchain.pem;
ssl_certificate_key /www/server/panel/vhost/cert/vm.256kb.top/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:!MD5;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
index index.html;
root /root/project/video/admin/dist;
location ^~ /.well-known/acme-challenge/ {
root /www/wwwroot/acme-challenge/;
}
location ~ /\. {
deny all;
}
# 后端 API
location /api/ {
proxy_pass http://127.0.0.1:8000;
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;
}
# 后端本地静态资源(uploads 挂载点)
location /static/ {
proxy_pass http://127.0.0.1:8000;
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;
}
# 邀请落地页
location /r/ {
proxy_pass http://127.0.0.1:8000;
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;
}
# Vue SPA history 路由回退
location / {
try_files $uri $uri/ /index.html;
}
access_log /www/wwwlogs/vm.256kb.top.log;
error_log /www/wwwlogs/vm.256kb.top.error.log;
}
```
**vapi.256kb.top**:`location / { proxy_pass http://127.0.0.1:8000; }` 全量反代。
### 6.3 vapi.256kb.top(App 接口域名,全量反代)
站点日志在 `/www/wwwlogs/<域名>.log`(排查 App 接口 401/500 时非常管用)。
```nginx
server {
listen 80;
server_name vapi.256kb.top;
location ^~ /.well-known/acme-challenge/ {
root /www/wwwroot/acme-challenge/;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
server_name vapi.256kb.top;
ssl_certificate /www/server/panel/vhost/cert/vapi.256kb.top/fullchain.pem;
ssl_certificate_key /www/server/panel/vhost/cert/vapi.256kb.top/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:!MD5;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
location ^~ /.well-known/acme-challenge/ {
root /www/wwwroot/acme-challenge/;
}
location ~ /\. {
deny all;
}
# 全部反代到 FastAPI
location / {
proxy_pass http://127.0.0.1:8000;
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;
# 上传大视频需要
client_max_body_size 500m;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
access_log /www/wwwlogs/vapi.256kb.top.log;
error_log /www/wwwlogs/vapi.256kb.top.error.log;
}
```
### 6.4 证书签发与续期(acme.sh)
```bash
# 首次签发(三个域名各一次,ECC 证书)
~/.acme.sh/acme.sh --issue -d h5.256kb.top --webroot /www/wwwroot/acme-challenge/ --keylength ec-256
~/.acme.sh/acme.sh --issue -d vm.256kb.top --webroot /www/wwwroot/acme-challenge/ --keylength ec-256
~/.acme.sh/acme.sh --issue -d vapi.256kb.top --webroot /www/wwwroot/acme-challenge/ --keylength ec-256
# 安装到宝塔证书目录(签发后 acme.sh 会自动 deploy 到 reloadcmd)
~/.acme.sh/acme.sh --install-cert -d h5.256kb.top --ecc \
--fullchain-file /www/server/panel/vhost/cert/h5.256kb.top/fullchain.pem \
--key-file /www/server/panel/vhost/cert/h5.256kb.top/privkey.pem \
--reloadcmd "nginx -t && nginx -s reload"
# vm / vapi 同理
# acme.sh 已在 crontab 注册续期任务,可用以下命令查看
crontab -l | grep acme
```
### 6.5 检查/排错
```bash
nginx -t # 校验语法
nginx -s reload # 平滑重载
nginx -T | grep -A 20 'server_name vm' # 看实际生效配置
tail -f /www/wwwlogs/vapi.256kb.top.error.log
```
## 7. App 编译与发版
@@ -339,6 +553,8 @@ curl -I https://h5.256kb.top/downloads/video-app.apk # 200
## 11. 新环境从零部署速查
**手动步骤**(理解流程用):
1. 装 Docker / Python3.11 / Node18+ / Flutter / nginx(或宝塔)
2. 建 mysql8、my-redis 容器(§3 命令)
3. `server/` 建 venv、装依赖、写 `.env`、`alembic upgrade head`、建超管(§4.3)
@@ -347,3 +563,17 @@ curl -I https://h5.256kb.top/downloads/video-app.apk # 200
6. App:放入 keystore + key.properties → `deploy.sh` 发版(§7)
7. 后台「系统配置」:`app.invite_base_url`、`app.version.android/ios` 等(见 03 接口文档配置键)
8. 跑 §10.3 验证清单
**一键脚本**(推荐,已封装上面 1-6 步):
```bash
bash /root/project/video/deploy-full.sh # 完整执行(首次部署)
bash /root/project/video/deploy-full.sh --skip-apk # 已有 APK 跳过 App 编译
bash /root/project/video/deploy-full.sh --skip-nginx # nginx 已配好,仅重启服务
bash /root/project/video/deploy-full.sh --skip-admin # 跳过 admin 前端构建
bash /root/project/video/deploy-full.sh --only-backend # 只重启后端 + 健康检查
```
`deploy-full.sh` 与 `deploy.sh` 的区别:
- `deploy.sh`:App 发版专用(编译 APK → 部署 → 同步 DB 版本号),日常迭代用
- `deploy-full.sh`:整栈首装/重装/迁移恢复,覆盖 Docker / 后端 / nginx / 后台前端 / 证书 / APK