Python Bottle+virtualenv+uWSGI+Nginx installation on Ubuntu 12.04.1 LTS

bottle+uwsgi+nginx

为了造福世界人民,我觉得还是用英语写吧 XD

Today I got a request to write a backend server to provide interface access from frontend. I determined to use Python and  RESTful api firstly . I hate writing Java code…

After some investigation, I picked up Bottle. It is very neat and small. And I also read that with nginx and uWSGI, the performance is good too.

My environment is Ubuntu 12.04.1 LTS; but after followed several posts, my environment still did not work. I want to share my findings to save others’ time:)

Let’s cut to the chase:

  • Note:

My application would be in below directory constructure, all following commands and configurations are based on below:
/var/www/myapp would be the root directory of my bottle app
/var/www/myapp/env would be the virtualenv for the app
/var/www/myapp/index.py would be main .py file of bottle

  • Install nginx and uwsgi:
sudo apt-get update
sudo apt-get install -y nginx uwsgi
sudo apt-get install uwsgi-plugin-python
  • Install pip to help install python modules
sudo apt-get install python-pip
  • Install virtualenv: virtualenv to seperate the Python environment for different deployments
sudo pip install virtualenv
  • Set up app virtualenv:
sudo mkdir -p /var/www/myapp
sudo virtualenv /var/www/myapp/env
source /var/www/myapp/env/bin/activate
pip install bottle
deactivate
  • Change the permission of the app directory so that uWSGI can read it and Python can write in it
sudo chown -R www-data:www-data /var/www/myapp
  • OK, the most important part: the configuration of nginx and uWSGI. These two recipes would worth some money XD

1. nginx config:

sudo gedit /etc/nginx/sites-enabled/default

copy below config in opend file:

server {

     listen   80;
     charset utf-8;
     root /var/www/myapp;
     server_name localhost;

location / {
     include uwsgi_params;
     uwsgi_pass unix:/tmp/uwsgi.myapp.socket;
     uwsgi_param UWSGI_PYHOME /var/www/myapp/env;
     uwsgi_param UWSGI_CHIDIR /var/www/myapp;
     uwsgi_param UWSGI_SCRIPT index; # this should be the .py file name without suffix that your bottle will use to launch
     }
}

2.uWSGI config:

sudo gedit /etc/uwsgi/apps-enabled/uwsgi.ini

copy below config in opend file:

[uwsgi]
plugins=python
socket=/tmp/uwsgi.myapp.socket
pythonpath=/var/www/myapp
  • Now we are one step to success. In order to verify the setup, we need a sample index.py file ( the file name must be consistent with the one in UWSGI_SCRIPT in nginx config).

Put index.py under /var/www/myapp

#!/usr/bin/env python
from bottle import route, run, default_app
@route('/')
def index():
    return "Aloha, world~"

if __name__ == "__main__":
    run(host="localhost", port=8081)
else:
    application = default_app()
  • Finally, Restart/start nginx and uWSGI services:
sudo service nginx restart
sudo service uwsgi restart

Now “it’s the moment to witness the miracle!” 😀  Access http://localhost/ in your browser, you should  see “Aloha, world~”.  If not, comment below:)

Advertisements

20 thoughts on “Python Bottle+virtualenv+uWSGI+Nginx installation on Ubuntu 12.04.1 LTS

  1. Why did we modify the file named default and not the file named nginx.config? I did all of the commands but it failed when I tried to restart nginx. I got this error message: Restarting nginx: nginx: [emerg] invalid number of arguments in “listen” directive in /etc/nginx/sites-enabled/default:3
    nginx: configuration file /etc/nginx/nginx.conf test failed
    Anyway, I feel like I’m 95% there because you’re tutorial is really good and I’d love to get this working. Thanks…

    • Oops. I had a typo in my index.py file. I typed botle instead of bottle! And then I had to change servername localhost to servername and my ip address. And everything works like a charm! Thanks!

      Although I’m still confused as to why we edit a file named default instead of nginx.config.

      Also, I’m not sure how to handle ipv6 stuff? Do we need to add additional server/location listen blocks for ipv6 addresses?

      Anyway, thanks dude! This is the first time I’ve ever gotten python to work on the web and I’ve been trying for over a week!

      • Actually nginx reads config files in the sites-enabled directory. The name of the file may be not that important if you only got one enabled config. That’s my guess though.

  2. Sean, my index.py works on swikit.com. However, i can’t get any other page in the root folder to show up. I have a page called snoopy.html at swikit.com/snoopy.html. It should load but I get a 404. It works, however, if I put it in static. (swikit.com/static/snoopy.html). Also, I can’t get other .py files to open on root either. So I was hoping maybe you could give me general/specific info on what I’m doing wrong.

    I apologize if you see this question twice. I posted a comment last night but it hasn’t shown up yet so I think I may not have submitted it correctly or something.

    Thanks,

    David
    Nashville

    • I do not know your meaning about “html can be loaded or cannot”. there is no code snippet. Maybe you should check the the route decorator and the static_file method section in bottle documentation?

  3. Ok, thanks for your help. I’ll look at the route decorator.

    What I meant was that I can’t browse to the page called swikit.com/snoopy.html. I get a 404 error (page not found) even though the page is in my root folder. And (to me), those pages should just work automatically. But I guess python/bottle doesn’t work like that…

    It took me a while to get the syntax right for the route decorator to handle css files in my static folder. I finally got that to work …but I thought I only needed a route decorator for static files (a special case of some kind). Evidently, I need it for any page/path.

    Sorry for all the questions.

  4. Using your tutorial, my index.py file works. ( you can see my site when you visit swikit.com ).

    But how, in general, do I get a .py file to work off the root (or anywhere for that matter).
    example: swikit.com/hello.py will not work even though I have a good hello.py file in the root folder.

    And I’ve tried everything but I can’t get swikit.com/snoopy.html page to work either. Snoopy.html is in my root folder.

    I have this folder structure:
    var
    www
    swikit
    static
    views
    env
    with bottle stuff in it

    Anyway, I am a .net programmer and I kick ass in the .net world with IIS… but I’ve spent 3 weeks on linux and python and I cannot do the simplest things. And I have to be misunderstanding something very fundamental on how to get this stuff to work. I just want to put .py files wherever I want and run them… and .html files where I want, etc… just like I do in .net.

    If you are too busy, it’s cool, I understand. I just have no idea what to do. Changing the route decorator hasn’t helped. I’ve tried adding different kinds of additional location commands in the default file for nginx. etc. etc.

    Also, second question. Using your setup instructions, will that automatically set nginx up as a front end proxy server that only serves static files and then directs the rest of the traffic to uwsgi?
    If not, can you give me general advice on what to do to set that kind of thing up…

    Thanks, I apologize for all the questions.

    David

    • actually I just set up a small site using Bottle, so I did not investigate that much.
      I know that it’s a pain for a Windows based programmer to understand Linux based programming and setup.. but I think that my tutorial is just a simple guide, you should read more about nginx config and uwsgi config if you want to set up a complex website. (in my understanding, one .py file with default_app and app() method is one app for bottle).

      I suggest you go to stackoverflow and/or the mail group for more help if cannot figure out more.

  5. Hi, I have problems after: Put index.py under /var/www/myapp

    i can’t write in this folder and I can’t copy the file index.py on here :S

  6. This worked great for me until I tried to move the app into a different URL.

    I want to load the app on the location “/foo” and changed the nginx location to “location /foo”. I figured that would be it but I get a 404 (from uWSGI not nginx). I tried adding a route for “/foo” in index.py but that didn’t work either.

    Do I need to change something else?

  7. this solved a huge problem for me. You said “it was worth some money” as a joke, but I would like to give you some. let me know how you want it (paypal, whatever)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s