Categories
Linux Python

Deploying a Flask app on Ubuntu: uWSGI, nginx and Upstart

Let’s get straight to the point. I have a Flask app that I want to run on Ubuntu. I shall use uwsgi and nginx. Upstart will be used to monitor the process and restart it if it’s killed or dies an untimely death.

Running the uWSGI app with nginx

It’s very easy to run Flask apps with uwsgi, just cd into the directory where your main app file exists and pass the uwsgi module name. If your main app file is called “main.py” and if your Flask app instance is called “app” inside main.py, then your uWSGI module name would be “main:app” from the directory where main.py resides.

cd /home/dev/awesome-flask-app
uwsgi --socket 127.0.0.1:8080 -w main:app

Now, we need to configure nginx:

upstream flaskapp {
        server 127.0.0.1:8080;
 }


server {
    listen 80;

    location / {

            include            uwsgi_params;
            uwsgi_pass         flaskapp;

            proxy_redirect     off;
            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_set_header   X-Forwarded-Host $server_name;

        }

}

Here, we first need to define an upstream. We define the “flaskapp” upstream for our app. Then inside the location block, we use it as the source of our uwsgi_pass directive. It would tell nginx to connect to the uwsgi server we defined and serve as a bridge between the internet and the flask uwsgi app.

Upstarting the uWSGI process

Now, what happens if our uWSGI process dies? nginx would no longer be able to connect to the app and throw a “bad gateway” error. So we need to make sure that if the process dies from an error or somehow gets killed, it is restarted automatically. There are a few tools which can do this. Supervisord is the most popular one, Circus is also very nice. However, I like to use Upstart for cases like this. Upstart comes with Ubuntu and used by the OS for many of it’s own services. It’s easy to use, already available, reliable and most importantly – it allows me to create a service too!

To create our upstart config, we cd into “/etc/init” and create a new file named “flaskapp.conf”. Then we put the following contents in there:

start on runlevel [2345]
stop on runlevel [016]

respawn

script
    cd /home/dev/awesome-flask-app
    exec uwsgi --socket 127.0.0.1:8080 -w main:app
end script

Here, we’re telling Upstart to launch our app on startup and respawn whenever the process dies. We put our commands in a script block. We have defined our service, now time to fire it up. If you have any uwsgi process run with the same config, first kill them. Then run this command to start the service:

sudo service flaskapp start

Right, you can use the usual “start|stop|restart|status” service commands with it. The service name is derived from the file name we used in “/etc/init”. The log of the process would be found in “/var/log/upstart/flaskapp.log”.

From Upstart to Systemd

Ubuntu is moving away from Upstart to systemd. Most of my apps use Ubuntu 14.04 LTS so I can still use Upstart fine. However, if your version of Ubuntu doesn’t ship Upstart, you can use systemd for similar tasks. Here’s the link: systemd for upstart users

Categories
Linux Python

Python and Django on Vagrant

Well, this is going to be another straight forward post with loads of shell commands. The background is simple, I love OS X for the many apps it offers but at the same time I always had the joy of developing on a Linux machine. I decided to use Vagrant to have one central box for my projects. I use separate vagrant boxes for complicated projects. But didn’t like the idea of having individual boxes for simple ones.

I work on Python and Django a lot. So in this post I am going to document my setup.

Vagrant File:

# I have assigned a private IP to the box
# I have assigned a hostname to it.
# I am using Ubuntu Precise Pangolin 64 bit as my base box (which I already have added)

# -*- mode: ruby -*-
# vi: set ft=ruby :

# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  
  config.vm.box = "precise64"

  config.vm.network :private_network, ip: "192.168.234.131"
  config.vm.hostname = "tardis.dev"
end

Hosts File (/etc/hosts):

 
192.168.234.131 tardis.dev

After I setup the box, I logged in using SSH:

vagrant ssh

Now, the usual Ubuntu setup.

sudo apt-get install python-pip
sudo pip install virtualenv
mkdir ~/.virtualenvs
sudo pip install virtualenvwrapper
sudo apt-get install python-dev libmysqlclient-dev libpq-dev

Bash Profile in the Ubuntu machine:

# To make the Django built in server available from outside the box I need to run it on 0.0.0.0 so that it listens on all interfaces. So I added a handy alias.

# Added the virtualenv stuff to the profile

# Virtual Env
export WORKON_HOME=~/.virtualenvs
. /usr/local/bin/virtualenvwrapper.sh

# Aliases
alias djrun="python manage.py runserver 0.0.0.0:8000"

Bootstrapping a project:

mkvirtualenv project
cd ~/project
pip install -r requirements.txt

## Later
workon env_name
djrun

Now the app would be available on: http://tardis.dev:8000

I also modify the ~/.virtualenvs//bin/postactivate script to cd into the project source directory. Saves time when I hit “workon env_name”

That’s it 🙂

Categories
Linux

Debugging MongoDB Connection Issues

I am working on a project where I connect to MongoDB from PHP using the PECL extension. Regardless of your stack, we might time to time face strange issues when our clients can’t connect to the mongodb server. In this post, I would document what I did in my case.

First test if the mongodb server can be connected to. Use the “mongo” shell client.

mongo --host localhost:27017

If the connection succeeds, then the server is definitely reachable. You have made some mistakes in configuring your client. A very common mistake is having a malformed connection URI. So double check if you typed in your host, port and other details properly in the connection string.

If the above fails, that means the server is not responding. To begin with, try restarting it.

sudo service mongodb restart

If the server started well, try again. Still connection failed? OK, the server might be damaged. How about checking the log files?

tail -f /var/log/mongodb/mongodb.log

Nothing interesting? Or do not understand the format? Well, then let’s try blindly repairing the server:

sudo rm /var/lib/mongodb/mongod.lock   
sudo -u mongodb mongod -f /etc/mongodb.conf --repair 
sudo service mongodb start

Your problem should be resolved by now. But if it doesn’t solve the issue, your problem is not a common one. Try Googling further or asking on StackOverflow or other programming forums.