Serving a request from gunicorn
Asked Answered
C

4

19

Trying to setup a server on Rackspace.com.

Have done the following things:

  • Installed Centos 6.3
  • Installed Python 2.7
  • Installed gunicorn using the "Quick Start" on their home page: gunicorn.org/

In the quick start, a "hello world" application seems to be initialized:

Create file "myapp.py":

(tutorial) $ vi myapp.py
(tutorial) $ cat myapp.py

Contents of "myapp.py"

def app(environ, start_response):
   data = "Hello, World!\n"
   start_response("200 OK", [
       ("Content-Type", "text/plain"),
       ("Content-Length", str(len(data)))
   ])
   return iter([data])

Since I know very little about servers, I do not know what to do next. I tried typing the server's IP address into the browser, but that seemed to result in a timeout.

I'm not sure if there is:

  • something else that needs to be installed. Nginx is mentioned under "deploy" on the gunicorn website. Looks like Nginx is a proxy server which is confusing to me because I thought gunicorn was a server. Not sure why I need two servers?
  • something that needs to be configured in gunicorn
  • something that needs to be configured on the server itself
  • something that else entirely that needs to be done in order to actually serve a request

What are the next steps?

Thanks so much!

Chasidychasing answered 12/10, 2012 at 12:4 Comment(0)
R
28

looking at the quickstart guide, you probably should have run

(tutorial) $ ../bin/gunicorn -w 4 myapp:app

which should have produced a line that looks a bit like:

Listening at: http://127.0.0.1:8000

Among others. see if you can access your site at that address.

Also Note that 127.0.0.1 is the loopback address; accessible only from that host itself. To get gunicorn to bind to a different option, pass it --bind 0.0.0.0:80, as Jan-Philip suggests.

Since you mention rackspace, its possible that you may need to adjust the firewall settings to allow incoming connections to the desired ports.

Raffinate answered 12/10, 2012 at 12:48 Comment(0)
K
38

since gunicorn is a Web server on your case Nginx will act as a back proxy passing the an HTTP request from Nginx to gunicorn.

So, I will put here the steps to take for a simple Nginx and Gunicorn configuration running on the same machine.

  • Starting with nginx configuration

Go to your /etc/nginx/nginx.conf and under the http{} make sure you have: include /etc/nginx/site-enabled/*;

http{
    # other configurations (...)
    include /etc/nginx/sites-enabled/*;
}

now, include a file on /etc/nginx/sites-enabled/mysite.conf where you will proxy your requests to your gunicorn app.

server {
    listen 80 default; # this means nginx will be 
                       # listening requests on port 80 and 
                       # this will be the default nginx server
    server_name localhost;

    # declare proxy params and values to forward to your gunicorn webserver
    proxy_pass_request_headers on;
    proxy_pass_request_body on;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_read_timeout 120s;

    location / {
        # here is where you declare that every request to / 
        # should be proxy to 127.0.0.1:8000 (which is where
        # your gunicorn will be running on)          
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_connect_timeout 10;
        proxy_read_timeout 10;

        proxy_pass http://127.0.0.1:8000/; # the actual nginx directive to 
                                           # forward the request
    }
}

Ok, at this point all you have is an Nginx acting as a proxy where all the requests going to 127.0.0.1:80 will be passed to 127.0.0.1:8000.

  • Now is time to configure your Gunicorn webserver:

Usually the way I do I use a configuration file, Gunicorn config file can be an ordinary python file. So now, create a file at any location you like, I will assume this file will be /etc/gunicorn/mysite.py

workers = 3              # number of workers Gunicorn will spawn 

bind = '127.0.0.1:8000'  # this is where you declare on which address your 
                         # gunicorn app is running.
                         # Basically where Nginx will forward the request to

pidfile = '/var/run/gunicorn/mysite.pid' # create a simple pid file for gunicorn. 

user = 'user'          # the user gunicorn will run on

daemon = True          # this is only to tell gunicorn to deamonize the server process

errorlog = '/var/log/gunicorn/error-mysite.log'    # error log

accesslog = '/var/log/gunicorn/access-mysite.log'  # access log

proc_name = 'gunicorn-mysite'            # the gunicorn process name

Ok, all set in configuration. Now all you have to do its to start the servers.

Starting the gunicorn and telling it which app to use and which config file. from the command line and the folder where your myapp.py file is located run:

gunicorn -c /etc/gunicorn/mysite.py mysite:app

Now, only start nginx.

/etc/init.d/nginx start 

or

service nginx start

Hope this helps.

Kinson answered 12/10, 2012 at 12:44 Comment(0)
R
28

looking at the quickstart guide, you probably should have run

(tutorial) $ ../bin/gunicorn -w 4 myapp:app

which should have produced a line that looks a bit like:

Listening at: http://127.0.0.1:8000

Among others. see if you can access your site at that address.

Also Note that 127.0.0.1 is the loopback address; accessible only from that host itself. To get gunicorn to bind to a different option, pass it --bind 0.0.0.0:80, as Jan-Philip suggests.

Since you mention rackspace, its possible that you may need to adjust the firewall settings to allow incoming connections to the desired ports.

Raffinate answered 12/10, 2012 at 12:48 Comment(0)
C
8

Looks like you do not have a web application developed so far. So, I assume that your goal for now is to set up a development environment. For the time being, develop your web application using the development web server included in most frameworks, e.g. Flask.

Whatever framework you are using, make the development web server listen on 0.0.0.0 so that the service is listening on all configured network interfaces and make sure that the port is open to the outside (check the Rackspace settings).

When you are done developing your application or are looking into an existing one, you have to deploy it in a solid way. Then, gunicorn behind nginx is an option.

I will roughly go through your questions. It looks you have to read a bit more :-)

  • Nginx is mentioned under "deploy" on the gunicorn website. Looks like Nginx is a proxy server which is confusing to me because I thought gunicorn was a server. Not sure why I need two servers?

Nginx is a full-featured web server. It is appreciated for its performance and stability. People use it to serve static files (to not burden a dynamic web application with this task), to forward requests to web applications whenever necessary, for SSL-termination, and for load-balancing. Note that this is an incomplete picture.

gunicorn is a server for serving WSGI apps. Mainly, it manages worker processes that actually execute the web application.

  • something that needs to be configured in gunicorn. something that needs to be configured on the server itself. something that else entirely that needs to be done in order to actually serve a request.

Actually, you can optimize your linux box in endless ways (for performance, e.g. increase the file descriptor limit and for security). Within gunicorn, you can configure the number of worker processes and a lot more. If you have nginx as frontend or even another load balancer, this one has its own configuration. You see, your setup might become very complex for actual deployment in a real-world scenario. This is not trivial.

However, for playing around with a WSGI application, just set up your development framework properly, which is very simple in most cases, and make sure that there are no firewall issues. That's all.

Congeneric answered 12/10, 2012 at 12:31 Comment(0)
C
0

You might just need to bind to something other than localhost:8000 (127.0.0.1:8000)

Assuming that you are in a python venv, or otherwise can run gunicorn --help from a command line, then you should see an option:

-b ADDRESS, --bind ADDRESS
    The socket to bind. [['127.0.0.1:8000']]

As you can see the default is to bind only to localhost, 127.0.0.1 so if you are able to access the endpoint using the localhost address, but cannot access it from an address external to the host machine, eg from local or remote networks then your problem is likely solved by simply binding to all interfaces / addresses.

Add a --bind argument. For example, I am running my application with:

gunicorn -w 4 'server:app' --bind 0.0.0.0:8000
Complicate answered 23/9, 2023 at 21:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.