LEMP Stack Installation with Nginx, uWSGI, and MariaDB on Ubuntu 14.04

Update Your Packages

Before installing the components for a LEMP stack, you want to make sure your system is up to date. Since we’re opting to use MariaDB rather than MySQL, we’ll also add a repository for our preferred MariaDB version.

sudo apt-get install software-properties-common
sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db
sudo add-apt-repository 'deb http://ftp.utexas.edu/mariadb/repo/10.1/ubuntu trusty main'

If you’re not particular about the MariaDB version you use, the commands above can be skipped.

Next, update the machine’s package list and upgrade any packages that can be upgraded.

sudo apt-get update
sudo apt-get -y upgrade

Since this stack is using uWSGI and I’m planning on deploying a Python application, I install pip and a few dependent packages.

sudo apt-get -y install build-essential debconf-utils python-dev libpcre3-dev libssl-dev python-pip

MariaDB

The line below will begin the installation process for MariaDB. During this process, you’ll be asked to set a root password. This is separate from the system user.

apt-get -y install mariadb-server

When the installation is complete, run a script to secure the database. You can just accept the defaults for the various prompts.

mysql_secure_installation

Nginx

By default, Ubuntu will install a version of Nginx that’s significantly older than the current stable release.

sudo apt-get -y install nginx

If you want the newest version of Nginx to take advantage of newer features and fixes, you can add the repository for the latest stable release similar to MariaDB.

sudo add-apt-repository ppa:nginx/stable
sudo apt-get update
sudo apt-get -y install nginx

Check to see if Nginx was installed successfully by visiting your server’s hostname or IP address in your browser. You should see a welcome page which can be disabled by removing it’s link in /etc/nginx/sites-enabled.

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

Nginx Configuration

Nginx must be configured to deliver the appropriate files and to eventually communicate with uWSGI to serve your application. Create a site configuration file named after your application in /etc/nginx/sites-available.

sudo nano /etc/nginx/sites-available/flaskapp

The entire block below can be pasted into the configuration. It tells Nginx to listen on port 80 using your machine’s hostname and defines the site’s content.

The first location directive has Nginx serve all requests matching /static from a directory containing your static files such as CSS, images, or JavaScript. The second takes each request and checks to see if the file exists using try_files. If the file exists, it’s served, otherwise the request is sent to our Python application.

server {
    listen 80;
    server_name $hostname;

    location /static {
        alias /srv/www/flaskapp/app/static;
    }

    location / { try_files $uri @flaskapp; }
    location @flaskapp {
        include uwsgi_params;
        uwsgi_pass unix:/tmp/flaskapp.sock;
        }
    }

Create the corresponding directories for your site. We’re placing our site in /srv/www/ here, but /var/www/ is currently more common on Ubuntu. It doesn’t matter which you use, as long as you’re consistent in your configuration.

sudo mkdir -p /srv/www/flaskapp/app/static
sudo mkdir -p /srv/www/flaskapp/app/templates

Now enable the site by creating a symbolic link between the configuration file in /etc/nginx/sites-available and sites-enabled.

sudo ln -s /etc/nginx/sites-available/flaskapp /etc/nginx/sites-enabled/flaskapp

uWSGI

uWSGI is the application server that we’re using for our sample Python web app. Since we have pip, we can use it to install uWSGI.

pip install uwsgi

uWSGI Configuration

Create the directories for uWSGI’s configuration and log files.

mkdir /etc/uwsgi
mkdir /var/log/uwsgi

While we only want to deploy one application right now, we’re still going to use uWSGI’s Emperor mode. It will monitor the uWSGI configuration directory for changes and will start, stop, and reload instances as necessary.

We’ll start the Emperor via Upstart so create a configuration file.

sudo nano /etc/init/uwsgi-emperor.conf

In this file, we’re only defining some very basic parameters in order to provide more flexibility later on.

description "uWSGI Emperor"
start on runlevel [2345]
stop on runlevel [06]
exec uwsgi --die-on-term --emperor /etc/uwsgi --logto /var/log/uwsgi/uwsgi.log

Now a uWSGI configuration for the application we’re deploying should be placed in the directory referenced above.

sudo nano /etc/uwsgi/flaskapp.ini

This file is where we’re be adding most of our parameters.

[uwsgi]
chdir = /srv/www/flaskapp
logto = /var/log/uwsgi/flaskapp.log
virtualenv = /srv/www/flaskapp/venv
socket = /tmp/flaskapp.sock
uid = www-data
gid = www-data
master = true
wsgi-file = wsgi.py
callable = app
vacuum = true

Create a simple application for uWSGI to run.

sudo nano /srv/www/flaskapp/wsgi.py

Paste the simple Flask application below so uWSGI has something to run.

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return "Success!"

Wrapping Up

You may have noticed that a virtual environment was defined in our uWSGI configuration. Create the virtual environment by installing virtualenv with pip and then install Flask within the new virtual environment.

sudo pip install virtualenv
cd /srv/www/flaskapp
virtualenv venv
source venv/bin/activate
pip install flask

Since all of our commands have been issued using sudo, you’ll want to fix file and directory permissions so www-data can access them..

sudo chgrp -R www-data /srv/www/*
sudo chmod -R g+rw /srv/www/*
sudo sh -c 'find /srv/www/* -type d -print0 | sudo xargs -0 chmod g+s'

Finally, start uWSGI and reload Nginx to use the new configuration.

start uwsgi-emperor
service nginx restart

Now when you visit your servers hostname or IP address in your browser, you should be see Success! If you do, you’ve successfully deployed a LEMP stack.