1

I have following location with rewrite:

location ~ ^/payment/gateway/v2/order/complete/(.*)$ {
    proxy_pass http://api.test.com:8080/payment/gateway/v2/order/complete?order_id=$1;
}

then I tried this:

 location /payment/gateway/v2/order/complete {
    rewrite ^/payment/gateway/v2/order/complete/(.+) /payment/gateway/v2/order/complete?order_id=$1 break;
    proxy_pass http://api.test.com:8080
}

then this:

 location /payment/gateway/v2/order/complete/ {
    rewrite ^/payment/gateway/v2/order/complete/$ /payment/gateway/v2/order/complete?order_id=$1 last;
    proxy_pass http://api.test.com:8080
}

then this:

location /payment/gateway/v2/order/complete {
    rewrite ^/payment/gateway/v2/order/complete/([^/]+)$ /payment/gateway/v2/order/complete?order_id=$1 last;
    proxy_pass http://api.test.com:8080;
}

all of them not works.

EDIT: this is full nginx config:

server {
    listen  443 ssl;
    server_name api.test.com www.api.test.com;

    ssl_certificate /home/ssl/api.test.com/cert.pem;
    ssl_certificate_key /home/ssl/api.test.com/key.pem;
    ssl_protocols SSLv3 TLSv1.2;
    ssl_ciphers  "RC4:HIGH:!aNULL:!MD5:!kEDH";
    add_header Strict-Transport-Security 'max-age=604800';

    access_log /var/log/nginx/api.test.access.log;
    error_log /var/log/nginx/api.test.error.log;

    root  /home/test;

    include /etc/nginx/conf/wellknown.conf;

    location /payment/paypal {
        proxy_pass http://api.test.com:8080;
    }

    location /payment/visa {
        proxy_pass http://api.test.com:8080;
    }

    location /payment/gateway {
        proxy_pass http://api.test.com:8080;
    }
    
    location /payment/gateway/order/complete {
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        proxy_pass http://api.test.com:8080;
    }

    location /payment/gateway/v2/order/complete {
        rewrite ^/payment/gateway/v2/order/complete/(.+) /payment/gateway/v2/order/complete?order_id=$1 break;
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_pass http://api.test.com:8080;
    }

    location /payment/mastercard/order {
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        proxy_pass http://api.test.com:8080;
    }

    location /payment/mir/order {
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        proxy_pass http://api.test.com:8080;
    }

    location /payment/v1 {
        proxy_pass http://api.test.com:8080;
    }
    
    location /catalog {
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
        proxy_pass http://localhost:9202;   
     }

    location / {
         if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Locale';
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'text/plain charset=UTF-8';
            add_header 'Content-Length' 0;
            return 204;
         }
         if ($request_method = 'POST') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
            add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
         }
         if ($request_method = 'GET') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
            add_header 'Access-Control-Expose-Headers' 'Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
         }
    }

    location /test-rpc {
        proxy_pass http://api.test.com:8080;
    }
}

EDIT2: here wellknown.conf config file body:

location ^~ /.well-known/ {
    default_type "text/plain";
    allow all;
}

EDIT3 I optimized the locations, but it doesn't affect the final result:

server {
    listen  443 ssl;
    server_name api.test.com www.api.test.com;

    ssl_certificate /home/ssl/api.test.com/cert.pem;
    ssl_certificate_key /home/ssl/api.test.com/key.pem;
    ssl_protocols SSLv3 TLSv1.2;
    ssl_ciphers  "RC4:HIGH:!aNULL:!MD5:!kEDH";
    add_header Strict-Transport-Security 'max-age=604800';

    access_log /var/log/nginx/api.test.access.log;
    error_log /var/log/nginx/api.test.error.log;

    root  /home/test;

    include /etc/nginx/conf/wellknown.conf;
    
    location /payment/gateway/v2/order/complete {
        rewrite ^/payment/gateway/v2/order/complete/(.+) /payment/gateway/v2/order/complete?order_id=$1 break;
        proxy_pass http://api.test.com:8085;
    }  

    location /payment {
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_pass http://api.test.com:8085;
    }

    location /catalog {
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_pass http://localhost:9202;
    }

    location / {
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Locale';
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'text/plain charset=UTF-8';
            add_header 'Content-Length' 0;

            return 204;
        }

        if ($request_method = 'POST') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
            add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
        }

        if ($request_method = 'GET') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
            add_header 'Access-Control-Expose-Headers' 'Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
        }
    }

    location /test-rpc {
        proxy_pass http://api.test.com:8080;
    }
}

Nginx version 1.13.8

Thanks in advance

SBotirov
  • 25
  • 1
  • 8
  • At least first two of them looks ok, what you do receive on your backend instead of right URI/query string? – Ivan Shatsky Nov 05 '20 at 04:24
  • not changed request url i receives: http://api.test.com:8080/payment/gateway/v2/order/complete/23223 – SBotirov Nov 05 '20 at 15:21
  • Do you have any other locations with the `proxy_pass http://api.test.com:8080;`? Can't it be that some other location is taking priority over this one? – Ivan Shatsky Nov 05 '20 at 17:16
  • I edited my answer, there have full nginx config, there are all paths different – SBotirov Nov 06 '20 at 10:09
  • I don't see any errors, the `location /payment/gateway/v2/order/complete` is really a longest prefix location and should capture those requests. Ok, I'd try to test this config on the weekend (need a couple of free time for this) and will tell you what I've got. – Ivan Shatsky Nov 06 '20 at 11:44
  • It's kind of you Ivan, thanks in advance! I'm also trying with docker on this version of nginx. Because, this locations works fine with nginx/1.16.1 version, but not with nginx version: nginx/1.13.8. I really want to find out why this is so. – SBotirov Nov 06 '20 at 12:51
  • May I ask what make you stick with 1.13.8 if this config works properly with 1.16? Why do not update to something more recent? Is it some openresty fork or something similar? – Ivan Shatsky Nov 06 '20 at 12:59
  • There are two big projects running on the production, updating nginx expensive to me now – SBotirov Nov 06 '20 at 15:20
  • First, second and fourth location variants works correctly with nginx 1.13.6 (most close version to 1.13.8 I have access to right now). Can you add `/etc/nginx/conf/wellknown.conf` file contents to your question, maybe it caused some problems? – Ivan Shatsky Nov 07 '20 at 05:47
  • Hi Ivan, I added body of wellknown config file, but there is clearly have path segment "well-known". – SBotirov Nov 07 '20 at 07:19

2 Answers2

1

What about this?

location /payment/gateway/v2/order/complete {
    rewrite ^/payment/gateway/v2/order/complete/([^/]+)/? /payment/gateway/v2/order/complete/?order_id=$1? break;
    proxy_pass http://api.test.com:8080;
}

Note that I have removed the end string char $ and that I have added an optional trailing slash /?. I have also changed the redirect flag last with break to prevent redirection loops. Finally, the trailing ? in the destination URL prevents nginx from adding the previous request arguments if there were any. That regular expression matchs strings like these:

/payment/gateway/v2/order/complete/123123
/payment/gateway/v2/order/complete/123123/
/payment/gateway/v2/order/complete/123123/whatever
/payment/gateway/v2/order/complete/123123/whatever?var=a

In all those cases, $1 would be 123123 and the redirect destination is /payment/gateway/v2/order/complete/?order_id=123123

You can test the redirection with curl:

curl -I https://yoursite/payment/gateway/v2/order/complete/123123/whatever/you/want/?var1=1&var2=b

You should get a response with Location: https://yoursite/payment/gateway/v2/order/complete/?order_id=123123

Documentation: http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite

Jesús Ángel
  • 518
  • 2
  • 6
1

This should be possible to do without using the rewrite command.

location ~* /payment/gateway/v2/order/complete/(.+)$ {
    proxy_pass http://api.test.com:8085/payment/gateway/v2/order/complete?order_id=$1;
} 

In this example we use the case insensitive regex (~*) to capture everything after complete in the URL, then inside the location we rebuild the request using the $1.

To test the setup, I added a configuration to my nginx:

server {
    listen  80;
    server_name localhost;

    location ~* /payment/gateway/v2/order/complete/(.+)$ {
        proxy_pass http://localhost:8085/payment/gateway/v2/order/complete?order_id=$1;
    }

    location / {
        return 404;
    }
}


server {
    listen 8085;
    server_name localhost;
    location ~ /payment/gateway/v2/order/complete(.*) {
        return 202;
    }
}

This is configured so that a successful hit will be proxied to the other server and return a 202, and any unsuccessful hit will result in a 40x response.

This can be tested from the 'client side' using curl, like this:

$ curl -v http://localhost:80/payment/gateway/v2/order/complete/1234 -L 
*   Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /payment/gateway/v2/order/complete/1234 HTTP/1.1
> Host: localhost
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 202 Accepted
< Server: nginx/1.18.0 (Ubuntu)
< Date: Thu, 12 Nov 2020 02:02:12 GMT
< Content-Type: application/octet-stream
< Content-Length: 0
< Connection: keep-alive
< 
* Connection #0 to host localhost left intact

And seeing the logs, we observe two entries:

  1. The connection from the 'client' to the 'frontend' with the original path:
127.0.0.1 - - [12/Nov/2020:02:02:12 +0000] "GET /payment/gateway/v2/order/complete/1234 HTTP/1.1" 202 0 "-" "curl/7.68.0"
  1. The connection from the 'frontend' to the 'backend' which includes the modified path:
127.0.0.1 - - [12/Nov/2020:02:02:12 +0000] "GET /payment/gateway/v2/order/complete?order_id=1234 HTTP/1.0" 202 0 "-" "curl/7.68.0"

This could also be cleaned up a bit to only match requests that contain a valid ID using a more complex regex. Nginx supports full PCRE for match/set expressions.

Source: https://nginx.org/en/docs/http/ngx_http_core_module.html#location

nbailey
  • 171
  • 6