chore: harden build and deployment workflow
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
name: Backend tests
|
||||
name: Build and tests
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -20,10 +20,23 @@ jobs:
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
cache: npm
|
||||
cache-dependency-path: backend/package-lock.json
|
||||
cache-dependency-path: |
|
||||
backend/package-lock.json
|
||||
frontend/package-lock.json
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Audit production dependencies
|
||||
run: npm audit --omit=dev
|
||||
- name: Run backend tests
|
||||
run: npm test
|
||||
- name: Install frontend dependencies
|
||||
working-directory: frontend
|
||||
run: npm ci
|
||||
- name: Audit frontend dependencies
|
||||
working-directory: frontend
|
||||
run: npm audit
|
||||
- name: Build frontend
|
||||
working-directory: frontend
|
||||
run: npm run build
|
||||
- name: Validate deployment script syntax
|
||||
run: bash -n ../install.sh
|
||||
|
||||
35
CONTRIBUTING.md
Normal file
35
CONTRIBUTING.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# 贡献与工程约束
|
||||
|
||||
## 本地验证
|
||||
|
||||
项目要求 Node.js `20.19` 至 `24.x`。后端与 Web 前端分别维护锁文件,依赖变更后必须同步提交对应的 `package-lock.json`。
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
npm ci
|
||||
npm test
|
||||
npm audit --omit=dev
|
||||
|
||||
cd ../frontend
|
||||
npm ci
|
||||
npm run build
|
||||
npm audit
|
||||
```
|
||||
|
||||
开发 Web 前端时分别运行后端 `npm run dev` 与前端 `npm run dev`。生产环境只服务 `frontend/dist/`,不要手工修改构建产物或给资源 URL 追加版本号。
|
||||
|
||||
## 不可破坏的约束
|
||||
|
||||
1. `app.use(expressErrorHandler)` 必须保持为最后一个 `app.use`;CI 的架构测试会检查这一点。
|
||||
2. Express 4 使用 `express-async-errors` 捕获异步路由拒绝;该补丁必须在注册任何路由前加载。
|
||||
3. 限流器、下载安全计数和 OSS 用量缓存仍是进程内状态,PM2 必须保持单实例 `fork` 模式。扩容前先迁移到共享状态存储。
|
||||
4. `npm ci` 依赖严格同步的 lock 文件;禁止在部署脚本中删除 `package-lock.json`。
|
||||
5. Express 中间件顺序是安全边界:requestId/安全头/CORS/HTTPS/静态资源/API 限流/请求体/CSRF,不得无验证调整。
|
||||
6. 桌面安装包目录 `frontend/downloads/` 是运行时发布目录,更新前必须备份且不得放进 `frontend/dist/` 的清理生命周期。
|
||||
|
||||
## 改动原则
|
||||
|
||||
- 路由继续按业务域渐进迁移,每次只迁移一个域并运行全部测试。
|
||||
- 新抽取的纯函数必须直接测试生产模块;禁止在测试文件复制实现。
|
||||
- 安全或配额核心逻辑应做一次变异验证:临时改坏生产实现,确认对应测试失败后立即还原。
|
||||
- 日志使用 `req.log` 或公共 logger,禁止记录密码、令牌、Cookie、Access Key 或完整授权头。
|
||||
@@ -10,7 +10,7 @@
|
||||
- **磁盘空间**: 至少 2GB 可用空间
|
||||
|
||||
### 软件依赖
|
||||
- **Node.js**: 20.x LTS
|
||||
- **Node.js**: 20.19+(支持 20.19-24)
|
||||
- **Nginx**: 1.18+
|
||||
- **Git**: 2.x
|
||||
|
||||
@@ -27,7 +27,7 @@ curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||||
sudo apt-get install -y nodejs
|
||||
|
||||
# 验证安装
|
||||
node -v # 应显示 v20.x.x
|
||||
node -v # 应显示 v20.19.0 或更高版本
|
||||
npm -v
|
||||
```
|
||||
|
||||
@@ -88,6 +88,19 @@ npm ci --omit=dev
|
||||
mkdir -p data storage
|
||||
```
|
||||
|
||||
### 4.1 构建 Web 前端
|
||||
|
||||
```bash
|
||||
cd /var/www/wanwanyun/frontend
|
||||
|
||||
# Vite 是构建依赖,生产构建时也必须安装 devDependencies
|
||||
npm ci --include=dev
|
||||
npm run build
|
||||
|
||||
# Nginx 只需要 dist,可按需释放依赖占用
|
||||
rm -rf node_modules
|
||||
```
|
||||
|
||||
### 5. 配置环境变量
|
||||
|
||||
```bash
|
||||
@@ -115,7 +128,8 @@ ADMIN_PASSWORD=你的强密码
|
||||
sudo cp /var/www/wanwanyun/nginx/nginx.conf /etc/nginx/sites-available/wanwanyun
|
||||
|
||||
# 修改配置中的路径
|
||||
sudo sed -i 's|/usr/share/nginx/html|/var/www/wanwanyun/frontend|g' /etc/nginx/sites-available/wanwanyun
|
||||
sudo sed -i 's|/usr/share/nginx/html|/var/www/wanwanyun/frontend/dist|g' /etc/nginx/sites-available/wanwanyun
|
||||
sudo sed -i 's|/runtime/downloads|/var/www/wanwanyun/frontend/downloads|g' /etc/nginx/sites-available/wanwanyun
|
||||
sudo sed -i 's|backend:40001|127.0.0.1:40001|g' /etc/nginx/sites-available/wanwanyun
|
||||
|
||||
# 创建软链接启用配置
|
||||
@@ -245,6 +259,7 @@ sudo tail -f /var/log/nginx/error.log
|
||||
cd /var/www/wanwanyun
|
||||
sudo git pull
|
||||
cd backend && npm ci --omit=dev
|
||||
cd ../frontend && npm ci --include=dev && npm run build && rm -rf node_modules
|
||||
sudo systemctl restart wanwanyun
|
||||
```
|
||||
|
||||
@@ -294,14 +309,9 @@ sudo chown -R www-data:www-data /var/www/wanwanyun/backend/data/
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 启用 Nginx 缓存
|
||||
在 Nginx 配置的 `location /` 中添加:
|
||||
```nginx
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
```
|
||||
### Nginx 静态缓存
|
||||
|
||||
仓库配置已经对 Vite 哈希资源 `/assets/` 设置一年缓存,对兼容库 `/libs/` 设置 30 天缓存。不要在子 `location` 中单独使用 `add_header Cache-Control`,否则会覆盖上层继承的安全响应头。
|
||||
|
||||
### 配置日志轮转
|
||||
```bash
|
||||
|
||||
44
README.md
44
README.md
@@ -6,7 +6,7 @@
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
</div>
|
||||
@@ -72,7 +72,7 @@
|
||||
### 环境要求
|
||||
|
||||
- **操作系统**: Linux (Ubuntu 18.04+ / Debian 10+ / CentOS 7+)
|
||||
- **Node.js**: 20.x LTS(支持 20-24,推荐与 `.nvmrc` 保持一致)
|
||||
- **Node.js**: 20.19+(支持 20.19-24,推荐与 `.nvmrc` 保持一致)
|
||||
- **内存**: 最低 1GB RAM(推荐 2GB+)
|
||||
- **磁盘空间**: 至少 2GB 可用空间
|
||||
- **后端实例数**: 当前限流与用量缓存为进程内状态,PM2 必须保持单实例 `fork` 模式
|
||||
@@ -234,13 +234,16 @@ vue-driven-cloud-storage/
|
||||
│ ├── data/ # 数据库目录
|
||||
│ └── storage/ # 本地存储目录
|
||||
│
|
||||
├── frontend/ # 前端代码
|
||||
├── frontend/ # Vite 多页面 Web 前端
|
||||
│ ├── index.html # 登录注册页面
|
||||
│ ├── app.html # 主应用页面
|
||||
│ ├── share.html # 分享页面
|
||||
│ ├── verify.html # 邮箱验证页面
|
||||
│ ├── reset-password.html # 密码重置页面
|
||||
│ └── libs/ # 第三方库 (Vue.js, Axios, FontAwesome)
|
||||
│ ├── package.json # Vue/Axios/Vite 依赖
|
||||
│ ├── vite.config.js # 多页面生产构建
|
||||
│ ├── dist/ # 构建产物(不入库)
|
||||
│ └── libs/ # 分享页兼容静态资源与 Font Awesome
|
||||
│
|
||||
├── nginx/ # Nginx 配置
|
||||
│ ├── nginx.conf # 反向代理配置
|
||||
@@ -272,6 +275,7 @@ vue-driven-cloud-storage/
|
||||
### 前端技术
|
||||
- **Vue.js 3** - 渐进式 JavaScript 框架
|
||||
- **Axios** - HTTP 请求库
|
||||
- **Vite 8** - 多页面构建、依赖打包与哈希缓存
|
||||
- **Font Awesome** - 图标库
|
||||
- **原生 CSS** - 现代化界面设计
|
||||
|
||||
@@ -310,7 +314,7 @@ vue-driven-cloud-storage/
|
||||
|
||||
```bash
|
||||
# Systemd 部署
|
||||
sudo systemctl status vue-cloud-storage
|
||||
sudo systemctl status wanwanyun
|
||||
|
||||
# Docker 部署
|
||||
docker-compose ps
|
||||
@@ -320,7 +324,7 @@ docker-compose ps
|
||||
|
||||
```bash
|
||||
# Systemd 部署
|
||||
sudo journalctl -u vue-cloud-storage -f
|
||||
sudo journalctl -u wanwanyun -f
|
||||
|
||||
# Docker 部署
|
||||
docker-compose logs -f backend
|
||||
@@ -330,7 +334,7 @@ docker-compose logs -f backend
|
||||
|
||||
```bash
|
||||
# Systemd 部署
|
||||
sudo systemctl restart vue-cloud-storage
|
||||
sudo systemctl restart wanwanyun
|
||||
|
||||
# Docker 部署
|
||||
docker-compose restart
|
||||
@@ -340,23 +344,26 @@ docker-compose restart
|
||||
|
||||
```bash
|
||||
# 备份数据库
|
||||
sudo cp /var/www/vue-driven-cloud-storage/backend/data/database.db \
|
||||
sudo cp /var/www/wanwanyun/backend/data/database.db \
|
||||
/backup/database.db.$(date +%Y%m%d)
|
||||
|
||||
# 备份上传文件(本地存储模式)
|
||||
sudo tar -czf /backup/uploads-$(date +%Y%m%d).tar.gz \
|
||||
/var/www/vue-driven-cloud-storage/backend/storage/
|
||||
/var/www/wanwanyun/backend/storage/
|
||||
```
|
||||
|
||||
### 更新系统
|
||||
|
||||
```bash
|
||||
cd /var/www/vue-driven-cloud-storage
|
||||
cd /var/www/wanwanyun
|
||||
git pull
|
||||
cd backend && npm install
|
||||
sudo systemctl restart vue-cloud-storage
|
||||
cd backend && npm ci --omit=dev
|
||||
cd ../frontend && npm ci --include=dev && npm run build
|
||||
sudo systemctl restart wanwanyun
|
||||
```
|
||||
|
||||
`install.sh --update` 会在替换线上文件前构建前端,并保留 `frontend/downloads/` 中由管理端发布的桌面安装包。完整工程约束见 [CONTRIBUTING.md](./CONTRIBUTING.md)。
|
||||
|
||||
## 📊 性能优化建议
|
||||
|
||||
### 生产环境配置
|
||||
@@ -401,7 +408,7 @@ A: 当前默认限制 10GB,可在系统设置和 Nginx 配置中同步调整
|
||||
### 故障排查
|
||||
|
||||
**Q: 无法访问系统**
|
||||
1. 检查服务是否启动:`sudo systemctl status vue-cloud-storage`
|
||||
1. 检查服务是否启动:`sudo systemctl status wanwanyun`
|
||||
2. 检查防火墙是否开放端口
|
||||
3. 查看 Nginx 日志:`sudo tail -f /var/log/nginx/error.log`
|
||||
|
||||
@@ -484,11 +491,14 @@ A: 当前默认限制 10GB,可在系统设置和 Nginx 配置中同步调整
|
||||
git clone https://git.workyai.cn/237899745/vue-driven-cloud-storage.git
|
||||
cd vue-driven-cloud-storage
|
||||
|
||||
# 安装依赖
|
||||
cd backend && npm install
|
||||
# 安装并测试后端
|
||||
cd backend && npm ci && npm test
|
||||
|
||||
# 启动开发服务器
|
||||
node server.js
|
||||
# 终端一:启动后端
|
||||
npm run dev
|
||||
|
||||
# 终端二:启动 Vite(项目根目录执行)
|
||||
cd ../frontend && npm ci && npm run dev
|
||||
```
|
||||
|
||||
### 提交规范
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
# 3. 访问: http://localhost (或配置的域名)
|
||||
# ============================================
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# ============================================
|
||||
# 后端服务
|
||||
@@ -32,6 +30,8 @@ services:
|
||||
# 数据持久化
|
||||
- ./backend/data:/app/data
|
||||
- ./backend/storage:/app/storage
|
||||
# 桌面安装包由管理端发布,前后端共享此目录
|
||||
- ./frontend/downloads:/frontend/downloads
|
||||
networks:
|
||||
- wanwanyun-network
|
||||
healthcheck:
|
||||
@@ -45,15 +45,17 @@ services:
|
||||
# Nginx 前端服务
|
||||
# ============================================
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile
|
||||
container_name: wanwanyun-nginx
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
# 前端静态文件
|
||||
- ./frontend:/usr/share/nginx/html:ro
|
||||
# 动态发布的桌面安装包覆盖镜像内初始版本
|
||||
- ./frontend/downloads:/runtime/downloads:ro
|
||||
# Nginx 配置
|
||||
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
# SSL 证书(如有)
|
||||
|
||||
3
frontend/.dockerignore
Normal file
3
frontend/.dockerignore
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
dist
|
||||
npm-debug.log*
|
||||
13
frontend/Dockerfile
Normal file
13
frontend/Dockerfile
Normal file
@@ -0,0 +1,13 @@
|
||||
FROM node:20-alpine AS build
|
||||
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
FROM nginx:alpine
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
COPY --from=build /app/downloads /runtime/downloads
|
||||
|
||||
EXPOSE 80
|
||||
278
install.sh
278
install.sh
@@ -35,6 +35,7 @@ PROJECT_NAME="wanwanyun"
|
||||
PROJECT_DIR="/var/www/${PROJECT_NAME}"
|
||||
REPO_URL="https://git.workyai.cn/237899745/vue-driven-cloud-storage.git"
|
||||
NODE_VERSION="20"
|
||||
NODE_MIN_VERSION="20.19.0"
|
||||
ADMIN_USERNAME=""
|
||||
ADMIN_PASSWORD=""
|
||||
DOMAIN=""
|
||||
@@ -529,13 +530,17 @@ install_dependencies() {
|
||||
echo ""
|
||||
}
|
||||
|
||||
node_version_supported() {
|
||||
node -e "const [major, minor] = process.versions.node.split('.').map(Number); process.exit((major > 20 && major < 25) || (major === 20 && minor >= 19) ? 0 : 1)" 2>/dev/null
|
||||
}
|
||||
|
||||
install_nodejs_apt() {
|
||||
if command -v node &> /dev/null; then
|
||||
NODE_VER=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
|
||||
if [[ $NODE_VER -ge $NODE_VERSION ]]; then
|
||||
if node_version_supported; then
|
||||
print_success "Node.js 已安装: $(node -v)"
|
||||
return
|
||||
fi
|
||||
print_warning "当前 Node.js $(node -v) 不满足 ${NODE_MIN_VERSION} 至 24.x,准备安装 20.x"
|
||||
fi
|
||||
|
||||
print_info "正在安装 Node.js ${NODE_VERSION}.x..."
|
||||
@@ -546,11 +551,11 @@ install_nodejs_apt() {
|
||||
|
||||
install_nodejs_yum() {
|
||||
if command -v node &> /dev/null; then
|
||||
NODE_VER=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
|
||||
if [[ $NODE_VER -ge $NODE_VERSION ]]; then
|
||||
if node_version_supported; then
|
||||
print_success "Node.js 已安装: $(node -v)"
|
||||
return
|
||||
fi
|
||||
print_warning "当前 Node.js $(node -v) 不满足 ${NODE_MIN_VERSION} 至 24.x,准备安装 20.x"
|
||||
fi
|
||||
|
||||
print_info "正在安装 Node.js ${NODE_VERSION}.x..."
|
||||
@@ -585,11 +590,11 @@ install_nginx_yum() {
|
||||
|
||||
install_nodejs_dnf() {
|
||||
if command -v node &> /dev/null; then
|
||||
NODE_VER=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
|
||||
if [[ $NODE_VER -ge $NODE_VERSION ]]; then
|
||||
if node_version_supported; then
|
||||
print_success "Node.js 已安装: $(node -v)"
|
||||
return
|
||||
fi
|
||||
print_warning "当前 Node.js $(node -v) 不满足 ${NODE_MIN_VERSION} 至 24.x,准备安装 20.x"
|
||||
fi
|
||||
|
||||
print_info "正在安装 Node.js ${NODE_VERSION}.x..."
|
||||
@@ -612,11 +617,11 @@ install_nginx_dnf() {
|
||||
|
||||
install_nodejs_zypper() {
|
||||
if command -v node &> /dev/null; then
|
||||
NODE_VER=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
|
||||
if [[ $NODE_VER -ge $NODE_VERSION ]]; then
|
||||
if node_version_supported; then
|
||||
print_success "Node.js 已安装: $(node -v)"
|
||||
return
|
||||
fi
|
||||
print_warning "当前 Node.js $(node -v) 不满足 ${NODE_MIN_VERSION} 至 24.x,准备安装 20.x"
|
||||
fi
|
||||
|
||||
print_info "正在安装 Node.js ${NODE_VERSION}.x..."
|
||||
@@ -1390,7 +1395,7 @@ deploy_certbot() {
|
||||
echo ""
|
||||
print_info "正在申请 Let's Encrypt 证书..."
|
||||
|
||||
if certbot certonly --webroot -w "${PROJECT_DIR}/frontend" -d "$DOMAIN" --non-interactive --agree-tos --email "admin@${DOMAIN}"; then
|
||||
if certbot certonly --webroot -w "${PROJECT_DIR}/frontend/dist" -d "$DOMAIN" --non-interactive --agree-tos --email "admin@${DOMAIN}"; then
|
||||
# 将证书复制到Nginx SSL目录
|
||||
mkdir -p /etc/nginx/ssl
|
||||
ln -sf "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" "/etc/nginx/ssl/${DOMAIN}.crt"
|
||||
@@ -1541,7 +1546,7 @@ deploy_acme_letsencrypt() {
|
||||
|
||||
# 使用webroot模式申请证书(更可靠)
|
||||
# 先尝试正常申请,如果证书已存在则使用--force强制更新
|
||||
if ~/.acme.sh/acme.sh --issue -d "$DOMAIN" --webroot "${PROJECT_DIR}/frontend"; then
|
||||
if ~/.acme.sh/acme.sh --issue -d "$DOMAIN" --webroot "${PROJECT_DIR}/frontend/dist"; then
|
||||
print_success "证书申请成功"
|
||||
else
|
||||
# 检查是否是因为证书已存在
|
||||
@@ -1707,7 +1712,7 @@ deploy_acme_zerossl() {
|
||||
fi
|
||||
|
||||
# 使用webroot模式申请证书(更可靠)
|
||||
if ~/.acme.sh/acme.sh --server zerossl --issue -d "$DOMAIN" --webroot "${PROJECT_DIR}/frontend"; then
|
||||
if ~/.acme.sh/acme.sh --server zerossl --issue -d "$DOMAIN" --webroot "${PROJECT_DIR}/frontend/dist"; then
|
||||
print_success "证书申请成功"
|
||||
else
|
||||
# 检查是否是因为证书已存在
|
||||
@@ -1866,7 +1871,7 @@ deploy_acme_buypass() {
|
||||
fi
|
||||
|
||||
# 使用webroot模式申请证书(更可靠)
|
||||
if ~/.acme.sh/acme.sh --server buypass --issue -d "$DOMAIN" --webroot "${PROJECT_DIR}/frontend"; then
|
||||
if ~/.acme.sh/acme.sh --server buypass --issue -d "$DOMAIN" --webroot "${PROJECT_DIR}/frontend/dist"; then
|
||||
print_success "证书申请成功"
|
||||
else
|
||||
# 检查是否是因为证书已存在
|
||||
@@ -2113,6 +2118,26 @@ install_backend_dependencies() {
|
||||
echo ""
|
||||
}
|
||||
|
||||
install_frontend_dependencies() {
|
||||
print_step "安装前端依赖并构建生产资源..."
|
||||
|
||||
cd "${PROJECT_DIR}/frontend"
|
||||
if [[ ! -f "package-lock.json" ]]; then
|
||||
print_error "前端 package-lock.json 不存在,无法执行可重复构建"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if npm ci --include=dev && npm run build; then
|
||||
rm -rf node_modules
|
||||
print_success "前端生产资源构建完成"
|
||||
else
|
||||
print_error "前端构建失败"
|
||||
print_info "可手动重试: cd ${PROJECT_DIR}/frontend && npm ci --include=dev && npm run build"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
create_env_file() {
|
||||
print_step "创建配置文件..."
|
||||
|
||||
@@ -2212,6 +2237,15 @@ PUBLIC_PORT=${HTTP_PORT}
|
||||
# CSRF 保护(生产环境强烈建议开启)
|
||||
# 使用 Double Submit Cookie 模式防止跨站请求伪造攻击
|
||||
ENABLE_CSRF=true
|
||||
|
||||
# 全局 API 限流与健康检查阈值
|
||||
API_RATE_LIMIT_WINDOW_MS=60000
|
||||
API_RATE_LIMIT_MAX=600
|
||||
HEALTH_MIN_DISK_FREE_BYTES=268435456
|
||||
|
||||
# 结构化日志
|
||||
LOG_LEVEL=info
|
||||
LOG_FORMAT=json
|
||||
EOF
|
||||
|
||||
print_success "配置文件创建完成"
|
||||
@@ -2369,7 +2403,9 @@ server {
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "no-referrer-when-downgrade" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Permissions-Policy "camera=(), geolocation=(), microphone=()" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; media-src 'self' blob: https:; connect-src 'self' https: ws: wss:; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self';" always;
|
||||
|
||||
# 隐藏Nginx版本号
|
||||
server_tokens off;
|
||||
@@ -2388,11 +2424,21 @@ server {
|
||||
|
||||
# 前端静态文件
|
||||
location / {
|
||||
root ${PROJECT_DIR}/frontend;
|
||||
root ${PROJECT_DIR}/frontend/dist;
|
||||
index index.html;
|
||||
try_files \$uri \$uri/ =404;
|
||||
}
|
||||
|
||||
location /assets/ {
|
||||
alias ${PROJECT_DIR}/frontend/dist/assets/;
|
||||
expires 1y;
|
||||
}
|
||||
|
||||
location /downloads/ {
|
||||
alias ${PROJECT_DIR}/frontend/downloads/;
|
||||
expires 1h;
|
||||
}
|
||||
|
||||
# 后端API
|
||||
location /api {
|
||||
proxy_pass http://localhost:${BACKEND_PORT};
|
||||
@@ -2404,6 +2450,7 @@ server {
|
||||
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_set_header X-Request-ID \$request_id;
|
||||
|
||||
# Cookie传递配置(验证码session需要)
|
||||
proxy_set_header Cookie \$http_cookie;
|
||||
@@ -2422,15 +2469,15 @@ server {
|
||||
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_set_header X-Request-ID \$request_id;
|
||||
}
|
||||
|
||||
# 静态资源
|
||||
location /libs {
|
||||
alias ${PROJECT_DIR}/frontend/libs;
|
||||
location /libs/ {
|
||||
alias ${PROJECT_DIR}/frontend/dist/libs/;
|
||||
expires 30d;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
@@ -2656,7 +2703,9 @@ server {
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "no-referrer-when-downgrade" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Permissions-Policy "camera=(), geolocation=(), microphone=()" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; media-src 'self' blob: https:; connect-src 'self' https: ws: wss:; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self';" always;
|
||||
|
||||
# 隐藏Nginx版本号
|
||||
server_tokens off;
|
||||
@@ -2675,11 +2724,21 @@ server {
|
||||
|
||||
# 前端静态文件
|
||||
location / {
|
||||
root ${PROJECT_DIR}/frontend;
|
||||
root ${PROJECT_DIR}/frontend/dist;
|
||||
index index.html;
|
||||
try_files \$uri \$uri/ =404;
|
||||
}
|
||||
|
||||
location /assets/ {
|
||||
alias ${PROJECT_DIR}/frontend/dist/assets/;
|
||||
expires 1y;
|
||||
}
|
||||
|
||||
location /downloads/ {
|
||||
alias ${PROJECT_DIR}/frontend/downloads/;
|
||||
expires 1h;
|
||||
}
|
||||
|
||||
# 后端API
|
||||
location /api {
|
||||
proxy_pass http://localhost:${BACKEND_PORT};
|
||||
@@ -2691,6 +2750,7 @@ server {
|
||||
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_set_header X-Request-ID \$request_id;
|
||||
|
||||
# Cookie传递配置(验证码session需要)
|
||||
proxy_set_header Cookie \$http_cookie;
|
||||
@@ -2709,15 +2769,15 @@ server {
|
||||
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_set_header X-Request-ID \$request_id;
|
||||
}
|
||||
|
||||
# 静态资源
|
||||
location /libs {
|
||||
alias ${PROJECT_DIR}/frontend/libs;
|
||||
location /libs/ {
|
||||
alias ${PROJECT_DIR}/frontend/dist/libs/;
|
||||
expires 30d;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
@@ -2792,7 +2852,9 @@ server {
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "no-referrer-when-downgrade" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Permissions-Policy "camera=(), geolocation=(), microphone=()" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; media-src 'self' blob: https:; connect-src 'self' https: ws: wss:; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self';" always;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
|
||||
# 隐藏Nginx版本号
|
||||
@@ -2812,11 +2874,21 @@ server {
|
||||
|
||||
# 前端静态文件
|
||||
location / {
|
||||
root ${PROJECT_DIR}/frontend;
|
||||
root ${PROJECT_DIR}/frontend/dist;
|
||||
index index.html;
|
||||
try_files \$uri \$uri/ =404;
|
||||
}
|
||||
|
||||
location /assets/ {
|
||||
alias ${PROJECT_DIR}/frontend/dist/assets/;
|
||||
expires 1y;
|
||||
}
|
||||
|
||||
location /downloads/ {
|
||||
alias ${PROJECT_DIR}/frontend/downloads/;
|
||||
expires 1h;
|
||||
}
|
||||
|
||||
# 后端API
|
||||
location /api {
|
||||
proxy_pass http://localhost:${BACKEND_PORT};
|
||||
@@ -2828,6 +2900,7 @@ server {
|
||||
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_set_header X-Request-ID \$request_id;
|
||||
|
||||
# Cookie传递配置(验证码session需要)
|
||||
proxy_set_header Cookie \$http_cookie;
|
||||
@@ -2846,15 +2919,15 @@ server {
|
||||
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_set_header X-Request-ID \$request_id;
|
||||
}
|
||||
|
||||
# 静态资源
|
||||
location /libs {
|
||||
alias ${PROJECT_DIR}/frontend/libs;
|
||||
location /libs/ {
|
||||
alias ${PROJECT_DIR}/frontend/dist/libs/;
|
||||
expires 30d;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
@@ -3398,6 +3471,12 @@ update_backup_important_files() {
|
||||
print_success "配置文件已备份"
|
||||
fi
|
||||
|
||||
# 桌面安装包可能由管理端动态上传,不可随前端源码更新丢失
|
||||
if [[ -d "${PROJECT_DIR}/frontend/downloads" ]]; then
|
||||
cp -a "${PROJECT_DIR}/frontend/downloads" "$TEMP_BACKUP/frontend-downloads"
|
||||
print_success "桌面安装包已备份"
|
||||
fi
|
||||
|
||||
print_success "备份完成: $TEMP_BACKUP"
|
||||
echo ""
|
||||
}
|
||||
@@ -3424,6 +3503,23 @@ update_pull_latest_code() {
|
||||
# 克隆最新代码
|
||||
git clone "$REPO_URL" "${PROJECT_NAME}-update"
|
||||
|
||||
# 在替换线上文件前完成前端构建,失败时旧版本仍保持完整。
|
||||
if [[ -d "$TEMP_BACKUP/frontend-downloads" ]]; then
|
||||
mkdir -p "/tmp/${PROJECT_NAME}-update/frontend/downloads"
|
||||
cp -a "$TEMP_BACKUP/frontend-downloads/." "/tmp/${PROJECT_NAME}-update/frontend/downloads/"
|
||||
fi
|
||||
|
||||
print_info "构建前端生产资源..."
|
||||
cd "/tmp/${PROJECT_NAME}-update/frontend"
|
||||
if ! npm ci --include=dev || ! npm run build; then
|
||||
print_error "前端构建失败,线上文件未替换"
|
||||
if command -v pm2 &> /dev/null; then
|
||||
pm2 restart ${PROJECT_NAME}-backend || true
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
rm -rf node_modules
|
||||
|
||||
# 更新前端文件
|
||||
print_info "更新前端文件..."
|
||||
if [[ -d "/tmp/${PROJECT_NAME}-update/frontend" ]]; then
|
||||
@@ -3470,14 +3566,109 @@ update_pull_latest_code() {
|
||||
print_success "配置文件已恢复"
|
||||
fi
|
||||
|
||||
# 清理临时文件
|
||||
# 临时源码可删除,数据备份保留到健康检查通过后再清理
|
||||
rm -rf "/tmp/${PROJECT_NAME}-update"
|
||||
rm -rf "$TEMP_BACKUP"
|
||||
|
||||
print_success "代码更新完成"
|
||||
echo ""
|
||||
}
|
||||
|
||||
update_migrate_nginx_config() {
|
||||
print_step "迁移 Nginx 前端构建目录..."
|
||||
|
||||
local candidates=(
|
||||
"/www/server/panel/vhost/nginx/${PROJECT_NAME}.conf"
|
||||
"/etc/nginx/sites-available/${PROJECT_NAME}.conf"
|
||||
"/etc/nginx/conf.d/${PROJECT_NAME}.conf"
|
||||
)
|
||||
local migrated=false
|
||||
local backup_dir="$TEMP_BACKUP/nginx"
|
||||
mkdir -p "$backup_dir"
|
||||
|
||||
for config_file in "${candidates[@]}"; do
|
||||
[[ -f "$config_file" ]] || continue
|
||||
migrated=true
|
||||
|
||||
local backup_name
|
||||
backup_name=$(echo "$config_file" | tr '/ ' '__')
|
||||
cp -a "$config_file" "$backup_dir/$backup_name"
|
||||
|
||||
sed -i "s|root ${PROJECT_DIR}/frontend;|root ${PROJECT_DIR}/frontend/dist;|g" "$config_file"
|
||||
sed -i "s|location /libs {|location /libs/ {|g" "$config_file"
|
||||
sed -i "s|alias ${PROJECT_DIR}/frontend/libs;|alias ${PROJECT_DIR}/frontend/dist/libs/;|g" "$config_file"
|
||||
sed -i 's|Referrer-Policy "no-referrer-when-downgrade"|Referrer-Policy "strict-origin-when-cross-origin"|g' "$config_file"
|
||||
|
||||
if ! grep -q "add_header Permissions-Policy" "$config_file" || ! grep -q "add_header Content-Security-Policy" "$config_file"; then
|
||||
local secured_file="${config_file}.security.$$"
|
||||
local need_permissions=0
|
||||
local need_csp=0
|
||||
grep -q "add_header Permissions-Policy" "$config_file" || need_permissions=1
|
||||
grep -q "add_header Content-Security-Policy" "$config_file" || need_csp=1
|
||||
awk -v need_permissions="$need_permissions" -v need_csp="$need_csp" '
|
||||
/add_header Referrer-Policy/ && !inserted_security {
|
||||
print
|
||||
if (need_permissions == 1) {
|
||||
print " add_header Permissions-Policy \"camera=(), geolocation=(), microphone=()\" always;"
|
||||
}
|
||||
if (need_csp == 1) {
|
||||
print " add_header Content-Security-Policy \"default-src \047self\047; script-src \047self\047 \047unsafe-inline\047 \047unsafe-eval\047; style-src \047self\047 \047unsafe-inline\047; img-src \047self\047 data: blob: https:; font-src \047self\047 data:; media-src \047self\047 blob: https:; connect-src \047self\047 https: ws: wss:; worker-src \047self\047 blob:; object-src \047none\047; base-uri \047self\047; frame-ancestors \047self\047; form-action \047self\047;\" always;"
|
||||
}
|
||||
inserted_security = 1
|
||||
next
|
||||
}
|
||||
{ print }
|
||||
' "$config_file" > "$secured_file"
|
||||
mv "$secured_file" "$config_file"
|
||||
fi
|
||||
|
||||
if ! grep -q "location /downloads/" "$config_file"; then
|
||||
local migrated_file="${config_file}.migrate.$$"
|
||||
awk -v project_dir="$PROJECT_DIR" '
|
||||
/^[[:space:]]*# 静态资源/ && !inserted {
|
||||
print " # 桌面安装包由管理端动态发布,不属于 Vite dist"
|
||||
print " location /downloads/ {"
|
||||
print " alias " project_dir "/frontend/downloads/;"
|
||||
print " expires 1h;"
|
||||
print " }"
|
||||
print ""
|
||||
inserted = 1
|
||||
}
|
||||
{ print }
|
||||
' "$config_file" > "$migrated_file"
|
||||
mv "$migrated_file" "$config_file"
|
||||
fi
|
||||
|
||||
if ! grep -q "root ${PROJECT_DIR}/frontend/dist;" "$config_file" || ! grep -q "location /downloads/" "$config_file"; then
|
||||
print_error "无法安全迁移 Nginx 配置: $config_file"
|
||||
cp -a "$backup_dir/$backup_name" "$config_file"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$migrated" != "true" ]]; then
|
||||
print_warning "未找到 install.sh 管理的 Nginx 配置,请手动确认 root 指向 ${PROJECT_DIR}/frontend/dist"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! nginx -t; then
|
||||
print_error "迁移后的 Nginx 配置校验失败,正在恢复"
|
||||
for config_file in "${candidates[@]}"; do
|
||||
[[ -f "$config_file" ]] || continue
|
||||
local backup_name
|
||||
backup_name=$(echo "$config_file" | tr '/ ' '__')
|
||||
if [[ -f "$backup_dir/$backup_name" ]]; then
|
||||
cp -a "$backup_dir/$backup_name" "$config_file"
|
||||
fi
|
||||
done
|
||||
nginx -t || true
|
||||
return 1
|
||||
fi
|
||||
|
||||
restart_nginx_safe
|
||||
print_success "Nginx 已切换到 Vite 构建目录"
|
||||
echo ""
|
||||
}
|
||||
|
||||
update_install_dependencies() {
|
||||
print_step "更新后端依赖..."
|
||||
|
||||
@@ -3511,7 +3702,7 @@ update_install_dependencies() {
|
||||
check_cpp_compiler
|
||||
if [[ -d "node_modules" ]]; then
|
||||
print_info "清理旧依赖..."
|
||||
rm -rf node_modules package-lock.json
|
||||
rm -rf node_modules
|
||||
fi
|
||||
|
||||
print_info "正在重新安装依赖(可能需要几分钟)..."
|
||||
@@ -3521,6 +3712,7 @@ update_install_dependencies() {
|
||||
else
|
||||
print_error "依赖更新失败"
|
||||
print_warning "请检查错误日志: ~/.npm/_logs/"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
@@ -3750,6 +3942,23 @@ update_patch_env() {
|
||||
else
|
||||
print_info ".env 已包含 ENABLE_CSRF,保持不变"
|
||||
fi
|
||||
|
||||
if ! grep -q "^API_RATE_LIMIT_MAX=" "${PROJECT_DIR}/backend/.env"; then
|
||||
echo "API_RATE_LIMIT_WINDOW_MS=60000" >> "${PROJECT_DIR}/backend/.env"
|
||||
echo "API_RATE_LIMIT_MAX=600" >> "${PROJECT_DIR}/backend/.env"
|
||||
print_info "已补充全局 API 限流默认值"
|
||||
fi
|
||||
|
||||
if ! grep -q "^HEALTH_MIN_DISK_FREE_BYTES=" "${PROJECT_DIR}/backend/.env"; then
|
||||
echo "HEALTH_MIN_DISK_FREE_BYTES=268435456" >> "${PROJECT_DIR}/backend/.env"
|
||||
print_info "已补充健康检查磁盘阈值"
|
||||
fi
|
||||
|
||||
if ! grep -q "^LOG_FORMAT=" "${PROJECT_DIR}/backend/.env"; then
|
||||
echo "LOG_LEVEL=info" >> "${PROJECT_DIR}/backend/.env"
|
||||
echo "LOG_FORMAT=json" >> "${PROJECT_DIR}/backend/.env"
|
||||
print_info "已启用 JSON 结构化日志"
|
||||
fi
|
||||
else
|
||||
print_warning "未找到 ${PROJECT_DIR}/backend/.env,请手动确认配置"
|
||||
fi
|
||||
@@ -3815,6 +4024,9 @@ update_main() {
|
||||
# 拉取最新代码
|
||||
update_pull_latest_code
|
||||
|
||||
# 旧版本 Nginx 指向 frontend 源码,需迁移到 dist
|
||||
update_migrate_nginx_config
|
||||
|
||||
# 更新依赖
|
||||
|
||||
update_install_dependencies
|
||||
@@ -3831,9 +4043,12 @@ update_main() {
|
||||
if ! health_check; then
|
||||
print_error "健康检查未通过,请检查日志"
|
||||
print_info "查看日志: pm2 logs ${PROJECT_NAME}-backend"
|
||||
print_info "更新备份保留在: $TEMP_BACKUP"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf "$TEMP_BACKUP"
|
||||
|
||||
# 检查版本
|
||||
update_check_version
|
||||
|
||||
@@ -3951,6 +4166,9 @@ main() {
|
||||
# 安装后端依赖
|
||||
install_backend_dependencies
|
||||
|
||||
# 安装前端依赖并生成 dist
|
||||
install_frontend_dependencies
|
||||
|
||||
# 创建配置文件
|
||||
create_env_file
|
||||
|
||||
|
||||
@@ -9,7 +9,9 @@ server {
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "no-referrer-when-downgrade" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Permissions-Policy "camera=(), geolocation=(), microphone=()" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; media-src 'self' blob: https:; connect-src 'self' https: ws: wss:; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self';" always;
|
||||
|
||||
# 隐藏Nginx版本
|
||||
server_tokens off;
|
||||
@@ -32,6 +34,21 @@ server {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
location /assets/ {
|
||||
root /usr/share/nginx/html;
|
||||
expires 1y;
|
||||
}
|
||||
|
||||
location /libs/ {
|
||||
root /usr/share/nginx/html;
|
||||
expires 30d;
|
||||
}
|
||||
|
||||
location /downloads/ {
|
||||
alias /runtime/downloads/;
|
||||
expires 1h;
|
||||
}
|
||||
|
||||
# 后端API反向代理
|
||||
location /api/ {
|
||||
proxy_pass http://backend:40001;
|
||||
@@ -43,6 +60,7 @@ server {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# 修复:使用当前请求协议(http或https),适用于直接IP访问
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Request-ID $request_id;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
|
||||
# Cookie传递配置(验证码session需要)
|
||||
@@ -69,5 +87,6 @@ server {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# 修复:使用当前请求协议(http或https),适用于直接IP访问
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Request-ID $request_id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@ server {
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Permissions-Policy "camera=(), geolocation=(), microphone=()" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; media-src 'self' blob: https:; connect-src 'self' https: ws: wss:; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self';" always;
|
||||
|
||||
# 隐藏 Nginx 版本
|
||||
server_tokens off;
|
||||
@@ -79,11 +81,21 @@ server {
|
||||
index index.html;
|
||||
try_files $uri $uri/ =404;
|
||||
|
||||
# 静态资源缓存
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
|
||||
location /assets/ {
|
||||
root /usr/share/nginx/html;
|
||||
expires 1y;
|
||||
}
|
||||
|
||||
location /libs/ {
|
||||
root /usr/share/nginx/html;
|
||||
expires 30d;
|
||||
}
|
||||
|
||||
location /downloads/ {
|
||||
alias /runtime/downloads/;
|
||||
expires 1h;
|
||||
}
|
||||
|
||||
# ============================================
|
||||
@@ -98,6 +110,7 @@ server {
|
||||
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_set_header X-Request-ID $request_id;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
|
||||
# Cookie 传递配置(验证码 session 需要)
|
||||
@@ -125,5 +138,6 @@ server {
|
||||
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_set_header X-Request-ID $request_id;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user