Home  >  Q&A  >  body text

Rewriting NGINX using proxy delivery directives does not work properly

I'm currently developing a legacy API running on an older Symfony version (2.8 being upgraded to 3.4).

The application has two "main" PHP entry points: app_dev.php and app.php. The _dev endpoint should only be used in a development environment, but is incorrectly used in older production applications.

We can easily modify the API to avoid exposing this file (and have done so successfully), however, we cannot easily update some applications that connect to the API. For example, some applications are still trying to connect using https://domain/app_dev.php/the/path.

As a temporary solution while we work on fixing applications that use the API, we would like to rewrite https://domain/app_dev.php/the/path to https:/ /domain/app.php/the/path or better yet https://domain/the/path. We believe rewriting is the right choice, but maybe we're not right?

We have the current configuration for NGINX:

## nginx.conf
user                    www-data;
worker_processes        auto;
worker_rlimit_nofile    65535;
error_log               /var/log/nginx/error.log warn;
pid                     /var/run/nginx.pid;

events {
    worker_connections          4096;
}

http {
    server_tokens           off;

    include                 /etc/nginx/mime.types;
    default_type            application/octet-stream;

    # log_format must come before access_log!
    log_format              main '$remote_addr - $remote_user [$time_local] "$request" $status '
                                 '$body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"';
    access_log              /var/log/nginx/access.log  main;

    sendfile                    on;
    keepalive_timeout           65;
    client_max_body_size        50M;
    proxy_buffer_size           128k;
    proxy_buffers               4 256k;
    proxy_busy_buffers_size     256k;
    large_client_header_buffers 4 16k;

    include /etc/nginx/conf.d/*.conf;
}
## php-prod.conf
upstream php {
    server 127.0.0.1:9000;
}

server {
    listen                      80;

    client_max_body_size        50M;
    client_body_buffer_size     128k;
    fastcgi_param               REMOTE_USER $remote_user;

    root                        /var/www/web;

    location = /favicon.ico {
        break;
    }

    location / {
        try_files               $uri /app.php$is_args$args;
    }

    # Configuration for PHP passthrough on remote / production endpoints
    location ~ ^/app\.php(/|$) {
        if ($request_method = OPTIONS ) {
            add_header Content-Length 0;
            add_header Content-Type text/plain;
            add_header Access-Control-Allow-Headers "x-custom-auth, content-type, x-requested-with, authorization, mobile";
            add_header Access-Control-Allow-Methods "POST, PUT, PATCH, GET, DELETE";
            add_header Access-Control-Allow-Origin "$http_origin";
            add_header Access-Control-Max-Age 1728000;
            return 204;
        }

        fastcgi_pass php;
        fastcgi_read_timeout 3600;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;

        # When you are using symlinks to link the document root to the current version of your application, you
        # should pass the real application path instead of the path to the symlink to PHP FPM. Otherwise, PHP's OPcache
        # may not properly detect changes to your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126
        # for more information).
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;

        # Prevents URIs that include the front controller. This will 404: http://domain.tld/app.php/some-path
        # Remove the internal directive to allow URIs like this
        internal;
    }

    # Return 404 for all other php files not matching the front controller.
    # This prevents access to other php files you don't want to be accessible.
    location ~ \.php$ {
        return 404;
    }

    error_log /var/log/nginx/error.log;
    access_log off;
}

I tried adding rewrite /app_dev\.php/(.*) /app.php$1 break; to various places including the main server block and location / block and can't seem to get the redirect to work. I've tried using break and last but I only get a 500 response from the API with no content.

If I update location ~ ^/app\.php(/|$) { to location ~ ^/(app|app_dev)\.php(/|$) { It works fine, so I know the API "works" behind NGINX.

I should mention that 301 redirects won't work here as I also need to rewrite the POST request. However, I've tested this as a 301 redirect and got the expected results (but the 301 doesn't work for our POST request):

location / {
        rewrite /app_dev\.php/(.*) / permanent;
        try_files               $uri /app.php$is_args$args;
    }

...

127.0.0.1 - testCommand [25/May/2023:09:04:31 +0000] "POST /app_dev.php/api/path HTTP/1.0" 301 162 "-" "PostmanRuntime/7.32.2"
172.20.0.1 - testCommand [25/May/2023:09:04:31 +0000] "POST /app_dev.php/api/path HTTP/1.1" 301 162 "-" "PostmanRuntime/7.32.2" "-"
172.20.0.1 - - [25/May/2023:09:04:31 +0000] "GET /api/path HTTP/1.1" 301 162 "https://api.domain.com/app_dev.php/api/path" "PostmanRuntime/7.32.2"

If I set it to interrupt:

172.20.0.1 - testCommand [25/May/2023:09:08:05 +0000] "POST /app_dev.php/api/path HTTP/1.1" 500 5 "-" "PostmanRuntime/7.32.2" "-"
127.0.0.1 - testCommand [25/May/2023:09:08:05 +0000] "POST /app_dev.php/api/path HTTP/1.0" 500 0 "-" "PostmanRuntime/7.32.2"

If I set it to last:

172.20.0.1 - testCommand [25/May/2023:09:13:57 +0000] "POST /app_dev.php/api/path HTTP/1.1" 500 5 "-" "PostmanRuntime/7.32.2" "-"
127.0.0.1 - testCommand [25/May/2023:09:13:57 +0000] "POST /app_dev.php/api/path HTTP/1.0" 500 0 "-" "PostmanRuntime/7.32.2"

So my question is how do I get this rewrite to work, rewriting URLs like https://domain/app_dev.php/the/path to https://domain/app .php /the/path Even betterhttps://domain/the/path?

P粉063862561P粉063862561306 days ago367

reply all(1)I'll reply

  • P粉642920522

    P粉6429205222024-01-11 14:13:15

    You tried to rewrite /app_dev\.php/(.*) /app.php$1 break;, but break is a bad flag - you need to use <强> at last. See rewriteDirective.


    Alternatively, to redirect a POST request, you can use the 307 status response, for example:

    location ~ ^/app_dev\.php(/|$) {
        return 307 /app.php$is_args$args;
    }

    Make sure to place it above the location ~ \.php$ block.

    I noticed that the location ~ ^/app\.php(/|$) block is marked internal, which prevents your server from responding to external requests for >/app.php. This seems to contradict some of the statements in your question.

    reply
    0
  • Cancelreply