DEV Community

Fernando
Fernando

Posted on • Updated on

Deploying masonite 2 project with Nginx and Gunicorn

Masonite is an incredible developer friendly framework to develop modern web applications with python. With a lot of out of the box functionality with an extremely extendable architecture. On my own experience, it helps you a lot to build your applications with a beautiful code.

It brings you a useful utility called craft command that make much easy and faster to create your models/controllers/authentication/middlewares classes and so on.

Craft command brings built in a web server designed to run on development environment your web application. While this makes development comfortable, this web server is not designed to deploy on production.

On this guide i will try to explain how to configure and deploy your Masonite app on a virtual private server such as AWS or DigitalOcean.

Requirements used for this guide

Installing your web app

To start, i will make a new Masonite project. I'm gonna skip the install step because is no the goal of this guide, but you can use this very well explained tutorial for installation process.

craft new demoapp
cd demoapp

# Create the virtual env with python3
python3 -m venv venv
source venv/bin/activate
craft install

This will make a new demoapp folder with the crafted application, then it will create the virtual env and activate it and to finish it will install the requirements described in the requirements.txt file.

In this last step (on my machine using Debian Sid) it prints some errors with Debian version of python wheels installed:

Failed building wheel for masonite
Failed building wheel for masonite-validation
Failed building wheel for masonite-dot
Failed building wheel for pyyaml

but craft command creates the application key and all is working without problems, but if it makes you noise, my suggested workaround is to install in the virtual env the wheels with pip:

# activate virtualenv if is deactivated
source venv/bin/activate
pip install wheel
craft install

Install nginx & gunicorn

In debian you can use apt, apt-get or aptitude to install packages. We will need to install nginx web server and configure it to make a proxy reverse to gunicorn.

# We need nginx and gunicorn3 for python3
sudo aptitude install nginx gunicorn3

Gunicorn is a Python WSGI HTTP Server for UNIX. Is recommended to use Gunicorn behind an HTTP proxy server (as Nginx in this case).

Masonite brings out of the box a wsgi.py file that you can use to execute our application:

gunicorn3 wsgi:application

Gunicorn defaults settings will allow to access to local machine only. If you want to access from other device you can use -b option.

Nginx and Gunicorn Configuration

After install nginx we will configure Gunicorn to run as a service on systemd, so this will allow us to control with systemctl command and run after system reboot.

This will be the /etc/nginx/sites-avalaible/default file, the path to the project is /home/admin/webapps/demoapp

server {
    server_name demoapp.io;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /public/ {
        root /home/admin/webapps/demoapp/storage;
    }
    location /static/ {
        root /home/admin/webapps/demoapp/storage;
    }
    location /uploads/ {
        root /home/admin/webapps/demoapp/storage;
    }
    location /compiled/ {
        root /home/admin/webapps/demoapp/storage;
    }

    access_log /var/log/nginx/access.log;

    location / {
        include proxy_params;
        proxy_set_header Host $host;
        proxy_pass http://unix:/run/gunicorn.socket;
    }
}

Now the Nginx config file is edited we need to check the syntax is ok:

sudo nginx -t

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

Create the Gunicorn service:
/etc/systemd/system/gunicorn.service

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
PIDFile=/run/gunicorn/pid
User=admin
Group=www-data
RuntimeDirectory=gunicorn
WorkingDirectory=/home/admin/webapps/demoapp
ExecStart=/usr/bin/gunicorn3 --pid /run/gunicorn/pid\
          --workers 3\
          --bind unix:/run/gunicorn.socket wsgi\
          --error-logfile /home/admin/logs/error.log\
          --access-logfile /home/admin/logs/access.log\
          --log-level debug\
          --timeout 320
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

This service file execute gunicorn3 command using the pid-file (on /run/gunicorn/pid) and make a connection thought a socket file located on /run/gunicorn.socket, it saves logs on /home/admin/logs/ directory so it will need permissions:

mkdir ~/logs/
sudo chown admin.www-data ~/logs/

Create /etc/systemd/system/gunicorn.socket file:

[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.socket

[Install]
WantedBy=sockets.target

Now almost everything is in place, we need to reload our services:

sudo systemctl daemon-reload

# start gunicorn
sudo systemctl start gunicorn

To check if gunicorn service is working:

sudo systemctl status gunicorn

# Output
● gunicorn.service - gunicorn daemon
   Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled)
   Active: active (running) since Wed 2019-07-29 21:05:07 UTC; 49s ago
 Main PID: 10154 (gunicorn)
   CGroup: /system.slice/gunicorn.service
           ├─10154 /home/admin/webapps/demoapp/venv/bin/python3 /home/admin/webapps/demoapp/venv/bin/gunicorn --workers 3 --bind unix:/run/gunicorn.socket wsgi:application
           ├─10157 /home/admin/webapps/demoapp/venv/bin/python3 /home/admin/webapps/demoapp/venv/bin/gunicorn --workers 3 --bind unix:/run/gunicorn.socket wsgi:application
           ├─10158 /home/admin/webapps/demoapp/venv/bin/python3 /home/admin/webapps/demoapp/venv/bin/gunicorn --workers 3 --bind unix:/run/gunicorn.socket wsgi:application
           └─10159 /home/admin/webapps/demoapp/venv/bin/python3 /home/admin/webapps/demoapp/venv/bin/gunicorn --workers 3 --bind unix:/run/gunicorn.socket wsgi:application

Dec 21 21:05:07 debian-512mb-nyc3-01 systemd[1]: Started gunicorn daemon.

Finally restart nginx to work with our deployed application

sudo systemctl restart nginx

And ta-dah!

Conclusions

If you like beautiful code, try Masonite.

Top comments (3)

Collapse
 
josephmancuso profile image
Joseph Mancuso

Awesome explanation!

Collapse
 
clsource profile image
Camilo

Thanks for this awesome guide!.

Collapse
 
poojitha1713 profile image
Poojitha D Naidu

hey, I want to build a web app using python, can you please help me on how to get started?