WebFaction
Community site: login faq

My main question here is: Did I set it up right, or what would be the more preferable way of going about it regarding the directory structure, configs, whatever else I may just not know about for setting up a web server! Is there something I need to do to ensure it auto-restarts if the server crashes or something? I guess I could have asked this in a support ticket, but figured

I just recently got a server with WebFaction and started trying to set it up with using nginx+gunicorn+flask as my first project. I started by installing python 2.7.2 into lib/python2.7.2 and then installed distribute/pip/virtualenv/virtualenvwrapper for that python install and created a virualenv from it. I downloaded and extracted nginx-1.0.11 into webapps/nginx(which is a "custom app(listening)" in the control panel), and pip installed gunicorn+flask into my py27 virtualenv. I started up nginx and tested my url, which displayed the basic "nginx is working" page. I then opened up my nginx.conf to start trying to adjust it to work with gunicorn. This is the main part where I feel I could probably use some tips.

I read through a lot of the nginx docs, and understand the majority of the various settings/directives. I am not completely sure how the magic works with the upstream block or the named location for setting up the proxy(I used http://gunicorn.org/deploy.html as a starting point and changed very little), but I was surprised I was able to set just any port on 127.0.0.1 given this is a shared box? I probably just don't understand what all I have access to when using my WebFaction's server solution! The directives that are commented out are that way because that is the way they came and I don't know why/when I would need them yet.

This is my current webapps/nginx/conf/nginx.conf:

#user  nobody;
worker_processes  1;

pid logs/nginx.pid;
error_log logs/nginx.error.log;

events {
    worker_connections  1024;
    accept_mutex off;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    access_log  logs/nginx.access.log  combined;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    gzip  on;
    gzip_comp_level 2;
    gzip_types    text/plain text/html text/css
                  application/x-javascript text/xml
                  application/xml application/xml+rss
                  text/javascript;

    upstream frontends {
        server 127.0.0.1:18000;
    }

    server {
        listen       port;
        server_name  example.com;

        keepalive_timeout 5;

        root html;

        location / {
            root   html;
            index  index.html index.htm;
        }
        location /yo/ {
            #checks for static file, if not found proxy to app
            try_files $uri @proxy_to_app;
        }

        location @proxy_to_app {
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_redirect off;

            proxy_pass http://frontends;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

I then created the following webapps/nginx/conf/gunicorn.conf in the webapps/nginx/conf directory:

workers = 2
bind = '127.0.0.1:18000'
procname = 'example.com'
pidfile = '~/webapps/nginx/logs/gunicorn.pid'

I and then a simple flask app to test it all(test.py), located within webapps/nginx/html with:

from flask import Flask
from flask import render_template_string
from werkzeug.contrib.fixers import ProxyFix

app = Flask(__name__)

@app.route('/yo/')
def index():
    return render_template_string('yo!')

app.wsgi_app = ProxyFix(app.wsgi_app)

Given those files I start nginx by calling webapps/nginx/sbin/nginx, and then I start up gunicorn from the directory of the flask app by calling gunicorn -c ../conf/gunicorn.conf test:app. At this point if I go to .example.com it'll load the default "Welcome to nginx page!", and if I go to example.com/yo/ it will utilize the flask app and display "yo!'

Anyways my goal for this post is to hopefully get some tips from those with more experience on the best way to setup the nginx/gunicorn config, as well as hopefully give people trying to do this some guidance to at least get to the level of having a working site.

asked 27 Jan '12, 12:22

rdb's gravatar image

rdb
313
accept rate: 0%


Hello,

A few things to cover,

Your python steps are OK, you likely did not need to build python from source, but it does not hurt.

For the guicorn app and frontend setting you need a second 'custom app' and you should be using its port. You can technically assign any port that is open on the server, however we will not promise that the port will not get assigned in the future, and if your are using it and not assigned to it we may stop the app and send you a warning.

Although it gives you an extra layer of configuration, which sometimes you want, you do not need to build your own nginx stack to deploy this. The front-end nginx server is already a proxy server that can have a port assigned to it.

I have a community post that deploys django using the front-end nginx server and guinicorn. The same general steps apply to other gunicorn apps.

permanent link

answered 27 Jan '12, 17:16

johns's gravatar image

johns ♦♦
4.9k29
accept rate: 23%

I had a hard time finding & reading various articles and putting it all together. Below is a summary for a Flask app but a similar approach can be used for Django.

If you don't need to custom configure Nginx settings, you can make use of WebFaction's system Nginx instance. It will save you shared RAM and CPU.

Overview

  • Create a 'Custom app (listening on port)' application to serve gunicorn
  • Create a 'Symbolic link to static-only app' application to serve static files
  • Create a 'Website'
  • Configure gunicorn to start the Flask app (or Django)
  • Configure supervisord to manage gunicorn
  • Configure cron to start supervisord

Create a 'Custom app (listening on port)' application

  • From WebFaction's main menu, select Domains/Websites > Application > Add new application
  • Name: MY_APP
  • App category: Custom
  • App type: Custom app (listening on port)
  • Click Save

Re-open the newly added app and take note of the port number in the 'Port' section. This article will use a value of 12345, which you will need to replace.

This article will assume that the file /home/USERNAME/webapps/MY_APP/src/app/__init__.py contains a WSGI App named application that can be started using gunicorn app:application

Create a 'Symbolic link to static-only app' application to serve static files

  • From WebFaction's main menu, select Domains/Websites > Application > Add new application
  • Name: MY_APP_static
  • App category: Symbolic link
  • App type: Symbolic link to static-only app
  • Extra info: /home/USERNAME/webapps/MY_APP/src/app/static
  • Click Save

Substitute USERNAME and MY_APP/src/app/static according to your environment.

Create a 'Website'

  • From WebFaction's main menu, select Domains/Websites > Websites > Add new website
  • Under the 'Contents' section
  • Add an application > Reuse an existing application > MY_APP
  • Add an application > Reuse an existing application
    • Application: MY_APP_static
    • URL: static
  • Click Save

Configure gunicorn to start the Flask app

(Optionally) create a virtualenv:

mkvirtualenv MY_APP    # create new virtualenv
workon MY_APP    # switch to virtualenv

Install gunicorn:

pip install gunicorn

Make note of the full path to gunicorn:

which gunicorn

You should be able to start the Flask app with gunicorn like so:

gunicorn -w 2 -b 0.0.0.0:12345 app:application

Substitute port 12345 according to your environment.

Type Control-C to exit gunicorn.

Configure supervisord to manage gunicorn

Supervisor is used to restart gunicorn whenever it closes unexpectedly.

We recommend installing supervisor outside of any virtualenvs so it can manage multiple Flask applications if needed

deactivate   # exit any virtualenvs
pip install supervisor

Make a note of where supervisord is installed:

which supervisord

Create a default supervisord.conf file:

cd ~
echo_supervisord_conf > ~/supervisord.conf

Edit ~/supervisord.conf and add the following stanza at the bottom of this file:

[program:my_app]
user=USERNAME
directory=/home/USERNAME/webapps/MY_APP/src
command=/FULL/PATH/TO/gunicorn -w 2 -b 0.0.0.0:12345 "app:application"
autostart=true
autorestart=true
redirect_stderr=true

Make sure to use fully qualified paths and substitute FULL/PATH/TO, port 12345, USERNAME, and MY_APP/src according to your environment.

You can start supervisor with:

supervisord -c ~/supervisord.conf

Which should start gunicorn

Configure cron to start supervisord

Cron can start supervisord after the host system reboots by adding a @reboot entry to cron:

Edit the crontab with:

crontab -e

Add the following line at the top of the crontab file:

@reboot /home/USERNAME/bin/supervisord -c /home/USERNAME/supervisord.conf

Make sure to use fully qualified paths and substitute USERNAME according to your environment.

permanent link

answered 21 Sep, 08:33

lingthio's gravatar image

lingthio
112
accept rate: 0%

edited 21 Sep, 20:23

Your answer
toggle preview

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Markdown Basics

  • *italic* or _italic_
  • **bold** or __bold__
  • link:[text](http://url.com/ "title")
  • image?![alt text](/path/img.jpg "title")
  • numbered list: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • basic HTML tags are also supported

Question tags:

×183
×42
×12

question asked: 27 Jan '12, 12:22

question was seen: 9,831 times

last updated: 21 Sep, 20:23

WEBFACTION
REACH US
SUPPORT
AFFILIATE PROGRAM
LEGAL
© COPYRIGHT 2003-2016 SWARMA LIMITED - WEBFACTION IS A SERVICE OF SWARMA LIMITED
REGISTERED IN ENGLAND AND WALES 5729350 - VAT REGISTRATION NUMBER 877397162
5TH FLOOR, THE OLD VINYL FACTORY, HAYES, UB3 1HA, UNITED KINGDOM