Fixing the bottleneck in understanding how to host a Flask-based website
Published on Thursday, 02. July 2020Last week I started to prototype a feedback tool for drafts of my blog posts. Usually, I write my posts in an offline editor. To share them, I copy them into a google document. This solution is less than ideal, so I decided to build a tool for this myself. Everything went well until the time came to host its first version.
I have rented a virtual server to host everything I need. Right now, this comes down to two WordPress instances and some services like Nextcloud. But I also want to use the server to host prototypes of tools I built. Yet every time I tried this, I ran into some unexplainable errors. Most of the projects I abandoned, because I wasn't able to solve the problem of hosting them. This week, I challenged myself to find a solution for this, and to dig deeper into what I didn't understand. My goal was to find a system to go from a prototype running locally to hosting it on the server in less than 15 minutes.
Here then, is a summary of what I have learned during this.
Choosing the webserver
The purpose of a webserver is to handle the incoming requests to the server and to forward them to the correct application (for example WordPress or Nextcloud). The two options available for this are Apache and Nginx. My server uses Apache. Since I wasn't able to get the backend running with it, my first step was to contemplate this choice.
Both options differ in their design. Nginx is a reverse proxy server. This means, that it only forwards the request to the application, which runs in another process. Apache, on the other hand, is a fully-fledged webserver. It executes the application itself and handles all incoming requests with an internal language processor.
This makes Apache much more versatile. Unfortunately, this versatility comes at a cost. To handle each request, Apache needs to create a new thread. This creates an overhead, especially for static files. Because Nginx doesn't interpret the requests, it's significantly faster for serving static content. For dynamic content, this difference disappears.
If I would set up the server from scratch, I probably would choose Nginx over Apache. But since I didn't want to migrate the WordPress instances I am already hosting, I decided to stick with Apache. What started the process of comparing Nginx and Apache though, was the fact, that I was unable to get Apache's python interpreter to work. I still didn't find out the reason for this. But reading about Nginx inspired me to use Apache as a reverse proxy.
Flask already comes with an HTTP server included, which should only be used in development and for testing purposes though. I decided to run the application with Gunicorn.
A few words about HTTPS
Until recently I was also a bit confused about the correct usage of HTTPS certificates. In short, to verify the identity of the server, you create a certificate that is based on the domain. Generally, a certificate is valid for only a single domain name. Certbot also lets you create certificates that are valid for multiple websites. If you want to add a new subdomain to your server, you have to create a new certificate.
Another possibility is to get a wildcard certificate. This certificate covers all subdomains. Unfortunately, the current version of Certbot is unable to install them, and you have to do it yourself. Since I didn't want to look into how this is done (even if it probably are a few simple commands), I stuck to the method above.
Conclusion
Fixing the problems to host the tool has been a worthwhile mix of desperation, relief, and a sense of accomplishment.
It once again proved that going down the rabbit hole to answer seemingly unrelated questions and things you don't understand is worth your time. The few things that always confused me about administrating a server are now cleared up forever.
But right now, I'm just glad I can finally host my prototypes.