TransWikia.com

Some problems with nginx rewrites - forwarding request from folder to subdomain , then processing it further

Super User Asked on November 29, 2021

I am trying to do the following, and maybe I’m just stuck on a stupid syntax error.

old site had a sub-site called database, so we had:
www.example.com (getting entirely replaced )

www.example.com/database/ < lots of stuff >

new database site:

database.example.com/ < other stuff than before >

in the nginx.conf for example.com:

location ^~/database {
        rewrite ^/database/?(.*)$ https://database.example.com/$1 permanent;
        }

This part is working.

cURL: curl -L -v www.example.com/database/thisisatest

* Connected to www.example.com (<>) port 80 (#0)
> GET /database/thisisatest HTTP/1.1
[...]
< HTTP/1.1 301 Moved Permanently
[...]
< Location: https://database.example.com/thisisatest
<
* Ignoring the response-body
* Connection #0 to host www.example.com left intact
* Issue another request to this URL: 'https://database.example.com/thisisatest'

So far, so good. Now the part that I can not get to work:

full original request:

only difference:
valid input for id= is a 6 digit number
input= would be textinput

target:

  • virtual: database.example.com/search/XXXX
  • real: database.example.com/index.php?db=search&name=XXXX

first request id= can only be a 6 digit number for a valid request.
input= can be pretty much any text (german/english/spanish/french/polish/chinese and 0-9 )

in database.example.com config:

from within location /

rewrite ^/search.php?input=(.+)/?$ index.php?db=search&name=$1 last;
rewrite ^/view.php?id=([0-9]+)$  index.php?db=search&name=$1 last;
rewrite ^/search/(.+)/?$ index.php?db=search&name=$1 last;

So, this doesnt work ..yet. Somewhere my logic is off.

full nginx.conf of database.example.com:

server {
    listen 80;
    listen [::]:80;
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name database.example.com;

    ssl_certificate /etc/acme.sh/database.example.com/fullchain.pem;
    ssl_certificate_key /etc/acme.sh/database.example.com/privkey.pem;
    add_header Strict-Transport-Security max-age=15768000;



    root /var/webs/database.example.com/htdocs;
    
    access_log /var/webs/database.example.com/logs/access.log main;
    error_log /var/webs/database.example.com/logs/error.log warn;
    
    # Add index.php to the list if you are using PHP
    index index.php index.html index.htm;

    # serve static files directly
    location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico|html|xml|txt)$ {
        access_log        off;
        expires           365d;
    }

    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
     try_files $uri $uri/ =404;
     
########################################
##### THIS PART HERE DOES NOT WORK #####
########################################
     rewrite ^/search.php?input=(.+)/?$ index.php?db=search&name=$1 last;
     rewrite ^/view.php?id=([0-9]+)$  index.php?db=search&name=$1 last;
     rewrite ^/search/(.+)/?$ index.php?db=search&name=$1 last;
########################################
########################################     

     }

    
    # pass PHP scripts to FastCGI server
    #
    location ~ .php$ {
        include snippets/fastcgi-php.conf;
        include fastcgi_params;

        # With php-fpm (or other unix sockets):
         fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
       
    }

    location ~ /.ht {
        deny all;
    }

     location ~ /.git {
        deny all;
    }
}

Obviously, neither view.php nor search.php exist as real files (anymore) – it’s just the request to them that I need modified.

So, where is my logic off? :/ Any help is appreciated.

One Answer

The location ~ .php$ block handles any URI that ends with .php, so the first two rewrite statements are never triggered, because they are in the wrong location block.

All Nginx URIs begin with a leading /, so the rewritten URI should be /index.php for correct operation.

The rewrite and location statements are matched against a normalised URI which does not include the query string (anything from the ? onwards). The query string parameters are available as variables with names beginning with $arg_.

One possible solution is to place the three rewrite statements into separate location blocks, using the = and ^~ operators. See this document for details.

For example:

location / {
    try_files $uri $uri/ =404;
}

location = /search.php { 
    rewrite ^ /index.php?db=search&name=$arg_input? last;
}

location = /view.php { 
    rewrite ^ /index.php?db=search&name=$arg_id? last;
}

location ^~ /search/ {
    rewrite ^/search/(.+)/?$ /index.php?db=search&name=$1? last;
}

location ~ .php$ { ... }

Note that the rewritten URI has a trailing ? to prevent the original query string being appended. See this document for details.


Another solution uses your original regular expressions, but need to be performed against the $request_uri variable, which contains the full original request.

For example:

map $request_uri $rewrite {
    default 0;
    ~^/search.php?input=(?<name>.+)/?$ /index.php?db=search&name=$name;
    ~^/view.php?id=(?<name>[0-9]+)$    /index.php?db=search&name=$name;
    ~^/search/(?<name>.+)/?$             /index.php?db=search&name=$name;
}

server {
    ...
    if ($rewrite) {
        rewrite ^ $rewrite? last;
    }
    ...
}

See this document for details.

Answered by Richard Smith on November 29, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP