Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

My proxy server runs on ip A and this is how people access my web service. The nginx configuration will redirect to a virtual machine on ip B.

For the proxy server on IP A, I have this in my sites-available

server {
        listen 443;
        ssl on;
        ssl_certificate nginx.pem;
        ssl_certificate_key nginx.key;

        client_max_body_size 200M;
        server_name localhost 127.0.0.1;
        server_name_in_redirect off;

        location / {
                proxy_pass http://10.10.0.59:80;
                proxy_redirect http://10.10.0.59:80/ /;

                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

}

server {
        listen 80;
        rewrite     ^(.*)   https://$http_host$1 permanent;
        server_name localhost 127.0.0.1;
        server_name_in_redirect off;
        location / {
                proxy_pass http://10.10.0.59:80;
                proxy_redirect http://10.10.0.59:80/ /;
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

The proxy_redirect was taken from how do I get nginx to forward HTTP POST requests via rewrite?

Everything that hits the public IP will hit 443 because of the rewrite. Internally, we are forwarding to 80 on the virtual machine.

But when I run a python script such as the one below to test our configuration

import requests

data = {'username': '....', 'password': '.....'}
url = 'http://IP_A/api/service/signup'

res  = requests.post(url, data=data, verify=False)
print res
print res.json
print res.status_code
print res.headers

I am getting a 405 Method Not Allowed. In nginx we found that when it hit the internal server, the internal nginx was getting a GET request, even though in the original header we did a POST (this was shown in the Python script).

So it seems like rewrite has problem. Any idea how to fix this? When I commented out the rewrite, it hits 80 for sure, and it went through. Since rewrite was able to talk to our internal server, so rewrite itself has no issue. It's just the rewrite dropped POST to GET.

Thank you!

(This will also be asked on Nginx forum because this is a critical blocker...)

share|improve this question

1 Answer 1

up vote 3 down vote accepted

It's not Nginx, it's your browser.

Note from RFC2616:

RFC 1945 and RFC 2068 specify that the client is not allowed to change the method on the redirected request. However, most existing user agent implementations treat 302 as if it were a 303 response, performing a GET on the Location [..]

This is true for all popular browsers and there is nothing you can do about it.

share|improve this answer
    
@c2h50h I understand that the HTTP spec stated something similar like that. But what can I do in Nginx? I mean this is a trivial setup where people forward 443 to an internal 80 port, but they can still do PUT, POST, DELETE, GET. In my previous setup I didn't have this extra proxy at the front serving the crowd. I had the same configuration on the same internal server (our test server). That works fine. –  CppLearner Oct 2 '12 at 20:51
    
Nothing. It's 100% client side. If a webserver, any webserver, returns a 301 or 302 redirect then browser, on client side, will replace any type of request to GET. No server-side configuration or any http headers returned will not change that. It's like that for historical reasons (early browsers behaved that way due to misunderstanding and it became a de facto standard). –  c2h5oh Oct 2 '12 at 20:54
    
Well for one this is not really a browser. Well you can say it's browser because it uses HTTP protocol..okay.. thats fine. But then again, it looks like this only happens if I were doing over this two-layer configuration. If I were to put the same configuration directly on the internal machine, and running the test there, it will not complain. But then again, how do people do it in their production? I would assume some people are doing similar thing, reverse 443 to some VM that may be running 80 only. If there is a better practice, I'd like to learn it and hear about it. –  CppLearner Oct 2 '12 at 20:58
    
By browser I meant HTTP client and with all popular clients POST will become GET if it's 301 or 302 redirected. POST will remain POST on proxy redirect, but not on rewrite. –  c2h5oh Oct 2 '12 at 21:22
    
@c2h50h Thanks. But any way to go around this problem? Any better way to route from proxy to internal (which is 80 by default)? I insist that this is not a common issue so my method is probably really bad so if there's a more practical setup please share :) –  CppLearner Oct 2 '12 at 21:30

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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