# nginx + uwsgi + python [WORKAROUND]

## pigeon768

So I'm trying to cobble together a webserver using nginx + python, and am having problems.

/etc/nginx/nginx.conf: 

```
user nginx nginx;

worker_processes 4;

error_log /var/log/nginx/error_log info;

events {

        worker_connections 1024;

        use epoll;

}

http {

        include /etc/nginx/mime.types;

        default_type application/octet-stream;

        log_format main

                '$remote_addr - $remote_user [$time_local] '

                '"$request" $status $bytes_sent '

                '"$http_referer" "$http_user_agent" '

                '"$gzip_ratio"';

        client_header_timeout 10m;

        client_body_timeout 10m;

        send_timeout 10m;

        connection_pool_size 256;

        client_header_buffer_size 1k;

        large_client_header_buffers 4 2k;

        request_pool_size 4k;

        gzip on;

        gzip_min_length 1100;

        gzip_buffers 4 8k;

        gzip_types text/plain;

        output_buffers 1 32k;

        postpone_output 1460;

        sendfile on;

        tcp_nopush on;

        tcp_nodelay on;

        keepalive_timeout 75 20;

        ignore_invalid_headers on;

        index index.html;

        server {

                listen 80;

                server_name localhost 127.0.0.1;

                access_log /var/log/nginx/localhost.access_log main;

                error_log /var/log/nginx/localhost.error_log info;

                root /var/www/localhost/htdocs/;

                location /static/ {

                         expires 30d;

                }

                location / {

                         include uwsgi_params;

                         uwsgi_pass 127.0.0.1:8080;

                }

        }

}
```

 webpy.py: 

```
#!/usr/bin/python3

from wsgiref.simple_server import make_server

def application(env,start_response):

    status = '200 OK' # HTTP Status

    headers = [('Content-type', 'text/html; charset=utf-8')] # HTTP Headers

    start_response(status, headers)

    query_args = { arg[ 0:arg.find("=",1,-1) ]

                   : arg[ arg.find("=",1,-1)+1 : len(arg) ]

                   for arg in env["QUERY_STRING"].split("&")

                   if arg.find("=",1,-1) > 0 }

    ret_string = """

<!doctype html>

<html lang="en">

<head>

<meta charset="utf-8">

<style>

html { background-image: url(/static/background.jpg); }

body { color: red; }

</style>

<title>

Hello world!

</title>

<body>

<p>Some text here.</p>

"""

    ret_string += "<p>PATH_INFO: " + env["PATH_INFO"] + "</p>"

    for key,val in query_args.items():

        ret_string += "<p>" + key + ":" + val + "</p>"

    ret_string += "</body></html>"

    return [bytes(ret_string,"utf-8")]

httpd = make_server('127.0.0.1', 8080, application)

httpd.serve_forever()
```

 When I point my browser at http://localhost:8080/ (the python application) everything works: 

```
localhost - - [19/Sep/2011 09:10:03] "GET / HTTP/1.1" 200 252

localhost - - [19/Sep/2011 09:10:03] "GET /static/background.jpg HTTP/1.1" 200 273
```

 And I get a web page. If I point my browser at http://localhost/ (nginx) the python app complains: 

```
localhost - - [19/Sep/2011 09:12:57] code 400, message Bad request syntax ('\x00\x81\x02\x00\x0c\x00QUERY_STRING\x00\x00\x0e\x00REQUEST_METHOD\x03\x00GET\x0c\x00CONTENT_TYPE\x00\x00\x0e\x00CONTENT_LENGTH\x00\x00\x0b\x00REQUEST_URI\x01\x00/\t\x00PATH_INFO\x01\x00/\r\x00DOCUMENT_ROOT\x19\x00/var/www/localhost/htdocs\x0f\x00SERVER_PROTOCOL\x08\x00HTTP/1.1\x0b\x00REMOTE_ADDR\t\x00127.0.0.1\x0b\x00REMOTE_PORT\x05\x0033891\x0b\x00SERVER_PORT\x02\x0080\x0b\x00SERVER_NAME\t\x00localhost\t\x00HTTP_HOST\t\x00localhost\x0f\x00HTTP_USER_AGENTB\x00Mozilla/5.0 (X11; Linux x86_64; rv:6.0) Gecko/20100101 Firefox/6.0\x0b\x00HTTP_ACCEPT?\x00text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\x14\x00HTTP_ACCEPT_LANGUAGE\x0e\x00en-us,en;q=0.5\x14\x00HTTP_ACCEPT_ENCODING\r\x00gzip, deflate\x13\x00HTTP_ACCEPT_CHARSET\x1e\x00ISO-8859-1,utf-8;q=0.7,*;q=0.7\x08\x00HTTP_DNT\x01\x001\x0f\x00HTTP_CONNECTION')

localhost - - [19/Sep/2011 09:12:57] "QUERY_STRINGREQUEST_METHODGETCONTENT_TYPECONTENT_LENGTHREQUEST_URI/       PDOCUMENT_ROOT/var/www/localhost/htdocsSERVER_PROTOCOHTTP/1.1REMOTE_ADDR 127.0.0.1REMOTE_PORT33891SERVER_PORT80SERVER_NAME        localhost       HTTP_HOST       localhostHTTP_USER_AGENTBMozilla/5.0 (X11; Linux x86_64; rv:6.0) Gecko/20100101 Firefox/6.0HTTP_ACCEPT?text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8HTTP_ACCEPT_gzip, deflateHTTP_ACCEPT_CHARSETISO-8859-1,utf-8;q=0.7,*;q=0.HTTP_DNT1HTTP_CONNECTION" 400 -
```

 ...and nginx complains about the web app: 

```
2011/09/19 09:12:57 [error] 6002#0: *16 upstream prematurely closed connection while reading response header from upstream, client: 127.0.0.1, server: localhost, request: "GET / HTTP/1.1", upstream: "uwsgi://127.0.0.1:8080", host: "localhost"
```

 ..and after a while I get a 502: Bad Gateway error from nginx in the browser.

Help!

Is it maybe because the python application is serving http:// and nginx is asking for uwsgi:// ? How do I get wsgiref to serve wsgi?

edit: nginx serves everything from /static/ just fine. Obviously the python application doesn't serve anything from /static/.

edit2: Using www-servers/uwsgi. Not in the python standard library but appears to be supported well enough. webpy.py is now:

```
import uwsgi

def application(env,start_response):

    status = '200 OK' # HTTP Status

    headers = [('Content-type', 'text/html; charset=utf-8')] # HTTP Headers

    start_response(status, headers)

    query_args = { arg[ 0:arg.find("=",1,-1) ]

                   : arg[ arg.find("=",1,-1)+1 : len(arg) ]

                   for arg in env["QUERY_STRING"].split("&")

                   if arg.find("=",1,-1) > 0 }

    ret_string = """

<!doctype html>

<html lang="en">

<head>

<meta charset="utf-8">

<style>

html { background-image: url(/static/background.jpg); }

body { color: red; }

</style>

<title>

Hello world!

</title>

<body>

<p>Some text here.</p>

"""

    ret_string += "<p>PATH_INFO: " + env["PATH_INFO"] + "</p>"

    for key,val in query_args.items():

        ret_string += "<p>" + key + ":" + val + "</p>"

    ret_string += "</body></html>"

    return [bytes(ret_string,"utf-8")]
```

 and run with: 

```
uwsgi-3.2 --socket 127.0.0.1:8080 --file webpy.py --callable application
```

----------

