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
#!/bin/sh
set -eu
PROJECT_NAME="yourprojectname"
TARGET="$HOME/path/to/your/$PROJECT_NAME"
# 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:
#!/bin/bash
set -eu
PROJECT_NAME="yourproject"
TARGET="$HOME/$PROJECT_NAME"
GIT_DIR="$HOME/$PROJECT_NAME.git"
BRANCH="master"
while read oldrev newrev ref
do
# only checking out the master (or whatever branch you would like to deploy)
if [[ $ref = refs/heads/"$BRANCH" ]];
then
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
else
echo "Ref $ref received. Doing nothing: only the ${BRANCH} branch may be deployed on this server."
fi
done
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=0.0.0.0
Your app should now be running at the URL:
http://yourserverip:5000
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
[program:yourproject]
directory=/home/youruser/yourproject
command=/home/youruser/yourproject/venv/bin/gunicorn -w 3 run:app
user=youruser
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
stderr_logfile=/var/log/yourproject/yourproject.err.log
stdout_logfile=/var/log/yourproject/yourproject.out.log
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!