name: nginx serve /uploads direct (audio speed) # 让 nginx 直接吐 /uploads(音频),绕过 Node → 首播更快、sendfile 高效、长效不可变缓存。 # 只影响公开的【试听】音频(满血走 Node 的签名/令牌口,不在 /uploads)。 # ★安全:保留首次原始备份;精确定位 443 server 块插入;幂等(先删旧再插);nginx -t + 自检失败一律还原,绝不弄坏线上。 on: push: paths: ['.github/workflows/nginx-uploads-direct.yml'] workflow_dispatch: {} jobs: patch-nginx: runs-on: ubuntu-latest steps: - name: Add location /uploads to API nginx (robust+guarded) uses: appleboy/ssh-action@v1 with: host: ${{ secrets.ECS_HOST }} username: ${{ secrets.ECS_USER }} password: ${{ secrets.ECS_PASSWORD }} command_timeout: 5m script: | set -e CONF=$(grep -rl "digitalme-api.invoratec.cn" /etc/nginx 2>/dev/null | head -1) echo "conf=$CONF"; [ -n "$CONF" ] || { echo "❌ 找不到 API nginx conf"; exit 1; } UP=/var/www/digitalme-api.invoratec.cn/data/uploads [ -d "$UP" ] || { echo "❌ 上传目录不存在: $UP"; exit 1; } BAK="$CONF.orig-bak"; [ -f "$BAK" ] || cp "$CONF" "$BAK" # 只保留【首次】原始备份 SAFE="$CONF.pre-uploads.$(date +%s)"; cp "$CONF" "$SAFE" # 本次回滚点 python3 - "$CONF" "$UP" <<'PY' import sys, re conf, up = sys.argv[1], sys.argv[2] s = open(conf, encoding='utf-8').read() # 1) 幂等:先删掉已有的 location /uploads/ {...}(本模块的块无嵌套花括号) s = re.sub(r'\n?\s*location\s+/uploads/\s*\{[^{}]*\}\n?', '\n', s) # 2) 精确定位含 listen ... 443 的 server 块:找到 443 的 listen,再回溯它所属的 server 的 '{' m = re.search(r'listen[^;]*443', s) if not m: print('NO_443'); sys.exit(2) srv = s.rfind('server', 0, m.start()) if srv < 0: print('NO_SERVER'); sys.exit(3) brace = s.find('{', srv) if brace < 0: print('NO_BRACE'); sys.exit(4) block = ('\n location /uploads/ {\n' ' alias %s/;\n' ' add_header Cache-Control "public, max-age=31536000, immutable";\n' ' access_log off;\n' ' try_files $uri =404;\n' ' }\n') % up open(conf, 'w', encoding='utf-8').write(s[:brace+1] + block + s[brace+1:]) print('inserted into 443 server block at', brace) PY if ! nginx -t; then echo "❌ nginx -t 失败,还原本次"; cp "$SAFE" "$CONF"; nginx -t; exit 1; fi nginx -s reload; sleep 1 F=$(ls -1 "$UP"/songprev-* 2>/dev/null | head -1 | xargs -r basename) if [ -n "$F" ]; then H=$(curl -sI "https://digitalme-api.invoratec.cn/uploads/$F" 2>/dev/null) CODE=$(echo "$H" | head -1) echo "自检: $CODE"; echo "$H" | grep -iq "x-request-id" && echo "⚠ 仍是 Node 在吐(未直吐)" || echo "✓ 已由 nginx 直吐(无 x-request-id)" echo "$CODE" | grep -qE " 200| 206" || { echo "❌ 自检非2xx,还原"; cp "$SAFE" "$CONF"; nginx -s reload; exit 1; } fi echo "✓ done"