0

We implemented our web application using web2py. It consists of several modules offering a REST API at various resources (e.g. /dids, /replicas, ...). The API is used by clients implementing requests.py.

My problem is that our web app works fine if it's behind HAProxy and hosted by Apache using mod_wsgi. It also works fine if the clients interact with nginx directly. It doesn't work though when using HAProxy in front of nginx. My guess is that HAProxy somehow modifies the request and thus nginx behaves differently i.e. looking for a static file instead of calling the WSGI container. Unfortunately I can't figure out what's exactly going (wr)on(g).

Here are the relevant config sections of these three component's config files. At least I guess they are interesting. If you miss anything, please let me know.

1) haproxy.conf

frontend app-lb
 bind loadbalancer:443 ssl crt /etc/grid-security/hostcertkey.pem
 default_backend nginx-servers
 mode http
backend nginx-servers
 balance leastconn
 option forwardfor
 server nginx-01 nginx-server-int-01.domain.com:80 check

2) nginx.conf:

    sendfile        off;
    #tcp_nopush     on;
    keepalive_timeout  65;
    include /etc/nginx/conf.d/*.conf;
    server {
            server_name nginx-server-int-01.domain.com;
            root /path/to/app/;
            location / {
                    uwsgi_pass unix:///tmp/app.sock;
                    include uwsgi_params;
                    uwsgi_read_timeout 600;  # Requests can run for a serious long time
            }

3) uwsgi.ini

[uwsgi]
chdir = /path/to/app/
chmod-socket = 777
no-default-app = True
socket = /tmp/app.sock

manage-script-name = True
mount = /dids=did.py
mount = /replicas=replica.py
callable = application

Now when I let my clients go against nginx-server-int-01.domain.com everything is fine. In the access.log of nginx lines like these are appearing:

128.142.XXX.XX0 - - [23/Aug/2014:01:29:20 +0200] "POST /dids/attachments HTTP/1.1" 201 17 "-" "python-requests/2.3.0 CPython/2.6.6 Linux/2.6.32-358.23.2.el6.x86_64" "-"
128.142.XXX.XX0 - - [23/Aug/2014:01:29:20 +0200] "POST /dids/attachments HTTP/1.1" 201 17 "-" "python-requests/2.3.0 CPython/2.6.6 Linux/2.6.32-358.23.2.el6.x86_64" "-"
128.142.XXX.XX0 - - [23/Aug/2014:01:29:20 +0200] "POST /dids/user.ogueta/cnt_mc12_8TeV.16304.stream_name_too_long.other.notype.004202218365415e990b9997ea859f20.user/dids HTTP/1.1" 201 17 "-" "python-requests/2.3.0 CPython/2.6.6 Linux/2.6.32-358.23.2.el6.x86_64" "-"
128.142.XXX.XX0 - - [23/Aug/2014:01:29:20 +0200] "POST /replicas/list HTTP/1.1" 200 5282 "-" "python-requests/2.3.0 CPython/2.6.6 Linux/2.6.32-358.23.2.el6.x86_64" "-"
128.142.XXX.XX0 - - [23/Aug/2014:01:29:20 +0200] "POST /replicas/list HTTP/1.1" 200 5094 "-" "python-requests/2.3.0 CPython/2.6.6 Linux/2.6.32-358.23.2.el6.x86_64" "-"
128.142.XXX.XX0 - - [23/Aug/2014:01:29:20 +0200] "POST /replicas/list HTTP/1.1" 200 528 "-" "python-requests/2.3.0 CPython/2.6.6 Linux/2.6.32-358.23.2.el6.x86_64" "-"
128.142.XXX.XX0 - - [23/Aug/2014:01:29:21 +0200] "GET /dids/mc13_14TeV/dids/search?project=mc13_14TeV&stream_name=%2Adummy&type=dataset&datatype=NTUP_SMDYMUMU HTTP/1.1" 401 73 "-" "python-requests/2.3.0 CPython/2.6.6 Linux/2.6.32-358.23.2.el6.x86_64" "-"
128.142.XXX.XX0 - - [23/Aug/2014:01:29:21 +0200] "POST /replicas/list HTTP/1.1" 200 713 "-" "python-requests/2.3.0 CPython/2.6.6 Linux/2.6.32-358.23.2.el6.x86_64" "-"
128.142.XXX.XX0 - - [23/Aug/2014:01:29:21 +0200] "POST /dids/attachments HTTP/1.1" 201 17 "-" "python-requests/2.3.0 CPython/2.6.6 Linux/2.6.32-358.23.2.el6.x86_64" "-"

But when I switch the clients to go against HAProxy (loadbalancer.domain.com:443), the error.log of nginx shows lines like these:

2014/08/23 01:26:01 [error] 1705#0: *21231 open() "/usr/share/nginx/html/dids/attachments" failed (2: No such file or directory), client: 128.142.XXX.XX1, server: localhost, request: "POST /dids/attachments HTTP/1.1", host: "loadbalancer.domain.com"
2014/08/23 01:26:02 [error] 1705#0: *21232 open() "/usr/share/nginx/html/replicas/list" failed (2: No such file or directory), client: 128.142.XXX.XX1, server: localhost, request: "POST /replicas/list HTTP/1.1", host: "loadbalancer.domain.com"
2014/08/23 01:26:02 [error] 1705#0: *21233 open() "/usr/share/nginx/html/dids/attachments" failed (2: No such file or directory), client: 128.142.XXX.XX1, server: localhost, request: "POST /dids/attachments HTTP/1.1", host: "loadbalancer.domain.com"
2014/08/23 01:26:02 [error] 1705#0: *21234 open() "/usr/share/nginx/html/replicas/list" failed (2: No such file or directory), client: 128.142.XXX.XX1, server: localhost, request: "POST /replicas/list HTTP/1.1", host: "loadbalancer.domain.com"
2014/08/23 01:26:02 [error] 1705#0: *21235 open() "/usr/share/nginx/html/dids/attachments" failed (2: No such file or directory), client: 128.142.XXX.XXX, server: localhost, request: "POST /dids/attachments HTTP/1.1", host: "loadbalancer"
2014/08/23 01:26:02 [error] 1705#0: *21238 open() "/usr/share/nginx/html/replicas/list" failed (2: No such file or directory), client: 128.142.XXX.XXX, server: localhost, request: "POST /replicas/list HTTP/1.1", host: "loadbalancer.domain.com"
2014/08/23 01:26:02 [error] 1705#0: *21239 open() "/usr/share/nginx/html/dids/attachments" failed (2: No such file or directory), client: 128.142.XXX.XXX, server: localhost, request: "POST /dids/attachments HTTP/1.1", host: "loadbalancer.domain.com"
2014/08/23 01:26:02 [error] 1705#0: *21242 open() "/usr/share/nginx/html/replicas/list" failed (2: No such file or directory), client: 128.142.XXX.XXX, server: localhost, request: "POST /replicas/list HTTP/1.1", host: "loadbalancer.domain.com"
2014/08/23 01:26:02 [error] 1705#0: *21244 open() "/usr/share/nginx/html/dids/attachments" failed (2: No such file or directory), client: 128.142.XXX.XXX, server: localhost, request: "POST /dids/attachments HTTP/1.1", host: "loadbalancer.domain.com"

As you can see, that request looks the same, only the client IP changed, from the client's host to the one from loadbalancer.domain.com. But due to what ever reasons ngxin seems to assume that it is a static file to be served which eventually results in the file not found message.

I searched the web for multiple hours already, but without much luck so far. Any help is very much appreciated.

Cheers, Ralph

Ralph
  • 33
  • 5
  • Can you add more information to your question, precisely show us the output of curl request to load balancer and directly to server? – Jakov Sosic Aug 24 '14 at 15:25
  • Hi Jakov, I figured the problem out by myself this morning and posted my solution below. But thanks for responding anyway. Cheers, Ralph – Ralph Aug 25 '14 at 13:05

1 Answers1

0

I figured out what the problem was in my setup.

As stated in the question, as soon as the requests have been redirected from HAProxy, nginx didn't map them to the defined WSGI container, but tried serving a static file instead. It turned out that this behaviour was the consequence of the

server_name nginx-server-int-01.domain.com;

directive in my nginx - config. This directive indicates that this server block is only applicable to requests directed to nginx-server-int-01.domain.com which is enforced by checking if the HTTP header field 'host' matches.

But requests sent to HAProxy have consequently 'loadbalancer.domain.com' set as host field, and HAProxy, being as transparent as possible, doesn't update this field when forwarding an HTTP request. Thus nginx received requests with 'loadbalancer.domain.com' which didn't match any defined server directive. Eventually nginx decided to play it safe and check for a static file (being the default setting) which resolved to the 404 Not found response as non of these files existed.

So after updating my nginx.conf to the server block defining the WSGI directives as default, it treats every request, independently of the host value, as a WSGI request if the URI matches. To do so, one must simply replace the server_name directive the following two lines

listen 80 default_server;
server_name _;

Hope this helps anyone.

Cheers, Ralph

Ralph
  • 33
  • 5
  • You would normally update your domain's A record to point to your loadbalancer after it's set up correctly. Test that everything is working by creating an appropriate `hosts` entry on your workstation prior to that. – Felix Frank Aug 26 '14 at 08:28