Hosting a flask app on ubuntu with nginx and gunicorn
Hey, I know, it's very complicated, but I got it running.
In the following commands replace vim
with nano
if noob:).
Install nginx(your server's load balancer):
sudo apt install nginx
Install python,pip and virtual environment:
sudo apt update
sudo apt install python3 python3-pip python3-venv
If you don't have requirements.txt -> on your local dev machine run this with virtual env active in your app folder pip freeze > requirements.txt
.
Get your source code to the server with cloning:
git clone <repository>
or with scp(secure copy). Copy the folder from the local machine with:
scp /folder_to_move <server_user>@<IP_adress>:/where/to/copy/in/server
Go to your app folder, create an virtual environment and activate it:
cd /path/to/your/app && python3 -m venv venv && source venv/bin/activate
Install your dependencies and gunicorn(used to run our app):
pip install -r requirements.txt && pip install gunicorn
Add environment variables needed for your app into:
sudo vim /etc/<your_app_name>_config.json
e.g. in app_config.json:
{
"SECRET_KEY":"asdf",
}
Then load this file into your app like this:
with open("/etc/app_config.json") as config_file:
config = json.load(config_file)
secret_key = config.get("SECRET_KEY")
Next create a nginx config for your app:
sudo vim /etc/nginx/conf.d/<your_app_name>.conf
Add the following stuff in there (replace example with your domain/IP):
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Run nginx:
sudo systemctl restart nginx
Our nginx is now listening on port 5000 so we need to make our app run on that port next. Create a new service file which will take care of running your app:
sudo vim /etc/systemd/system/<your_app_name>.service
Add the following stuff in there(edit when asked):
[Unit]
Description=Something here about your app, doesn't matter
After=network.target
[Service]
User=<your_server_username>
Group=<your_server_username>
WorkingDirectory=/<path_to_your_app>
ExecStart=/<path_to_your_app>/venv/bin/gunicorn -b 0.0.0.0:5000 -w 3 --env <ENVIRONMENT_VARIABLE_NAME>="this_is_the_value_but_you_should_put_env_variables_here_that_are_needed_WHEN_you_RUN_the_app_and_others_should_go_to_json_file_in_/etc/-folder" <your_filename_where_flask_app_var_is_like_"app">:<your_flask_app_var_name_like_"app">
Restart=always
[Install]
WantedBy=multi-user.target
There we said to bind -b
our app to run on localhost(0.0.0.0 is same as 127.0.0.1) and use port 5000, also we said -w 3
which meant we want 3 workers to be running our app. Determine how many workers you need in your machine: #cores * 2 + 1.
Load the service file:
sudo systemctl daemon-reload
Make our service file run in the background:
sudo systemctl restart <your_app_name>.service
Now our app should be running! You can check the status by:
sudo systemctl status <your_app_name>.service
When further developing your app I recommend using github and cloning the repo like we did above, then follow these steps after making changes to github:
-> login to your server
pull the changes:
cd /path/to/app && git pull && cd
reload the service:
sudo systemctl restart <your_app_name>.service
There you go:)