Deployment of a Flask application to DigitalOcean (part 2)

Jose Salvatierra
School of Code
Published in
6 min readMar 22, 2016

Now that we’ve got the server ready, we can start deploying the application. The application we are working with in this post is: https://github.com/schoolofcode-me/price-of-chair.

There are a couple of things we need to get installed in the server:

  • nginx
  • MongoDB
  • uWSGI
  • Python3.5

First, log in to your droplet using either the terminal (if using Linux or Mac), or PuTTY (if using Windows).

Installing Python3.5

Run the following commands to install some of Python’s dependencies:

$ sudo yum -y groupinstall “Development tools”$ sudo yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel$ sudo yum -y install wget

Then, run the following commands to install Python3.5:

$ wget http://python.org/ftp/python/3.5.1/Python-3.5.1.tar.xz$ tar xf Python-3.5.1.tar.xz$ cd Python-3.5.1$ sudo ./configure — prefix=/usr/local — enable-shared LDFLAGS=”-Wl,-rpath /usr/local/lib”$ sudo make && sudo make altinstall$ cd ..$ export PATH=”/usr/local/bin:$PATH”

Now lets install some Python tools that will allow us to install other packages and libraries easily:

# First get the setup script for Setuptools$ wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py# We are going to need necessary permissions in the local account to change stuff around$ sudo chmod 777 -R /usr/local/bin$ sudo chmod 777 -R /usr/local/lib# Then install it for Python 3.5:$ python3.5 ez_setup.py# Now install pip using the newly installed setuptools:$ easy_install-3.5 pip# Then install virtualenv, since we will need them for the dashboard$ pip3.5 install virtualenv

Installing nginx

Run the following commands to install nginx in your system, and to make sure it re-starts if you restart the server:

$ sudo yum -y install epel-release$ sudo yum -y install nginx$ sudo chkconfig --levels 235 nginx on

Now, modify the nginx config file by executing the following command:

sudo vi /etc/nginx/conf.d/default.conf

Delete everything by pressing `d` followed by `SHIFT+G`, and then press `i` and paste the following content:

server {  listen 80;  real_ip_header X-Forwarded-For;  set_real_ip_from 127.0.0.1;  server_name localhost;  #charset koi8-r;  #access_log logs/host.access.log main;  # Load configuration files for the default server block.  include /etc/nginx/default.d/*.conf;  location / {    include uwsgi_params;    uwsgi_pass unix:/var/www/html/pricing-service/socket.sock;    include uwsgi_params;    uwsgi_modifier1 30;  }  error_page 404 /404.html;  location = /404.html {    root /usr/share/nginx/html;  }  # redirect server error pages to the static page /50x.html  error_page 500 502 503 504 /50x.html;  location = /50x.html {  root /usr/share/nginx/html;  }}

Next, let’s modify another configuration file by executing the following command:

sudo vi /etc/nginx/nginx.conf

Find the line that says `worker_processes 1;`, and change it so it says `worker_processes 8;`.

Then we must add the `nginx` user to the `jose` group. Remember the group will be called the same as the user you created for your server in Part 1.

sudo usermod -a -G jose nginx

Then we must create the necessary directories. This is where we’ll put our application for nginx and uwsgi to be able to run it.

$ sudo mkdir /var/www && sudo mkdir /var/www/html && sudo mkdir /var/www/html/pricing-service$ sudo chown jose:jose /var/www/html/pricing-service/

Installing the application

Navigate to the `/var/www/html/pricing-service` folder and clone the git repository. Remember that in order to be able to clone the repository, you will have to create a fork of it, and clone the fork. Do not clone the repository as shown on this document, because it will not work.

$ cd /var/www/html/pricing-service/$ git clone git@github.com:schoolofcode-me/price-of-chair.git .

At this point, you may get an error. If you do, you need to create an SSH key for this server and add it to your GitHub profile.

Generating an SSH key

Run the command:

ssh-keygen

And press `Enter` whenever prompted to enter anything. You can enter a passphrase if you want. This will be required whenever you use the SSH key (e.g. pushing or pulling from GitHub).

Not, copy the contents of your newly-created SSH key:

cat ~/.ssh/id_rsa.pub

Copy the output of that command, and let’s go to GitHub

Adding the SSH key in GitHub

Log in to GitHub, and go to your profile.

Press the “Edit Profile” button, and then go to the section on SSH keys.

Add your new key. You will need to choose a title, but it is not important. The content must exactly reflect what you copied from the last command executed on the server.

Now, you can attempt to clone the repository again.

Creating the log directory

uWSGI will need a directory in which to write what happens while the system is running. We must create this directory:

mkdir /var/www/html/pricing-service/log

Creating the virtual environment

uWSGI will try to run from a virtual environment which would be located at `/var/www/html/pricing-service/venv`. Lets create that now:

$ cd /var/www/html/pricing-service$ virtualenv — python=python3.5 venv$ ./venv/bin/pip install -r requirements.txt$ ./venv/bin/pip install uwsgi

The commands above will create the virtual environment, install the requirements.txt as per the application, and then install `uwsgi` as well. This is a Python package that is required to run the uWSGI server.

Adding the config properties

Next, we need to create the configuration file that is required for the project. If you are not using the application linked at the top of the post, then you may not have to do this:

$ vi src/config.py

Place the following content in it:

DEBUG = FalseADMINS = frozenset([“yourname@yourdomain.com”])

Then, add your MailGun API details in the `src/models/alerts/constants.py` file:

$ vi src/models/alerts/constants.py

And make sure that the `URL`, `API_KEY`, and `FROM` properties are set to your MailGun properties.

Installing MongoDB

Execute the following command to create the MongoDB repository file. This is necessary so that the package manager `yum` knows where to download MongoDB from:

$ sudo vi /etc/yum.repos.d/mongodb-org-3.2.repo

And put the following content in it:

[mongodb-org-3.2]name=MongoDB Repositorybaseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.2/x86_64/gpgcheck=0enabled=1

Install MongoDB using `yum`:

$ sudo yum install -y mongodb-org

Make sure MongoDB restarts whenever you restart the server:

$ sudo chkconfig mongod on

Start MongoDB:

$ sudo service mongod start

Setting up uWSGI

uWSGI is a server that wraps around the Flask application and can serve the application to nginx. nginx can then give the content to the users.

Create the uWSGI configuration file:

$ sudo vi /etc/init/uwsgi_pricing_service.conf

And put the following content in it:

description “uWSGI_pricing_service”start on runlevel [2345]stop on runlevel [06]respawnenv UWSGI_ALIVE=/var/www/html/pricing-service/venv/bin/uwsgienv LOGTO_ALIVE=/var/www/html/pricing-service/log/emperor.logexec $UWSGI_ALIVE --master --emperor /var/www/html/pricing-service/uwsgi.ini --die-on-term --uid jose --gid jose --logto $LOGTO_ALIVE

Remember to change `--uid jose` and `--gid jose` to be your user name and group name (they both tend to be equal to your user name).

At any point, you can start the uWSGI service by running `sudo start uwsgi_pricing_service` and stop it with `sudo stop uwsgi_pricing_service `.

In the `/var/www/html/pricing-service/` folder, create a file `uwsgi.ini`:

$ cd /var/www/html/pricing-service/$ vi uwsgi.ini

And put the following content in it:

[uwsgi]#application’s base folderbase = /var/www/html/pricing-service#python module to importapp = src.appmodule = %(app)home = %(base)/venvpythonpath = %(base)#socket file’s locationsocket = /var/www/html/pricing-service/socket.sock#permissions for the socket filechmod-socket = 777#add more processesprocesses = 8#add more threadsthreads = 8#kill worker if timeout > 15 secondsharakiri = 15#the variable that holds a flask application inside the module imported at line #6callable = app#location of log fileslogto = /var/www/html/pricing-service/log/%n.log

SELinux

SELinux is a security tool running in many Linux distributions, including CentOS. When SELinux is running, nginx may not be able to serve your application.

There is a way around this, but for now we can simply disable SELinux:

$ sudo setenforce 0

Running the application

To run the application, we just have to execute the following:

sudo service nginx start

SELinux (again)

Once the application has been ran, visit the IP address of your server, and you should see it running. Hooray!

Now, we can re-enable SELinux and add nginx as an exception. We can only do this after visiting the site, as we need some data to add to the ‘exclusion log’.

Execute the following commands to add nginx to the exclusion log:

$ sudo yum install -y policycoreutils-{python,devel}$ sudo grep nginx /var/log/audit/audit.log | audit2allow -M nginx$ sudo semodule -i nginx.pp

Then, we can re-enable SELinux, now that nginx is allowed:

$ sudo setenforce 1

That’s it! The application should now just work!

--

--