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

  • At least first two of them looks ok, what you do receive on your backend instead of right URI/query string? – Ivan Shatsky Nov 5 '20 at 4:24
  • not changed request url i receives: api.test.com:8080/payment/gateway/v2/order/complete/23223 – mr.boyfox Nov 5 '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 5 '20 at 17:16
  • I edited my answer, there have full nginx config, there are all paths different – mr.boyfox Nov 6 '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 6 '20 at 11:44
1
+100

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

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.