【问题标题】:Proper handling of request_uri in double nginx reverse proxy?在双 nginx 反向代理中正确处理 request_uri?
【发布时间】:2017-12-03 21:34:27
【问题描述】:

所以,基本上我在 Docker php7-fpm 容器中运行 Joomla,然后我有一个 nginx 容器,其中 joomla.conf 文件定义如下:

#https://docs.joomla.org/nginx

server {
  listen 8081;

  error_log  /var/log/nginx/error.log;
  access_log /var/log/nginx/access.log;

  server_name php-docker.local;

  root /usr/src/joomla;
  index index.php index.html index.htm default.html default.htm;

  location / {
    try_files $uri $uri/ /index.php?$args;
  }

  # deny running scripts inside writable directories
  location ~* /(images|cache|media|logs|tmp)/.*\.(php|pl|py|jsp|asp|sh|cgi)$ {
    return 403;
    error_page 403 /403_error.html;
  }

  location ~ \.php$ {
    fastcgi_pass  joomla:9000;
    fastcgi_index index.php;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;

    include fastcgi_params;
    #include /etc/nginx/fastcgi.conf;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
  }
}

这按预期工作...转到 http://:8081 会正确加载所有内容。

现在,8081 只是暂时暴露在 nginx 容器中,我真正想做的是设置一个反向代理,这样 http:///joomla 将成为最终端点。

为此,我正在努力使用以下 conf 文件:

server{

  listen 80;
  server_name _;

  location /joomla/ {
    proxy_pass          http://localhost:8081/;

    proxy_set_header    Referer           $http_referer;
    proxy_set_header    X-Forwarded-Port  $server_port;
    proxy_set_header    X-Forwarded-Proto $http_x_forwarded_proto;
    proxy_set_header    Host              $host;
    proxy_set_header    X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header    X-Forwarded-Host  $host;
  }

}

发生的情况是 HTML 被正确提供,但是,没有任何资产。这是因为 Joomla 中的 URL 是由 JURI 类生成的,该类似乎依赖于 $request_uri,当它似乎到达 Joomla 时,它已经丢失了。

https://github.com/joomla/joomla-cms/blob/6ab2a6e9010e7e04c260b9eba17dc76e866dd3e6/libraries/joomla/uri/uri.php#L87

因此,对文件、脚本或 css 的每个链接或引用都呈现如下:

http://localhost/login

http://localhost/images/headers/maple.jpg

代替:

http://localhost/joomla/login

http://localhost/joomla/images/headers/maple.jpg

但是,当我访问第二组 URL 时,我可以毫无问题地访问链接/资产……当然,再一次,没有正确呈现图像、模板、js 或链接。

除非出现问题,否则我不喜欢碰 joomla.conf,至于 site.conf,我只想翻译 URI 段以将请求映射到其他应用程序,例如:

/joomla -> localhost:8081
/phpbb -> localhost:8082
/someapp -> localhost:8083

【问题讨论】:

  • 您是否尝试过从浏览器访问这个? :http:///joomla/(以 / 结尾)。
  • 您的 nginx 配置不会影响 Joomla 生成链接的方式。如果您面向 nginx 的客户端仅将 /joomla/ 转发到上游 Joomla nginx,那么它将永远不会通过 /images/headers/maple.jpg/login。如果您将始终在面向 nginx 的客户端上通过 /joomla/ 访问 Joomla,那么您唯一的选择是更改 Joomla 配置。
  • 您尝试过更改 joomla 配置文件中的 $live_site 参数吗?
  • OP,您会这么好心地查看答案并奖励赏金吗?如果您不执行任何操作,至少有一半的赏金将被浪费。谢谢。附言如果您决定采用推荐人路线,并且对 nginx.conf 有任何问题,请告诉我。

标签: php nginx docker joomla reverse-proxy


【解决方案1】:

我知道这很旧,但这是我的答案。您不应该更改configuration.php 文件,主要是因为您应该让您的服务(Web 和代理)完全分离(服务实现产生的问题应该在该服务中解决),这将使您的服务架构更加灵活。 您必须过滤资产 url 和一些 Location 标头更改以下代理设置。

server {
    #... other settings

    location /joomla/ {
        # Main redirect
        proxy_pass http://joomla_service/;

        # Set the Host Header
        proxy_set_header Host $host;

        # When Joomla redirects a Location Header
        # For example when you log in, Joomla retrieves you a response with a Location Header = localhost
        # we don't want this.
        proxy_redirect http://localhost/ http://localhost/joomla/;
        proxy_redirect / /joomla/;

        # Some content rewriting
        sub_filter_types text/javascript application/javascript;

        # Html redirection
        sub_filter '="/' '="/joomla/';
        sub_filter '="http://localhost/' '="/joomla/';
        sub_filter '\'http://localhost/administrator/' '\'/joomla/administrator/';
        sub_filter 'url(\'/media' 'url(\'/joomla/media';

        # Some json data
        sub_filter '"root":""' '"root":"\/joomla"';
        sub_filter '"uri":"\/index.php' '"uri":"\/joomla\/index.php';
        sub_filter '"jdragdrop":"\/media' '"jdragdrop":"\/joomla\/media';
        sub_filter '"plg_quickicon_privacycheck_url":"http:\/\/localhost' '"plg_quickicon_privacycheck_url":"\/joomla';
        sub_filter '"plg_quickicon_privacycheck_ajax_url":"http:\/\/localhost' '"plg_quickicon_privacycheck_ajax_url":"\/joomla';
        sub_filter '"content_css":"\/templates' '"content_css":"\/joomla\/templates';

        sub_filter_once off;
    }
}

由于某种原因,如果我们谈论实现反向代理,Joomla 并没有提供很好的支持。我创建了一个更详细的示例,你可以看到它here

【讨论】:

  • 由于您是 Joomla 开发人员并且可以提供 Joomla 支持,请加入 Joomla Stack Exchange 看看您是否也可以支持这个专门的社区。干杯。
【解决方案2】:

最简洁的解决方案是修改上游,为所有资源提供唯一路径。

从上游删除部分 URL(具有唯一前缀)通常比向非唯一部分添加额外部分要容易得多。这是因为您始终可以捕获较长的 URL 并准确了解它所指的内容,然后将 301 或 302 重定向返回到更短、更简洁的版本。

另一方面,面对一个简短的请求 URL,例如 /,很难确定它可能引用哪个应用程序(除非您也查看 $http_referer 变量,然后有条件地查看根据 URL 请求的来源发出重定向),或者除非您实施某种意大利面条式规则来检测哪些单个 URL 引用了哪些应用程序(如果您走这条路线,the map directive 可能会派上用场)。

此外,考虑到安全方面,当涉及到 cookie 时,在单个域上运行多个独立应用程序并不是最佳实践——一个应用程序的妥协很容易导致所有其他应用程序的安全违规。

【讨论】:

  • 你能举个例子吗?另一方面,您的意思是按子域分隔应用程序是最佳做法吗?
  • 是的,最好的办法是按子域分隔。如果你确实想走引荐路线,你可以在适用的位置有一些if 语句(例如,在/ 位置有if ($http_referer ~ ^/joomla)(不在/joomla 位置,例如不创建循环)),这将是return 302 /joomla/$request_uri;。如果您需要任何进一步的帮助,请告诉我(查看 access_log/error_log 以及适用的文件系统布局和 nginx.conf 也会有所帮助)。
【解决方案3】:

您可以尝试使用this answer 中提到的 sub_filter。

所以在您的情况下,您的 nginx 配置应该如下所示:

server{

  listen 80;
  server_name _;

  location /joomla/ {
    proxy_pass          http://localhost:8081/;

    proxy_set_header    Referer           $http_referer;
    proxy_set_header    X-Forwarded-Port  $server_port;
    proxy_set_header    X-Forwarded-Proto $http_x_forwarded_proto;
    proxy_set_header    Host              $host;
    proxy_set_header    X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header    X-Forwarded-Host  $host;
    sub_filter "http://your_server/" "http://your_server/joomla/";
    sub_filter_once off;
  }

}

【讨论】:

  • 这没有任何效果
【解决方案4】:

正如Rinos 所说,您需要在configuration.php 中配置$live_site var,如下所示:

public $live_site = '/joomla/';

我创建了一个complete example in Github,在编辑该文件后运行良好,它使用您的配置。



 变成:


【讨论】:

猜你喜欢
  • 1970-01-01
  • 2019-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-05
  • 1970-01-01
  • 1970-01-01
  • 2018-08-06
相关资源
最近更新 更多