How to change request path in nginx for PHP/Laravel?

Viewed 322

I'm trying to convert my legacy php files into a single entrypoint. For now, a few endpoints will require to be operational (10 or so), such as /legacy_endpoint.php. I would like to rewrite these into a different action (post/get etc) on the server.

So far I can rewrite the end point and skip trying to run it as a php file (as the file does not exist):


    # rewrite to skip trying to run as PHP file
    # use last to search for a new location, which will hit the rule below
    location ~ ^/legacy_endpoint.php {
       rewrite /(.*) /legacy/endpoint last;
    }

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

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;


        fastcgi_intercept_errors off;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
        fastcgi_connect_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_read_timeout 300;
    }

This runs and serves the index.php file. In the script (Laravel) however I still see the "route", by running dd($request) seen as

  requestUri: "/legacy_endpoint.php"

Can I somehow rewrite this into e.g /legacy/endpoint or similar directly in nginx? I'm guessing I'd have to change the request itself?

1 Answers

index.php very likely gets the route from the parameter REQUEST_URI which is set inside the fastcgi_params file using fastcgi_param REQUEST_URI $request_uri;. This is why the rewrite...last will not work, as $request_uri is never changed.

Assuming that you have more than one legacy URI, and that they do not exist as local files, you may want to use a map block to override the value of REQUEST_URI for specific endpoints. See this document for details.

For example:

map $request_uri $endpoint {
  default               $request_uri;
  /legacy_endpoint.php  /legacy/endpoint;
}
server {
  ...
  location ~ \.php$ {
    try_files $uri /index.php =404;

    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $request_filename;
    fastcgi_param REQUEST_URI     $endpoint;

    fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
  }
  ...
}

The map block must go outside of the server block. The try_files statement is added to force URIs ending with .php to also find index.php. The fastcgi_param statements must go after the include statement in order to override the value set within the included file.

If the URI /legacy_endpoint.php may contain an optional query string, you will need to use a regular expression to match the start of the URI instead, for example:

map $request_uri $endpoint {
  default                  $request_uri;
  ~^/legacy_endpoint\.php  /legacy/endpoint$is_args$args;
}
Related