Proper handling of request_uri in double nginx reverse proxy?

Viewed 2331

So, essentially I am running Joomla in a Docker php7-fpm container, then I have an nginx container where a joomla.conf file is defined as follows:

#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;
  }
}

And this works as expected... going to http://:8081 loads everything correctly.

Now, 8081 is just temporarily exposed in the nginx container, what I essentially want to do is setup a reverse proxy such that http:///joomla will be the final endpoint.

For this, I am struggling with the following conf file:

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;
  }

}

What happens is that the HTML is served correctly, however, none of the assets are. This is because the URLs in Joomla are generated by a JURI class, which seems to rely on $request_uri, which by when it appears to arrive to Joomla is already lost.

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

So every link or reference to a file, script, or css renders like this:

http://localhost/login

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

Instead of:

http://localhost/joomla/login

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

However, when I access the second set of URL, I can access the link/asset without a problem... but of course once again, no images, templates, js or links being rendered correctly.

I prefer not to touch joomla.conf unless something is wrong, as for site.conf I would only like to translate URI segments to map requests to other applications, e.g.:

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

I know this is old but here's my answer. You shouldn't change the configuration.php file, basically because you should keep your services (web and proxy) completely separated (A problem generated by a service implementation should be solved in that service), that will make your service architecture more flexible. You have to filter the assets urls and some Location headers changing the following proxy settings.

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;
    }
}

For some reason Joomla is not doing a good support if we talk about implement a reverse proxy. I created an example with more details, you can see it here.

Related