Score:0

Redirect all URLs to other (external) site except for one path?

ph flag

I have a working website (http://www.example.com) that (uses PHP-FPM) for which I want to redirect all incoming trafic to an URL on another website (ttps://www.other-example.com/foo.html) except one specific path (/api).

Here is the Nginx configuration I tried (put the PHP handling stuff in a dedicated location for /api and a return 301 on location /):

upstream php {
    server unix:/var/run/php/php7.4-fpm.sock;
}

server {
    listen 80;
    listen [::]:80;

    server_name www.example.com;

    root /var/www/www.example.com;
    index index.php;

    location  ~ ^/api(?:/(.*))?$ {
        #return 418;
        try_files $uri $uri/ /index.php$is_args$args;
    
        location ~ \.php$ {
            #include snippets/fastcgi-php.conf;

            # regex to split $uri to $fastcgi_script_name and $fastcgi_path
            fastcgi_split_path_info ^(.+?\.php)(/.*)$;

            # Check that the PHP script exists before passing it
            try_files $fastcgi_script_name =404;

            # Bypass the fact that try_files resets $fastcgi_path_info
            # see: http://trac.nginx.org/nginx/ticket/321
            set $path_info $fastcgi_path_info;
            fastcgi_param PATH_INFO $path_info;

            fastcgi_index index.php;
            include fastcgi.conf;
            include fastcgi_params;

            fastcgi_pass php;
        }
    }

    location / {
        return 301 https://www.other-example.com/foo.html;
    }
}

But all my requests (http://www.example.com, http://www.example.com/foo and http://www.example.com/api) gets a HTTP/1.1 301 Moved Permanently with Location: https://www.other-example.com/foo.html.

I know the location ~ ^/api(?:/(.*))?$ works because if I uncomment the return 418; I get 418 responses for http://www.example.com/api requests but 301 for the other requests.

Richard Smith avatar
jp flag
Where is `index.php`. Your `try_files` sends requests to `/index.php` which is not handled by the `/api` location. Should it `/api/index.php`?
CDuv avatar
ph flag
I see what you mean, but the API is handled by the same PHP application that handles (handled in fact) the other pages, and it's entrypoint is the `index.php` located at `/var/www/www.example.com/index.php`.
Score:0
us flag

The nginx processing goes as follows in your case:

  1. Request to /api/test_endpoint matches the location ~ ^/api(?:/(.*))?$ block.
  2. In try_files, it matches the /index.php$is_args$args part. Since it is the last part, it triggers an internal redirect.
  3. nginx restarts the processing with uri /index.php. This matches location / block, which triggers the redirect.

One solution to address the issue is the following configuration:

location  ~ ^/api(?:/(.*))?$ {
    #return 418;
    try_files $uri $uri/ /index.php$is_args$args;
}

location / {
    return 301 https://www.other-example.com/foo.html;
}

location = /index.php {
    internal;
    #include snippets/fastcgi-php.conf;

    # regex to split $uri to $fastcgi_script_name and $fastcgi_path
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;

    # Check that the PHP script exists before passing it
    try_files $fastcgi_script_name =404;

    # Bypass the fact that try_files resets $fastcgi_path_info
    # see: http://trac.nginx.org/nginx/ticket/321
    set $path_info $fastcgi_path_info;
    fastcgi_param PATH_INFO $path_info;

    fastcgi_index index.php;
    include fastcgi.conf;
    include fastcgi_params;

    fastcgi_pass php;
}

With this configuration, nginx finds a match for index.php in step 3 of the request processing. The internal keyword prevents external requests to /index.php matching this block. External requests to /index.php will be served by location / block.

CDuv avatar
ph flag
Thanks, it works. I know understand with the `try_files` made things go wrong.
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.