Barebone Flask Website

Learn how to set up and deploy a barebone website in Flask

In this post we’ll set up a Flask website serving as a starting point for building a simple website. If you know some Python, you will be able to go through the steps below to successfully set up the website on your own. Note: I’m using Python 3.6.3.

The full source code can be found on Github:

https://github.com/visini/barebone-flask-website

What we’ll use:

  • Flask, a popular Python micro framework for the web
  • Flask’s automatically configured Jinja2-templating engine
  • AWS Elastic Beanstalk to host our website to keep scaling in mind (alternatively, you’ll be free to use a single instance on AWS EC2)
  • Let’s Encrypt for SSL encryption
  • Gunicorn (WSGI server)
  • TODO: Flask-login integration

The end result is a fully working website serving as a starting point for your Flask-powered website project.


Step 1: Set up project folder and install Flask

In this step we will install all requirements on our local machine. I’m using macOS 10.14, so the commands that follow might not correspond exactly to your environment. Run the following in Terminal:

# create and go to project folder
cd ~/PycharmProjects/ # cd into your main project folder
mkdir barebone-flask-website
cd barebone-flask-website
# create virtual environment and activate it
python3 -m venv my_virtual_environment
source my_virtual_environment/bin/activate
# within virtual environment, install the following:
pip3 install flask flask-login
pip3 freeze > requirements.txt
deactivate
# set up file structure
touch app.py wsgi.py

Important: Be sure while debugging, when serving the website or when you install additional dependencies below using pip3, change to the virtual environment with the following commands:

source my_virtual_environment/bin/activate # activate virtual env
# your commands here
pip3 freeze > requirements.txt # after you're done, this will ensure that requirements.txt is up to date
deactivate # this will exit the virtual environment

Open the project folder in PyCharm with the following command (or, use the text editor of your choice). You might need to create the command-line launcher in advance from PyCharm > Tools (see here).

charm .

To get started, add the following barebone code to app.py:

# app.py
from flask import Flask
application = Flask(__name__)
@application.route("/")
def hello():
return "Hello World!"
if __name__ == '__main__':
application.run(debug=True)

In wsgi.py paste the following to prepare the WSGI server (i.e. gunicorn):

from app import application
if __name__ == "__main__":
application.run()

You can test if everything is working properly in two ways:

Note: As I explained above, switch to your virtual environment beforehand if needed.

# First option: Run with python interpreter (only for debugging)
python3 app.py --debug
# * Running on http://127.0.0.1:5000/
# * Restarting with stat
# * Debugger is active!
# Second option: Run with gunicorn (used for production later)
gunicorn --bind 0.0.0.0:8080 wsgi:application -w 1
# Starting gunicorn 19.7.1
# Listening at: http://0.0.0.0:8080 (19694)
# Using worker: sync
# Booting worker with pid: 19697

In Terminal, you can press CTRL+C to exit the process accordingly.

Our website is now working with a minimal “Hello world!” placeholder and we are ready for Step 2.


Step 2: Templating

Now we will set up a basic directory structure for your project. Run the following in Terminal while in the root of your project:

mkdir templates static
touch templates/index.html templates/contact.html
charm .

Change the contents of app.py to the following, to accommodate the two subpages (index page and contact page):

# app.py
from flask import Flask, render_template
application = Flask(__name__)
@application.route("/")
def index():
return render_template('index.html', title='Index')
@application.route("/contact")
def contact():
return render_template('contact.html', title='Contact')
if __name__ == '__main__':
application.run(debug=True)

This structure will set up two views, called „index“ and „contact“, with the according templates, index.html and contact.html, respectively residing in the /templates subfolder.

You can use the below boilerplate HTML for these two template files, in order to get you started right away:

<!DOCTYPE html>
<html>
<head>
<title>{{title}}</title>
</head>
<body>
<h1>{{title}}</h1>
<p>This is the {{title}} page.</p>
</body>
</html>

Step 3: Prepare for deployment

In order to deploy our website to AWS Elastic Beanstalk, we first need to install the AWS Elastic Beanstalk command line interface, called awsebcli. After some trial and error when trying to install it with pip3, I managed to install it successfully using brew, which seems to handle the dependencies correctly. If you have it already installed on your machine, you can skip this step. Run this command in Terminal to install the CLI:

brew install awsebcli

You can check if the installation was successful when you can execute the following without any errors:

eb --version

Now, run the following command in your project folder to initialize the application and register it with AWS Elastic Beanstalk (be sure to change the region accordingly; below, eu-west-1 is selected):

eb init -p python-3.4 -r eu-west-1 barebone-flask-website

This will trigger several prompts which will help you to set up the application, most importantly:

  • You will need to enter your AWS credentials, namely aws-access-id and aws-secret-key, if not specified

The following command will create an environment (called testenv-barebone-flask-rest-website), provision the necessary instance (we’ll use a single instance setup without load balancer for now), and deploy your application:

eb create testenv-barebone-flask-website --single -i t2.nano
eb use testenv-barebone-flask-website

This will take a few minutes to complete. Note that at this point, the application will not work yet and throw an Internal Server Error. This is because the default WSGI-Path is application.py whereas in our project it is wsgi.py. Luckily, this issue can be fixed quite easily.

In order to tell AWS Elastic Beanstalk to set up the EC2 instances with the correct WSGI-Path (where our website is ultimately called from), we have to perform the following steps. Run this in Terminal:

eb config

Then, scroll down to this section and in the last line, change application.py to wsgi.py. This will ensure that the correct file from our project folder is referenced (in other words, wsgi.py is the entry point to our application).

[...]
aws:elasticbeanstalk:container:python:
NumProcesses: '1'
NumThreads: '15'
StaticFiles: /static/=static/
WSGIPath: wsgi.py # change this from application.py to wsgi.py
[...]

Exit using CTRL-C and confirm with Yes. This will subsequently deploy the new configuration to your instances (in our case, still a single instance).

After deployment of the new configuration (which takes another 2–3 minutes) you can type the following command to open the URL under which your website is served from to confirm that everything is working properly:

eb open

You can also retrieve the URL (along other useful information about your environment) like this:

eb status

Now, your website boilerplate is up and running on AWS Elastic Beanstalk. You can access it with the URL provided by the above command.

If you make changes to your app’s source code, you can re-deploy your app to Elastic Beanstalk via the following command:

eb deploy

Step 4: Configure SSL using Let’s Encrypt

The steps below will show you how to configure SSL for free, using Let’s Encrypt. First, you’ll need to create a hosted zone for your custom domain in Route 53. Then, you can attach a CNAME Alias in the hosted zone, pointing to your elastic beanstalk deployment. Please check out this AWS guide for more information.

Note: The next step will download a config file from gist.github.com. Be sure to check out the source code before pasting the command into your command line!

After you can access the custom domain, and are able to see the same output as when accessing it via the elasticbeanstalk subdomain, run the following commands in Terminal in the root of your project (be sure to replace the two environment variables with your email, as well as your domain name configured in Route 53 from the step above):

eb setenv LETSENCRYPT_EMAIL=your@email.com LETSENCRYPT_DOMAIN=your_custom_route53_domain_alias.com
mkdir .ebextensions
wget -q https://gist.githubusercontent.com/visini/70c5b11c136be16ea2fe12a6d7b9bf3b/raw/231d3dedf4256b9081e46421714d7f8477055def/elasticbeanstalk-letsencrypt-ssl.config -O .ebextensions/elasticbeanstalk-letsencrypt-ssl.config
eb deploy

The config script put in place in the step above will install a cronjob to make sure that your SSL certificates will automatically renew every week.

Now, your website is accessible on your custom domain via AWS Elastic Beanstalk, secured via SSL provided by Let’s Encrypt. You can check if everything is working properly, if the certificate of your website is valid and trusted, and if you can navigate to both the index page and to the contact page.

I hope you enjoyed this guide — please leave a comment if you have any questions or if you run into any issue.


Thanks for reading. If you enjoyed this article, feel free to hit the clap button 👏 to help others find it.

Say Hi on Twitter or check out what we’re building at 1Media AG.


Originally published on November 7, 2018.