![](http://1.bp.blogspot.com/-9-QfjjRJs_0/WCyGFGFPnOI/AAAAAAAAMKQ/-B9q3QDlYl44xcPhTolOAXSXsXoM8kkqQCLcB/s1600/Falcon-web-framework.png)
In this guide, we'll walk you through the steps to build and deploy a Falcon web application using Gunicorn and Nginx on Ubuntu 16.04.
Falcon is a WSGI framework, so we'll install and use Gunicorn, a WSGI application server, to serve the app. Then we'll create a production-ready environment using Nginx as a reverse proxy server to process incoming requests before they reach Gunicorn.
Prerequisites
To deploy a falcon web application by following the steps mentioned in this guide, you will need:- Ubuntu 16.04 (physical or virtual) machine
Creating the Python Virtual Environment
Before we dive in to writing code or setting up services, we will create a Python virtual environment for our application on the server.Connect to your server as your non-root user:
- ssh sammy@your_server_ip
Falcon works with both Python 2.x and Python 3.x but we are going to use the latest version of Python available in Ubuntu 16.04 which is Python 3.5.We'll use pip and virtualenv to set up our Falcon application.
First, install virtualenv:
- sudo apt-get install virtualenv
Next, create a directory that will hold your application's source code and the virtual environment, and then change to that directory:
- mkdir falcon_app
- cd falcon_app
Then create the virtual environment:
- virtualenv venv -p /usr/bin/python3
This command creates a virtual environment inside the directory venv
. The -p
flag specifies which version of Python is used in the virtual environment.You'll see this output:
Output
Already using interpreter /usr/bin/python3
Using base prefix '/usr'
New python executable in /home/sammy/falcon_app/venv/bin/python3
Also creating executable in /home/sammy/falcon_app/venv/bin/python
Installing setuptools, pkg_resources, pip, wheel...done.
Now activate the virtual environment:
- . venv/bin/activate
To switch back to the system-wide Python interpreter, deactivate the virtual environment by issuing the command:
- deactivate
Now that you have set up your Python virtual environment, let's install the required Python packages.Installing Falcon and Gunicorn with pip
We need to install thefalcon
package, and since we are using Gunicorn to serve our app, we need to install that too. Both of these are available through pip
, You can install Falcon one of two ways. Falcon has a binary you can install with
pip install falcon
, but Falcon can get an extra speed boost when compiled with Cython. Issue the following commands to install Cython and then inform Falcon to detect it and compile itself using the system's C compiler:
- sudo apt-get install build-essential python3-dev
- pip install cython
- pip install --no-binary :all: falcon
Next, install Gunicorn:
- pip install gunicorn
Let's move on to writing our simple Falcon application.Writing a Simple Web Application Using Falcon
Let's create a simple single-file Falcon application. Create the filemain.py
in the falcon_app
directory:
- nano main.py
Populate the file with the following content, which creates a Falcon application that displays a simple test message when people visit the /test
route:main.py
import falcon
classTestResource(object):
defon_get(self, req, res):
"""Handles all GET requests."""
res.status = falcon.HTTP_200 # This is the default status
res.body = ('This is me, Falcon, serving a resource!')
# Create the Falcon application object
app = falcon.API()
# Instantiate the TestResource class
test_resource = TestResource()
# Add a route to serve the resource
app.add_route('/test', test_resource)
In this file, we create a class called
TestResource
. This class contains an on_get
method that defines the response we want to send. Then we create instances of the Falcon API and TestResource
. Then we add the route /test
to the API and attach the resource object test_resource
to it.Whenever a
GET
request is sent to the /test
URL, the on_get()
method of TestResource
is invoked.The response status and body are set using the variables
res.status
and res.body
respectively.Save the file and close your editor. Let's test the application.
Serving a Falcon Application with Gunicorn
Before we go through the work of making our application production-ready by using Nginx, let's make sure our application works by serving it with Gunicorn.Make sure you are in the
falcon_app
directory. Start Gunicorn with the following command:
- gunicorn -b 0.0.0.0:5000 main:app --reload
This starts Gunicorn and serves our web application at 0.0.0.0
on port 5000
, as you can see from its output:
Output
[2016-11-14 16:33:41 +0000] [9428] [INFO] Starting gunicorn 19.6.0
[2016-11-14 16:33:41 +0000] [9428] [INFO] Listening at: http://0.0.0.0:5000 (9428)
[2016-11-14 16:33:41 +0000] [9428] [INFO] Using worker: sync
[2016-11-14 16:33:41 +0000] [9431] [INFO] Booting worker with pid: 9431
You can use any port number you like, but make sure that it is above
1024
and it's not used by any other program.The
main:app
option tells Gunicorn to invoke the application object app
available in the file main.py
.Gunicorn provides an optional
--reload
switch that tells Gunicorn to detect any code changes on the fly.This way you can change your code without having to restart Gunicorn.
Test your application by opening your web browser on your local computer, and visiting
http://your_server_ip:5000/test
in your browser. You'll see the following output from your web application:![](http://1.bp.blogspot.com/-mkagpK1s9Os/WCyDi6-XicI/AAAAAAAAMKA/grHS_-aqedUpACeXwaSFSKjGvuVPrAYegCLcB/s1600/falcon-web-application-1.png)
Stop Gunicorn by pressing
CTRL+C
. Let's set this up in a more production-ready way.Using Nginx to Proxy Requests to Gunicorn
We'll set up and configure Nginx to proxy all the web requests to Gunicorn instead of letting Gunicorn serve requests from the outside world directly. By doing so, all the requests of your web application are first encountered by Nginx and then routed to the application server.First, install Nginx by executing the following command:
- sudo apt-get install nginx
Next, create a new configuration file called falcon_app.conf
in the /etc/nginx/sites-available
directory. This file will configure Nginx to proxy all requests coming to your server's IP address to the Gunicorn server of our Falcon application.
- sudo nano /etc/nginx/sites-available/falcon_app.conf
Add the following contents to the file:/etc/nginx/sites-available/falcon_app.conf
server {
listen80;
server_nameyour_server_ip_or_domain;
location / {
include proxy_params;
proxy_passhttp://localhost:5000;
}
}
This configuration tells Nginx to listen on port 80
and proxy all the HTTP requests to http://localhost:5000
, which is where Gunicorn will be listening.Activate this configuration by creating a symbolic link to this file in the
/etc/nginx/sites-enabled
directory:
sudo ln -s /etc/nginx/sites-available/falcon_app.conf /etc/nginx/sites-enabled/falcon_app.conf
Then disable the default Nginx configuration file by removing its symlink from the
/etc/nginx/sites-enabled
directory:
- sudo rm /etc/nginx/sites-enabled/default
Make sure that there are no syntax errors in any of your Nginx files:
- sudo nginx -t
You'll see this message if you have a working configuration:
Output
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
If you see any errors, fix them and test again.
Restart Nginx for the new configuration to take effect.
- sudo systemctl restart nginx
Now start Gunicorn again, but change the listening address from 0.0.0.0
to localhost
to prevent public access to Gunicorn:
- gunicorn -b localhost:5000 main:app --reload
Allow access to port 80
through the server's firewall if you've enabled it:
- sudo ufw allow 80
Note: If you are using https
to serve your web application, make sure to allow port 443
using ufw
.Finally, test out the app by visiting
http://your_server_ip/test
and you'll see the same output you saw before.Notice you no longer need the port number in the URL because your requests are going through Nginx now, which runs on port
80
, the default HTTP port. You'll see the following output in your browser:![](http://4.bp.blogspot.com/-DtKej_5Fg8k/WCyEJ25xeNI/AAAAAAAAMKE/z-JW48pkN6E5b5T87Out-kpgYeZ8BFCcQCLcB/s1600/falcon-web-application-2.png)
Stop the app server by pressing
CTRL+C
. Let's configure our Falcon application to start automatically in the background like our other services.Managing Gunicorn with Systemd
We should make sure that our application starts automatically every time our server boots, just like Nginx. If our server was accidentally restarted or had to be rebooted for any reason, we shouldn't have to start Gunicorn manually.
To configure this, we'll create a Systemd unit file for our Gunicorn application so we can manage it.
To start, we create a file for our application inside the
/etc/systemd/system
directory with a .service
extension:
- sudo nano /etc/systemd/system/falcon_app.service
A unit file is made up of sections. The [Unit]
section is used to specify the metadata and dependencies of our service, including a description of our service and when to start our service.Add this configuration to the file:
/etc/systemd/system/falcon_app.service
[Unit]
Description=Gunicorn instance to serve the falcon application
After=network.target
We specify that the service should start after the networking target has been reached. In other words, we only start this service after the networking services are ready.
After the
[Unit]
section, we define the [Service]
section where we specify how to start the service. Add this to the configuration file:/etc/systemd/system/falcon_app.service
[Service]
User=sammy
Group=www-data
PIDFile=/tmp/gunicorn.pid
Environment="PATH=/home/sammy/falcon_app/venv/bin"
WorkingDirectory=/home/sammy/falcon_app
ExecStart=/home/sammy/falcon_app/venv/bin/gunicorn --workers 3 -b localhost:5000 main:app
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
We first define the user and group that the service runs under. Then we define a file to store the PID (process ID) of the service; this PID is used to stop or reload the service.
Also, we specify the Python virtual environment, the application's working directory. and the command to execute to start the application. We assign the command to start Gunicorn to the
ExecStart
variable. The --workers
flag is used to define the number of workers that Gunicorn should start with. The Gunicorn docs suggest you set the number of workers to 2n+1
where n
is the number of CPU cores. Assuming that your server has a single CPU core, we arrive at the number 3
.The
ExecReload
and ExecStop
variables define how the service should be started and stopped. Finally, we add the
[Install]
section, which looks like this:/etc/systemd/system/falcon_app.service
[Install]
WantedBy=multi-user.target
The
Install
section allows you to enable and disable the service. The WantedBy
directive creates a directory called multi-user.target
inside /etc/systemd/system
and a symbolic link of this file will be created there. Disabling this service will remove this file from the directory.Save the file, close the editor, and start the new service:
- sudo systemctl start falcon_app
Then enable this service so that every time the server starts, Gunicorn starts serving the web application:
- sudo systemctl enable falcon_app
Once again, point your browser at http://your_server_ip/test
to see your application. Both Nginx and Gunicorn are running in the background. If you need to update your Falcon application, restart the falcon_app
service:
- sudo systemctl restart falcon_app
Conclusion
In this guide, we configured and deployed your first Falcon web application. We set up the Python environment and wrote your application code on the server, then served the web application with Gunicorn. Then we configured Nginx so that it passes web requests to our Gunicorn application. Finally, we wrote a Systemd Unit file and enabled the service so that web application starts when the server starts.