Automate Your Flask Deployment to VPS Using Github Actions
Tags: python, docker, tutorial, beginners
Published: 2022-01-03 02:46:39

_(Cover Image by [Joshua Sortino](https://unsplash.com/@sortino?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/automation?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText))_

In the project [lnprice](https://lnprice.com/) that I have mentioned in [my previous article](https://dev.to/adyaksa_w/what-i-learn-from-trying-selenium-on-vps-5a56), the backend deployment is done manually like this:

 1. Push code to Github

 2. Pull code in VPS

 3. Redeploy application

After dozens of deployments, **I have enough**. I decide to learn how to automate this. For some context, I already have experience in using Github Actions to automate my deployment. The reason that I’m not doing it in this project is that I have never done it in a Flask environment. I just want to prioritize the application first before any automation. So in this article, I will describe the step that I have done to deploy my backend on the VPS automatically. All the code can be accessed in my [Github repository](https://github.com/adyaksaw/tutorial/tree/master/1-flask-deployment)

![](https://cdn-images-1.medium.com/max/2000/1*liDJRez82TNvbhaBJn0B1Q.png)

## **1. Setup Pipenv & Dependency**

To have an easier time automating deployment, we need to have a simple dependency management system. So we need to install Pipenv in our project to handle our dependency and then install our dependency. We can do it like this:

    pip install pipenv
    pipenv install flask
    pipenv shell

By running pipenv shell , we initiate a virtual environment in this project that has the Flask framework.

## 2. **Create Flask Application**

The next step is creating a simple Flask application. We can use the sample on the Flask homepage. But in my case, I changed it a bit to use a different port so we don’t accidentally use an already used port.
{% gist https://gist.github.com/adyaksaw/a4c2afc703ce8db3215171646ce990c8.js %}
Now run flask run and go to localhost:5001 , there should be a ‘Hello World’ on that page.

## 3. Create Docker File

In my opinion, the easiest and painless way to deploy our application is to use Docker. We can definitely not use it and still be able to automate our deployment. But because there is so much possible pain that could appear when not using Docker, so I would really suggest using it.

Now, before touching Docker, we need to talk about how to deploy Flask to production. Like Django, Flask needs a WSGI server to deploy the application. There are 2 common WSGI server: UWSGI and Gunicorn. I won’t go into detail what is the difference between them. This article will use Gunicorn as the WSGI server.
[**GitHub - tiangolo/meinheld-gunicorn-flask-docker: Docker image with Meinheld and Gunicorn for Flask…**](https://github.com/tiangolo/meinheld-gunicorn-flask-docker)

Now, someone already created a docker image for the [Gunicorn-Flask](https://github.com/tiangolo/meinheld-gunicorn-flask-docker) combination. But in the context of this tutorial, that image needs modification so we are better off creating it from scratch. Here is the created Dockerfile.
{% gist https://gist.github.com/adyaksaw/c4544f016b43c7a814dbd1fc0f000f65.js %}
Why do we use requirements.txt instead of using Pipfile directly? Here, I just want to treat Pipenv as some ‘dependency organizer’. I don’t want to use Pipenv as a virtual environment tool. You should be able to use the dependency from Pipfile directly and use Pipenv to access the dependency with some modification to the code.

After creating the Dockerfile, we can build and run the Dockerfile by running the following commands:

    docker build -t 1-flask-deployment .
    docker run -dp 5001:5001 1-flask-deployment

Try to run docker container ls , the 1-flask-deployment container should be up and running and can be accessed from localhost:5001 .

## 4. Setup Github Runner

Before creating the Github Actions file, we need to configure our own Github Runner. We need to place the Runner on the same server as the server where we want to place our production code. For this step, we can just follow the steps that are outlined in the official [Github Runner Documentation](https://github.com/adyaksaw/tutorial/settings/actions/runners/new?arch=x64&os=linux)

## 5. Create Github Actions

Time to pay off the hard part of creating the Dockerfile! Because we already know the step to run the container, now we just need to repeat that step in the Github Actions.
{% gist https://gist.github.com/adyaksaw/e75b8b30c4b8e5707190f33cf9afd9d7.js %}
In this code, I configured the Github Actions so it will run only when the code is pushed to master (Line 3–6) and running in my own Virtual Machine (Line 10).

After pushing the deploy.yml, try to call curl localhost:5001 from inside the VPS. The ‘Hello World’ text should appear like when we call it in our local system. This means that the Github Runner is working, and the deployment automation is working!

*Hello, I’m Adyaksa, and I write about software development and my language learning experience. I’m planning to release a weekly blog about something that I find interesting while working on my side projects. If you’re interested, you can follow me to keep updated about it!*

References:

* Pipenv Basic: [https://pipenv.pypa.io/en/latest/basics/](https://pipenv.pypa.io/en/latest/basics/)

* Flask Quick Start: [https://flask.palletsprojects.com/en/2.0.x/quickstart/](https://flask.palletsprojects.com/en/2.0.x/quickstart/)

* Pipenv docker: [https://pythonspeed.com/articles/pipenv-docker/](https://pythonspeed.com/articles/pipenv-docker/)

* Gunicorn Flask: [https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-gunicorn-and-nginx-on-ubuntu-18-04](https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-gunicorn-and-nginx-on-ubuntu-18-04)