Get up and running with Flask, Nginx, and Certbot

I’ve had to set up multiple servers, over the course of my work. I mostly deal with hosting private APIs, with manual authentication, rate limiting, and security. Since the services which would be using these APIs are very limited, and there isn’t gonna be a lot of load on the server, I tend not to focus too much on “scaling” it up. There is no point in spending time and resources in making something scalable when it won’t be scaled at all.

So, I have this blueprint that I follow for hosting my APIs, though it can be modified slightly to handle a variety of situations.

The first step would be to create an application. I’ve been using Flask to host all of my stuff because it’s really easy to set it up, run it and troubleshoot it. I don’t need all the fanciness which Django offers, nor do I need the speed enough to warrant the use of some other language.

If you’re reading this for learning, you can check out my GitHub repository for this Flask app

https://github.com/animesh-srivastava/random-words-api.git

It doesn’t do much, except it gives a list of random English words and random numbers. Go ahead and read the documentation on the repo. If you already have an API or something else which you want to host, well go ahead.

Now, you have your code. The next step would be getting a domain. A domain is not strictly necessary, but it’s helpful if you wanna launch this for a longer-term, and you need to hard-code this into your application. Once you’ve done that, you need a server. Personally, go with a Linux machine on any provider. Take a Virtual Private Server, preferably with root access. Now, what you’d want to do is set the route of your sub-domain to point to the IPv4 address of this Server.

Your machine is now recognized by the domain and the subdomain you have acquired. Now, you need to set up things on your server

SSH into your newly acquired server. If you’re using a Windows machine as your primary, you can use PuTTY shell for the same. But on newer versions of Windows 10, you can enable Windows Subsystem for Linux (WSL) and use that instead. Either way, you have Terminal to your server. Do the usual

ssh root@xxx.xxx.xxx.xxx

or if you want an easy way, you can use your URL for it now

ssh root@subdomain.domain.topleveldomain

After this, do your usual upgrade and update (this is for Ubuntu/Debian systems).

apt-get upgrade && apt-get update

Now, depending on your OS, you need to install the required version of Python, Pip, Flask, Gunicorn, and other dependencies you need.

apt-get install python3
apt-get install python3-pip
apt-get install python3-certbot-nginx
apt-get install nginx
alias python=python3
alias pip=pip3
pip install flask
pip install gunicorn

This should be enough. Let the installations happen. Now, you need to get your code on this machine. The simplest way is to route it through GitHub or GitLab or the likes.

On your own machine

cd ~/path/to/project
git init
git add .
git commit -m 'some commit message'
git branch -M main
git remote add origin <link to your empty GitHub repository>
git push origin main

Or if you don’t want to go through GitHub, you can simply rsync your code onto it

rsync -avzh --progress /path/to/your/code root@ip:/path/which/exists

Now on your server, you have to pull the code, if you’ve opted for Git method.

cd /path/to/where/you/want/your/source/code
git init
git remote add origin <link to your GitHub repository>
git pull origin main

And you have your code onboard.

Now, for a dry run, try running the code with Python

python main.py

If everything goes alright, you’d see something like

 * Serving Flask app "<app name>" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: on

Now, you have everything set up, except your Nginx. To configure that, follow the steps

cd /etc/nginx/sites-available
touch <your URL>
ln <your URL> ../sites-enabled/<your URL>
nano <your URL>

And in the text editor, type the following configurations

server {
listen 80;
listen [::]:80;
server_name <your URL>; # Without http or slashes
location / {
proxy_pass http://0.0.0.0:8000;
}
}

Now, this will configure your HTTP server.

Now restart the nginx service to let the changes take effect

sudo service nginx restart

If this gives no output, you have configured Nginx successfully.

Now, back to your project directory, you can go and run the following command. Now, since you need this to run permanently, you cannot use a normal SSH session. Because as soon as the SSH session disconnects, the machine would end the process. You can use tmux for this, as tmux sessions run irrespective of access to the machine, indefinitely.

tmux
gunicorn <filename>:<appname> -b "0.0.0.0:8000"

You can test this by going to your website’s URL in your browser, or if it’s an API, you can test it using Postman.

Now, you want to enable SSL for your machine. For this, you have already installed python3-certbot-nginx

certbot --nginx -d <your URL>

Now, it’s gonna ask you for some basic information — your email, and your consent to them contacting you regarding stuff. Agree or disagree, up to you. After that, it’s gonna ask you about what you’re gonna do regarding HTTP requests. You can either set Nginx to redirect them to HTTPS (the recommended way), or you can just let HTTP run along with HTTPS.

And now you have a running website.

Later on, once you figure all this out, you can learn how to make your flask app run in Docker, or as a Systemd service. But until then, you’re good to go.