3

Our PHP-based application (custom made, no framework) sometimes needs to use its base full URL (for instance to store URL in files send to clients). Based for instance on this question, our application guess this (this is based on comparing __FILE__ and various variables in $SERVER like SCRIPT_NAME and SERVER_NAME).

Now we need to setup a (nginx) reverse-proxy in front of our application. Suppose that we map https://example.com/some/dir/onproxy/ to http://backend/another/dir/onbackend/.

Is there a way to guess the public URL (https://example.com/some/dir/onproxy/) from the code on backend ?

AFAIU (from my readings and experiments), it's not possible (HTTP_HOST may give example.com but I have found nothing that indicates some/dir/onproxy) but maybe I'm missing something (some variables or a nginx configuration option).

Any idea ?

In case it's not possible, the only solution is to store https://example.com/some/dir/onproxy/ in the configuration, right ?

EDIT 1

As suggested by @Progman, I tried solutions on this question. I have tried both the accepted answer and the second most upvoted answer but both return (some variation of) the URL on the backend (http://backend/another/dir/onbackend/).

EDIT 2

I forgot to mention that I would like to avoid to rely on URL rewriting in the proxy.

Mathieu Dubois
  • 1,054
  • 3
  • 14
  • 22
  • Have you checked https://stackoverflow.com/questions/6768793/get-the-full-url-in-php? Please [edit] your question to include the results you get when you try the solutions in the linked question. – Progman Feb 09 '20 at 20:38
  • To Clarify. You are uploading a file via Nginx. Nginx changes the path in the URL and sends the request on the new path to PHP. You are seeking a solution so the PHP code can know what the original path was before it was changed by Nginx? – Steve E. Feb 09 '20 at 21:01
  • @SteveE. it's not (only) uploading, it's for every request but yes, I want the original path. For instance when client requests `https://example.com/some/dir/onproxy/subdir/feature.php` (which is translated to `http://backend/another/dir/onbackend/subdir/feature.php` by the prox), the script `feature.php` must know that the base URL is `https://example.com/some/dir/onproxy/`. – Mathieu Dubois Feb 10 '20 at 10:38
  • @Progman I will update the question ASAP. – Mathieu Dubois Feb 10 '20 at 10:40

1 Answers1

5

Since Nginx is changing the request before it reaches the PHP backend, the solution is to add the original request data in somehow to the proxied request.

A common used convention for this is to add the original data in as extra HTTP headers. See X_Forwarded_For as an example of this.

To add the original request path as a new header, add a proxy_set_header directive to Nginx.

location /some/dir/onproxy/ {
    rewrite ^/some/dir/onproxy/(.*)$  /another/dir/onbackend/$1 break;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Request-URI $request; #** This adds the original path as a header **
    proxy_set_header Host $http_host; # **Optional, will retain the original host name**
    proxy_pass http://backend;
}

Something similar to that in your configuration will proxy the original request to a PHP web server on the back end. It does assume the backend is a HTTP server and not PHP-FPM.

Within PHP the quickest way to get the value of a single HTTP header is via $_SERVER. The original request path will be in $_SERVER['HTTP_X_REQUEST_URI'].

This is just an example, you may need to test and debug your application to refine the solution. php_info(); is a useful debug tool for the PHP environment, however it would also be useful to malicious actors so remove from your code as soon as possible or take other measures to ensure it is not exposed.

Steve E.
  • 9,003
  • 6
  • 39
  • 57
  • Thanks @SteveE. ! I was expecting something like that. I have 2 questions before accepting the answer. First, is the `rewrite` rule needed ? Second, and pardon my ignorance, but what would be different with `PHP-FPM` ? – Mathieu Dubois Feb 11 '20 at 07:51
  • @Mathieu Dubios The rewrite rule changes the path of the request to whatever the backend needs it to be. I assumed you had that already, but if it's not required as part of the solution then leave it out.PHP-FPM runs PHP with it's own network listener instead of going via a HTTP server. However PHP-FPM is not HTTP compliant itself so you need a proxy like Nginx which understands that. – Steve E. Feb 12 '20 at 02:56
  • Thanks for clarifying that: our app uses mostly relative links and when we construct the full URL when we need it (hence the question :) so we hope to avoid URL rewriting. `backend` may use `PHP-FPM` but behind Apache so there should be no problem. – Mathieu Dubois Feb 12 '20 at 13:29
  • Shouldn't `proxy_pass http://backend;` be `proxy_pass http://backend/another/dir/onbackend/;` ? – Mathieu Dubois Feb 12 '20 at 13:31
  • @Mathieu Dubois, It's probably easier to [read the manual](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass). TLDR the path is optional with `proxy_pass` and the behavior changes if it is specified. Either way is valid depending upon the use case. – Steve E. Feb 13 '20 at 02:34
  • Yep sorry for the noob question. I relied on our IT for this part of the configuration and they used the path so I though it was needed. – Mathieu Dubois Feb 14 '20 at 09:17