Laravel 项目容器化部署生产环境后,资源链接多出个 80 端口字样解决方案

前言

最近在阿里云服务器上部署一个基于 Laravel 12 + Filament v4 的项目(代号“土豆食堂”),使用 Docker Compose 容器化部署,后端 Nginx + PHP-FPM,前端通过 Nginx Proxy Manager (NPM) 实现 HTTPS 反向代理。部署完成后,一切看似正常,但访问应用时发现前端资源(如 Filament 的 app.js)的 URL 被错误生成成 https://lynx.wkarrow.top:80/js/filament/filament/app.js?v=4.1.6.0,多出的 :80 端口导致浏览器无法加载资源,报 404 错误。

这不是代码 bug,而是典型的 HTTPS 代理到 HTTP 后端的头部传递问题。NPM 默认将 X-Forwarded-Port 设置为后端端口 80,而 Laravel 在生成资产 URL 时会根据此头部附加端口,导致与 HTTPS scheme 不匹配。

本文记录了问题排查与最终解决方案,重点分享后端 Nginx 的备选修复方法(适用于 NPM 配置无效的情况)。希望对类似部署遇到坑的开发者有帮助!

问题复现与分析

环境概述

  • 项目:Laravel 12 + Filament v4,使用 Vite 构建前端资源。
  • 部署:Docker Compose(docker-compose.internet.yml),包含 app (PHP-FPM)、nginx、mysql、redis 等服务。
  • 代理:NPM 监听 443 端口,强制 HTTPS,转发到后端 Nginx 的 80 端口。
  • Nginx 配置default.conf 中已传递 X-Forwarded-* 头部到 PHP-FPM。

故障现象

  • 正常预期:https://lynx.wkarrow.top/js/filament/filament/app.js?v=4.1.6.0
  • 实际生成:https://lynx.wkarrow.top:80/js/filament/filament/app.js?v=4.1.6.0
  • 影响:浏览器 Network 面板显示资源 404,应用界面 JS/CSS 加载失败,Filament 面板无法交互。

根因分析

  1. NPM 作为前端代理,添加 X-Forwarded-Proto: httpsX-Forwarded-Port: 80(后端端口)。
  2. 后端 Nginx 将这些头部传递给 PHP-FPM(fastcgi_param HTTP_X_FORWARDED_PORT $http_x_forwarded_port;)。
  3. Laravel 的 Request 对象信任代理头部(config/trustedproxies.php),读取 X-Forwarded-Port=80
  4. URL 生成器(如 asset() 或 Filament 的资源 URL)检测到端口非 HTTPS 默认 443,故附加 :80
  5. 参考 Laravel 12 文档(HTTP Requests 部分):request()->getPort() 优先从 X-Forwarded-Port 取值,导致畸形 URL。

这是一个常见痛点,尤其在 Docker + 反向代理环境中。

解决方案

我先尝试了在 NPM 的 Advanced 选项卡添加 proxy_set_header X-Forwarded-Port 443;,但由于 NPM 的自定义配置有时不稳定(可能与版本或缓存相关),最终选择了后端 Nginx 的备选修复——直接在 default.conf 中覆盖端口逻辑。这方法更可靠,且不依赖代理工具。

步骤:修改后端 Nginx 配置

  1. 编辑配置文件:在项目目录下,打开 ./docker-internet/nginx/default.conf(或挂载路径 /etc/nginx/conf.d/default.conf)。

  2. 定位 PHP 处理块:找到 location ~ \.php$ 部分(已存在 FastCGI 配置)。

  3. 添加覆盖逻辑:在 fastcgi_param 相关行后,插入以下 Nginx 指令:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    location ~ \.php$ {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass app:9000;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;

    # 原有头部传递
    fastcgi_param HTTP_X_FORWARDED_FOR $http_x_forwarded_for;
    fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto;
    fastcgi_param HTTP_X_FORWARDED_HOST $http_x_forwarded_host;
    fastcgi_param HTTP_X_FORWARDED_PORT $http_x_forwarded_port;

    # 新增:基于 proto 覆盖端口,确保 HTTPS 时为 443
    set $real_port $http_x_forwarded_port;
    if ($http_x_forwarded_proto = "https") {
    set $real_port "443";
    }
    fastcgi_param HTTP_X_FORWARDED_PORT $real_port;
    }
    • 解释
      • set $real_port $http_x_forwarded_port;:默认使用传入端口。
      • if ($http_x_forwarded_proto = "https") { set $real_port "443"; }:如果 scheme 是 HTTPS,则强制覆盖为 443(忽略后端 80)。
      • 最后用 $real_port 替换原参数,确保 Laravel 读取正确端口。
  4. 保存并重启服务

    1
    sudo docker compose -f docker-compose.internet.yml restart nginx
    • Nginx 会优雅重载,无需重建整个容器。
  5. 辅助优化(可选,但推荐):

    • 确认 .env 中的 APP_URL=https://lynx.wkarrow.top(无端口)。
    • 清除 Laravel 缓存:
      1
      2
      3
      sudo docker compose -f docker-compose.internet.yml exec app php artisan config:clear
      sudo docker compose -f docker-compose.internet.yml exec app php artisan cache:clear
      sudo docker compose -f docker-compose.internet.yml exec app php artisan optimize

验证与测试

  • 浏览器测试:清空缓存,访问 https://lynx.wkarrow.top,打开 F12 > Network,检查资源 URL(如 app.js)是否无 :80,并确认 200 OK。
  • 命令行验证
    1
    curl -I https://lynx.wkarrow.top/js/filament/filament/app.js
    预期返回 200,无重定向或 404。
  • 日志检查:若仍有问题,查看容器日志:
    1
    sudo docker compose -f docker-compose.internet.yml logs nginx app | grep -i "forwarded\|port"

修复后,Filament 面板加载顺畅,前端交互完美!

总结与建议

这个坑让我意识到,在容器化部署中,代理头部的处理至关重要。优先尝试 NPM 的 Advanced 配置,如果无效,后端 Nginx 的 if 逻辑是稳妥备选。未来更新项目时,记得 git pull 后检查此配置是否覆盖。

如果您也遇到类似问题,欢迎评论区交流!项目源码在 GitHub 开源中,星标支持下~

参考

  • Laravel 12 文档:HTTP Requests
  • Nginx Proxy Manager 官方指南:Advanced Tab

本文基于实际部署经验撰写,如有疑问,欢迎讨论。