Flask App Hosting Continued

Next we want to copy over our local flask app to the server. You could do this with scp but I prefer to create a deploy folder and bare git repo on the server so I can simply 'git push production master' to deploy to production.

Ensure your pre-commit local git hook is configured:

touch ~/yourproject/.git/hooks/pre-commit
chmod +x ~/yourproject/.git/hooks/pre-commit
vi ~/yourproject/.git/hooks/pre-commit
set -eu


# Activate virtual env
source "$TARGET"/venv/bin/activate

# Update requirements.txt
pip freeze > "$TARGET"/requirements.txt

# Migrate DB
export FLASK_APP=run.py
flask db migrate
flask db upgrade

# Add changes to commit
git add -A

SSH into your server:

ssh <usermame>@<server-ip>

Create deploy folder:

mkdir ~/deploy-folder

Init a python virtual environment and install wheel via pip:

sudo apt-get install python3-venv
cd ~/yourproject
python3 -m venv venv
source venv/bin/activate
pip install wheel

Add a bare git repo for our hooks:

git init --bare ~/yourproject.git

Add a post-receive file and make it executable:

touch ~/yourproject.git/hooks/postreceive
chmod +x ~/yourproject.git/hooks/post-receive

This post-receive file should contain:

set -eu


while read oldrev newrev ref
        # only checking out the master (or whatever branch you would like to deploy)
        if [[ $ref = refs/heads/"$BRANCH" ]];
                echo "Ref $ref received. Deploying ${BRANCH} branch to production..."
                git --work-tree="$TARGET" --git-dir="$GIT_DIR" checkout -f
                source $TARGET/venv/bin/activate
                pip install -r $TARGET/requirements.txt
                export FLASK_APP=run.py
                cd $TARGET
                flask db upgrade
                sudo supervisorctl restart $PROJECT_NAME
                echo "Ref $ref received. Doing nothing: only the ${BRANCH} branch may be deployed on this server."

Now we have the server set to receive the branch, we can add the remote on our local machine:

cd ~/path/to/working-copy/
git remote add production yourusername@yourserverip.com:yourproject.git

Copy your local sqlite.db file from local to the server, because for obvious reasons this is not tied to version control.

scp ~/yourproject/dbname.db yourusername@yourserverip:~/yourproject

Copy your local /etc/projectname-config.json to the server's /etc/

On your local:

sudo cp /etc/yourproject-config.json ~/
scp ~/yourproject-config.json yourusername@yourserverip:~/

On the server:

sudo cp ~/yourproject-config.json /etc/

Make some changes back on local and push them via:

git push production master

Your project will now be found in the server's home directory.

On the server open up port 5000:

sudo ufw allow 5000

Serve your flask app:

cd ~/yourproject
source venv/bin/activate
export FLASK_APP=run.py
flask run --host=

Your app should now be running at the URL:


Confirm that your site functions properly then kill it.

Now we can setup nginx and gunicorn to serve our app:

sudo apt install nginx
cd ~/youproject
source venv/bin/activate
pip install gunicorn
sudo rm /etc/nginx/sites-enabled/default
sudo vi /etc/nginx/sites-enabled/yourproject
server {
        listen 80;
        server_name yourserverip;

        location /static {
                alias /home/yourusername/yourproject/yourproject/static;

        location / {
                proxy_pass http://localhost:8000;
                include /etc/nginx/proxy_params;
                proxy_redirect off;

Allow http traffic and close 5000:

sudo ufw allow http/tcp
sudo ufw delete allow 5000
sudo ufw enable
sudo ufw status verbose

Restart nginx:

sudo systemctl restart nginx

Start gunicorn service:

cd ~/yourproject
source venv/bin/activate
gunicorn -w 3 run:app

Your app should now be served at http://yourserverip

Got your flask app up and running? Now we can install supervisor to handle gunicorn:

sudo apt install supervisor
sudo vi /etc/supervisor/conf.d/yourproject.conf
command=/home/youruser/yourproject/venv/bin/gunicorn -w 3 run:app

Create the log files:

sudo mkdir -p /var/log/yourproject
sudo touch /var/log/yourproject/yourproject.err.log
sudo touch /var/log/yourproject/yourproject.out.log

Restart supervisor:

sudo supervisorctl reload

Now your server will be running even if you close your SSH connection and will reboot if the server restarts, great!

We will stop here... Next time I'll show you how to configure your namecheap domain for your site!