Deploying a Simple WSGI Application on AWS¶
Let’s walk through manually deploying a simple WSGI application to an AWS EC2 instance we’ve created.
Setup¶
$ python3 -m venv wsgiapp
$ cd wsgiapp
$ . bin/activate
(wsgiapp)$
In the new wsgiapp
directory, create a very simple WSGI application. Start by
creating a new file myapp.py
and opening it in your editor. In the file,
type the following Python code:
# -*- coding: utf-8 -*-
def app(environ, start_response):
data = "Hello, World!\n"
start_response("200 OK", [
("Content-Type", "text/plain"),
("Content-Length", str(len(data)))
])
return iter([data])
if __name__ == '__main__':
from wsgiref.simple_server import make_server
srv = make_server('localhost', 8080, app)
srv.serve_forever()
Test your application to be sure it works by running it from the command line:
(wsgiapp)$ python myapp.py
Point your web browser at http://localhost:8080/ and verify that you can see “Hello World!” printed.
Next, provision a new EC2 instance on AWS using the through-the web provisioner. Make sure you are using an Ubuntu image, either version 12.04 or 14.04.
Next, use the shell command scp
to securely copy your wsgi application to the new server instance.
You’ll need to update the path to your private key file and the public DNS name of your EC2 instance from the values shown here.
(wsgiapp)$ scp -i ~/.ssh/pk-cpe.pem myapp.py ubuntu@ec2-54-184-162-20.us-west-2.compute.amazonaws.com:~/
...
Are you sure you want to continue connecting (yes/no)? yes
...
myapp.py 100% 381 0.4KB/s 00:00
(wsgiapp)$
Manual Configuration¶
We are going to do this manually once together. Later, you’ll have a chance to repeat the process using a configuration management tool.
Configure Nginx¶
The first step is to configure nginx
to proxy HTTP requests to our simple application.
If you know, or are more comfortable with the Apache
webserver, you can also use that.
However, the trend I’ve seen over the last few years is toward the use of nginx
over the old stand-by.
Nginx stores site configuration on Ubuntu in the /etc/nginx/sites-available
directory.
This is in fact a pattern you’ll get used to.
On most Linux machines, configuration of individual applications can be found in the /etc
directory.
Let’s shell into our new instance and look at what’s there:
(wsgiapp)$ ssh -i ~/.ssh/pk-cpe.pem ubuntu@ec2-54-184-162-20.us-west-2.compute.amazonaws.com
Welcome to Ubuntu 12.04.4 LTS (GNU/Linux 3.2.0-58-virtual x86_64)
...
Last login: Wed Feb 26 19:10:01 2014 from 199.231.242.170
ubuntu@ip-10-254-159-140:~$ ls /etc/nginx/sites-available/
default
ubuntu@ip-10-254-159-140:~$ more /etc/nginx/sites-available/default
# You may add here your
# server {
# ...
# }
# statements for each of your virtual hosts to this file
...
ubuntu@ip-10-254-159-140:~$
The sites-available
directory will hold individual site configuration for all sites that might be available on a server.
Active site configuration is listed in the /etc/nginx/sites-enabled
:
ubuntu@ip-10-254-159-140:~$ ls /etc/nginx/sites-enabled/
default
ubuntu@ip-10-254-159-140:~$ ls -l /etc/nginx/sites-enabled/
total 0
lrwxrwxrwx 1 root root 34 Feb 26 19:09 default -> /etc/nginx/sites-available/default
ubuntu@ip-10-254-159-140:~$
Notice that in fact, although default
is in that directory too,
it’s actually a soft link to the file in sites-available
.
Let’s move aside the existing default
config and replace it with a simple one of our own.
On your local machine, in the wsgiapp
directory, make a new file simple_nginx_config
.
Open that file in your editor and add the following:
server {
listen 80;
server_name ec2-54-184-162-20.us-west-2.compute.amazonaws.com;
access_log /var/log/nginx/test.log;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Remember, you want to use the name of your actual server on aws, not the example used above.
Now, copy that file up to your server too:
(wsgiapp)$ scp -i ~/.ssh/pk-cpe.pem simple_nginx_config ubuntu@ec2-54-184-162-20.us-west-2.compute.amazonaws.com:~/
simple_nginx_config 100% 363 0.4KB/s 00:00
(wsgiapp)$
Next, on the server, move the original default configuration file aside and put your new one in its place:
ubuntu@ip-10-254-159-140:~$ ls
myapp.py simple_nginx_config
ubuntu@ip-10-254-159-140:~$ sudo mv /etc/nginx/sites-available/default /etc/nginx/sites-available/default.orig
ubuntu@ip-10-254-159-140:~$ sudo mv simple_nginx_config /etc/nginx/sites-available/default
ubuntu@ip-10-254-159-140:~$ ls -l /etc/nginx/sites-enabled/
total 0
lrwxrwxrwx 1 root root 34 Feb 26 19:09 default -> /etc/nginx/sites-available/default
ubuntu@ip-10-254-159-140:~$
Once that’s complete, you can restart nginx to have it pick up your changes:
ubuntu@ip-10-254-159-140:~$ sudo service nginx restart
...
ubuntu@ip-10-254-159-140:~$
If you now try to load the public DNS name for your EC2 instance, you’ll see that nginx has updated and is now throwing an error:
http://ec2-54-184-162-20.us-west-2.compute.amazonaws.com
This should tell you Bad Gateway. That’s the error that means “I am a proxy, but the thing I’m proxying to is not running!”
Running a WSGI Server¶
Let’s make our wsgi app run, so we can fix that.
On your server, run the wsgi app:
ubuntu@ip-10-254-159-140:~$ python myapp.py
And now reload your web browser and verify that you can see “Hello, World!”
Automation¶
The steps we took there allowed us to upload an application and some configuration to our server,
apply the configuration to the nginx
web server we installed,
and then run our WSGI application in a terminal to get a response via public DNS.
Your task is to repeat this process for homework. Later, we’ll learn how to automate this task using configuration management tools.