How to Serve Python Apps using uWSGI and Nginx on Centos-7

Want your very own server? Get our 1GB memory, Xeon V4, 25GB SSD VPS for £10.00 / month. Get a Cloud Server

The WSGI (Web Server Gateway Interface) is a specification for simple and universal interface between web servers and web applications or frameworks for the Python programming language. This was created in order to simplify and standardise communication between these components for consistency and interchangeability.

WSGI is not a server, a python module, a framework, an API or any kind of software. It is just an interface specification by which server and application communicate.

If an application is written to the WSGI spec, then it will run on any server written to that spec.

The uWSGI is a deployment option on servers like Nginx, Lighttpd, and Cherokee. The uWSGI provides an implementation of the WSGI specification and is both a protocol and an application server. The uWSGI server provides a non-FastCGI method for deploying Python applications with the nginx web server. In coordination with nginx, uWSGI offers great stability, flexibility, and performance.

In this tutorial, w'll learn how to set up a simple WSGI application served by uWSGI. We will use the Nginx web server as a reverse proxy to the application server to provide more robust connection handling. We will be installing and configuring these components on a CentOS 7 server.

Requirements

A server running Centos-7

A static IP Address for your server

A non-root user account with sudo privilege set up on your server.

Getting Started

Let's start by making sure that your Centos-7 server is fully up to date. You can update your server by running the following command:

sudo yum update -y

Installing required Components

Before starting, you will need to install the necessary components on your CentOS 7 server. First, you will need to install EPEL repository to access wider range of packages.

You can install it easily by running the following yum command:

sudo yum install epel-release

Next, you need to get the Nginx web server and reverse proxy, the pip Python package manager, and the Python development libraries and headers.

You can install all these components by running the following command:

sudo yum install python-pip python-devel nginx gcc

Once the installation is completed, you will have access to pip Python package manager. Next, you will need to install the virtualenv package to isolate your application's Python environment from any others that may exist on the system:

You can install it by running the following command:

sudo pip install virtualenv

Set up Virtual Environment

Next, you will need to create the general directory structure for your application. This will hold your virtual environment and your WSGI entry point.

sudo mkdir /opt/myproject

Next, change the directory to set up the environment for your application:

cd /opt/myproject

Now, create a virtual environment with the virtualenv command.

sudo virtualenv myprojectenv

You should see the following output:

New python executable in /opt/myproject/myprojectenv/bin/python Installing setuptools, pip, wheel...done.

After running the above command, a new Python environment will be set up under a directory called myprojectenv .

Now, activate this environment by running the following command:

source myprojectenv/bin/activate

The output will look something like this:

(myprojectenv) [root@centOS-7 myproject]#

You can deactivate this environment at any time by running the following command:

deactivate

When you install any Python package with this active environment that will be contained within this directory hierarchy. They will not interfere with the system's Python environment.

Next, you will need to install the uWSGI server into your environment. You can easily install it by using the pip command:

sudo pip install uwsgi

You can check the version of uwsgi by running the following command:

uwsgi --version

You should see the following output:

2.0.13.1

Now, the uWSGI server is available for use.

Create a WSGI App

Next, create a simple WSGI application using the WSGI specification requirements. To do so, create a wsgi.py file in your application directory:

sudo nano /opt/myproject/wsgi.py

Add the following code:

def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return ["<h1 style='color:blue'>Testing Success!</h1>"]

The above code constitutes a complete WSGI application. By default, uWSGI will look for a callable called application. As you can see, it takes two parameters.

The first is environ because it will be an environmental variable. The second is called start_response and is the name the app will use internally to refer to the uWSGI web server callable that is sent in.

Save and close the file when you are finished.

To test your application, you will need to start up uWSGI. To do so, run the following command:

uwsgi --socket 0.0.0.0:8080 --protocol=http -w wsgi

Now, open your favourite web browser and type the URL http://server-ip-address:8080, you should see the output in following image.

HP_NO_IMG/data/uploads/users/fd35bf73-10f3-43bf-b753-4edc26228307/737372865.png" alt="" />

You can stop the server with CTRL-C when you have verified that this works.

You can also deactivate your virtual environment by running the following command:

deactivate

Configure a uWSGI Config File

In the above section, we have manually started the uWSGI server. You can avoid this by creating a configuration file for uWSGI server.

To do so, create myproject.ini file inside /opt/myproject directory:

sudo nano /opt/myproject/myproject.ini

Add the following code:

[uwsgi] module = wsgi:application master = true processes = 5 uid = nginx socket = /run/uwsgi/myproject.sock chown-socket = nginx chmod-socket = 660 vacuum = true die-on-term = true

Save and close the file when you are finished.

Create Upstart Script to Manage the App

You will need to create a systemd unit file to launch a uWSGI instance at system boot, so that your application is always available. To do so, create the unit file uwsgi.service inside /etc/systemd/system directory:

sudo nano /etc/systemd/system/uwsgi.service

add the following code:

[Unit] Description=uWSGI instance to serve myproject [Service] ExecStartPre=-/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown nginx /run/uwsgi' ExecStart=/usr/bin/bash -c 'cd /opt/myproject; source myprojectenv/bin/activate; uwsgi --ini myproject.ini' [Install] WantedBy=multi-user.target

Save and close the file when you are finished.

Now, you can start the service by running:

sudo systemctl start uwsgi

To check the status of service, run:

sudo systemctl status uwsgi

You should see the following output:

● uwsgi.service - uWSGI instance to serve myproject Loaded: loaded (/etc/systemd/system/uwsgi.service; disabled; vendor preset: disabled) Active: active (running) since Thu 2016-05-19 21:28:02 IST; 4s ago Process: 3196 ExecStartPre=/bin/bash -c mkdir -p /run/uwsgi; chown nginx /run/uwsgi (code=exited, status=0/SUCCESS) Main PID: 3200 (bash) CGroup: /system.slice/uwsgi.service ├─3200 /bin/bash -c cd /opt/myproject; source myprojectenv/bin/activate; uwsgi --ini myproject.ini ├─3204 uwsgi --ini myproject.ini ├─3205 uwsgi --ini myproject.ini ├─3206 uwsgi --ini myproject.ini ├─3207 uwsgi --ini myproject.ini ├─3208 uwsgi --ini myproject.ini └─3209 uwsgi --ini myproject.ini May 19 21:28:02 centOS-7 bash[3200]: mapped 436560 bytes (426 KB) for 5 cores May 19 21:28:02 centOS-7 bash[3200]: *** Operational MODE: preforking *** May 19 21:28:02 centOS-7 bash[3200]: WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x223de60 pid: 3204 (default app) May 19 21:28:02 centOS-7 bash[3200]: *** uWSGI is running in multiple interpreter mode *** May 19 21:28:02 centOS-7 bash[3200]: spawned uWSGI master process (pid: 3204) May 19 21:28:02 centOS-7 bash[3200]: spawned uWSGI worker 1 (pid: 3205, cores: 1) May 19 21:28:02 centOS-7 bash[3200]: spawned uWSGI worker 2 (pid: 3206, cores: 1) May 19 21:28:02 centOS-7 bash[3200]: spawned uWSGI worker 3 (pid: 3207, cores: 1) May 19 21:28:02 centOS-7 bash[3200]: spawned uWSGI worker 4 (pid: 3208, cores: 1) May 19 21:28:02 centOS-7 bash[3200]: spawned uWSGI worker 5 (pid: 3209, cores: 1)

Now, enable the service to start during boot:

sudo systemctl enable uwsgi

Configure Nginx to Proxy to uWSGI

Next, you will need to configure Nginx as a reverse proxy. Nginx has the ability to proxy using the uwsgi protocol for communicating with uWSGI. This is a faster protocol than HTTP and will perform better.

To configure Nginx, you will need to modify the existing nginx.conf file and adding a new server block.

You can do this by editing nginx.conf file:

sudo nano /etc/nginx/nginx.conf

Before the default server block, add your own server block:

server { listen 80 default_server; server_name 192.168.0.42; root /usr/share/nginx/html; # Load configuration files for the default server block. include /etc/nginx/default.d/*.conf; location / { include uwsgi_params; uwsgi_pass unix:/run/uwsgi/myproject.sock; }

Save and close the file when you have finished.

You can test your Nginx configuration by running the following command:

sudo nginx -t

You should see the following output if everything is ok:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful

Now, start Nginx service and enable it to start during boot:

sudo systemctl start nginx

sudo systemctl enable nginx

Now, open your web browser and type the URL http://server-ip-address, you will see the application you configured:

HP_NO_IMG/data/uploads/users/fd35bf73-10f3-43bf-b753-4edc26228307/737372865.png" alt="" />