Setting up Flask and Apache on AWS EC2 Instance

Quickstart to getting a website running on Amazon Web Services

I create websites on EC2 pretty frequently but every time I do, I inevitably take 30 minutes to an hour with just the setup process. Flask, on its own, tends to be pretty straightforward but there are several other important steps that are less straightforward. Even among the tutorials that I have found online, none of them have worked out of the box and in the rare cases that they do, they do not satisfy all of my requirements.

This quickstart guide will use Python3, virtualenv, and will allow you to keep your project directory anywhere on your instance (I prefer to keep my project in ~/project-name rather than in /var/www/html). This guide is meant to document the process so that I can get through the setup process faster in the future and hopefully, it will help someone else as well.

Launch an EC2 instance

In the EC2 console, select an Ubuntu Server (t2.micro for free tier) and launch. Select an existing key pair or create a new key pair and save it to your computer. I will save it askeypair.pem. As for the security group, add HTTP and HTTPS in the inbound rules section with the source set to Anywhere. Now, once the instance is running, we can connect to it.

Connect to the EC2 instance

Open a terminal session in the directory where you have saved the key pair. Set permissions on the file.
$ chmod 400 keypair.pem
Copy the EC2 Public DNS from the AWS EC2 Instance Description and save it to an environment variable. Something like:
$ export EC2_DNS="ec2-12-34-567-89.compute-1.amazonaws.com"
Connect to the EC2 instance.
$ ssh -i "keypair.pem" [email protected]$EC2_DNS

Troubleshooting Note: Sometimes, keypair.pem is saved as keypair.pem.txt. Either rename and remove the .txt extension or replace keypair.pem in the instructions with keypair.pem.txt.

Setup Python3 Environment

First, update apt-get.
$ sudo apt-get update
Python3 (3.5 at the time of writing) should be already available on EC2 but pip still needs to be installed.
$ sudo apt-get install python3-pip
Get virtualenv.
$ pip3 install virtualenv
Create the project folder or clone the project from your Git repository.
$ mkdir flaskproject
Set up the virtual environment.
$ cd flaskproject
$ virtualenv venv
Activate the environment (use deactivate to exit the environment).
$ . venv/bin/activate

Setup Flask

Install Flask
$ pip install Flask

Note: You do not need to use pip3 or python3 within the virtualenv since it is already a Python3 virtualenv. To be sure, you can run python while in the venv and check the version that it displays.

Create the Flask file. For now, we will use a basic sample file and call it app.py
$ vi app.py
Paste the following code in.
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
	return 'Hello, World!'

if __name__ == "__main__":
    app.run()

Setup Apache

Install mod_wsgi, make sure to have '-py3' at the end of libapache2-mod-wsgi-py3 or the runtime will default to Python2.7
$ sudo apt-get install apache2 libapache2-mod-wsgi-py3
Create a wsgi file.
$ vi app.wsgi
Paste the following code in.
activate_this = '/home/ubuntu/flaskproject/venv/bin/activate_this.py'
with open(activate_this) as f:
	exec(f.read(), dict(__file__=activate_this))

import sys
import logging

logging.basicConfig(stream=sys.stderr)
sys.path.insert(0,"/var/www/html/flaskproject/")

from app import app as application
Create a symlink so that the project directory appears in /var/www/html
$ sudo ln -sT ~/flaskproject /var/www/html/flaskproject
Enable wsgi.
$ sudo a2enmod wsgi
Configure apache (you will need to sudo to edit the file)
$ sudo vi /etc/apache2/sites-enabled/000-default.conf
Paste this in right after the line with DocumentRoot /var/www/html
WSGIDaemonProcess flaskproject threads=5
WSGIScriptAlias / /var/www/html/flaskproject/app.wsgi

<Directory flaskproject>
	WSGIProcessGroup flaskproject
	WSGIApplicationGroup %{GLOBAL}
	Order deny,allow
	Allow from all
</Directory>
Restart the Server
$ sudo apachectl restart

Open the page in a browser

Get the Public DNS from EC2 or just exit from EC2 and run echo $EC2_DNS to get the DNS. Paste it into a browser and it should display "Hello, World!". From this point on, refer to Flask documentation to build your application.

Debugging

Internal Server Error

If anything goes wrong, first check the error logs using:

$ vi /var/log/apache2/error.log
My changes are not showing up. The page still displays "Hello, World"

Try restarting your apache server

$ sudo apachectl restart
I can't get out of vim!!

Sorry, can't help you there.
Trapped
Stack Overflow: Helping One Million Developers Exit Vim

The error log is way too long

To clear the log, run

sudo bash -c 'echo > /var/log/apache2/error.log'
Mistakes in the guide

If you find any mistakes here or find that something needs an update, feel free to send me an email.