Python CGI on Amazon AWS EC2 micro-instance — a how-to!

amazon ec2cgilighttpdpython

How can you make an EC2 micro instance serve CGI scripts from lighthttpd? For instance Python CGI?

Well, it took half a day, but I have gotten Python cgi running on a free Amazon AWS EC2 micro-instance, using the lighttpd server. I think it will help my fellow noobs to put all the steps in one place. Armed with the simple steps below, it will take you only 15 minutes to set things up!

My question for the more experienced users reading this is: Are there any security flaws in what I've done? (See file and directory permissions.)

Step 1: Start your EC2 instance and ssh into it.

[Obviously, you'll need to sign up for Amazon EC2 and save your key pairs to a *.pem file. I won't go over this, as Amazon tells you how to do it.]

  1. Sign into your AWS account and start your EC2 instance. The web has tutorials on doing this. Notice that default instance-size that Amazon presents to you is "small." This is not "micro" and so it will cost you money. Be sure to manually choose "micro." (Micro instances are free only for the first year…)

  2. Find the public DNS code for your running instance. To do this, click on the instance in the top pane of the dashboard and you'll eventually see the "Public DNS" field populated in the bottom pane. (You may need to fiddle a bit.) The Public DNS looks something like:
    ec2-174-129-110-23.compute-1.amazonaws.com

  3. Start your Unix console program. (On Max OS X, it's called Terminal, and lives in the Applications -> Utilities folder.)

  4. cd to the directory on your desktop system that has your *.pem file containing your AWS keypairs.

  5. ssh to your EC2 instance using a command like:
    ssh -i <<your *.pem filename>> ec2-user@<< Public DNS address >>

    So, for me, this was:
    ssh -i amzn_ec2_keypair.pem ec2-user@ec2-174-129-110-23.compute-1.amazonaws.com

  6. Your EC2 instance should let you in.

Step 2: Download lighttpd to your EC2 instance.

  1. To install lighttpd, you will need root access on your EC2 instance. The problem is: Amazon will not let you sign in as root. (Not straightforwardly, at least.) But there is a workaround. Type this command:
    sudo /bin/bash

  2. The system prompt-character will change from $ to #. We won't exit from "sudo" until the very last step in this whole process.

  3. Install the lighttpd application (version 1.4.28-1.3.amzn1 for me):
    yum install lighttpd

  4. Install the FastCGI libraries for lighttpd (not needed, but why not?):
    yum install lighttpd-fastcgi

  5. Test that your server is working:
    /etc/init.d/lighttpd start

Step 3: Let the outside world see your server.

  1. If you now tried to hit your server from the browser on your desktop, it would fail. The reason: By default, Amazon AWS does not open any ports to your EC2 instance. So, you have to open the ports manually.

  2. Go to your EC2 dashboard in your desktop's browser. Click on "Security Groups" in the left pane. One or more security groups will appear in the upper right pane. Choose the one that was assigned to your EC2 instance when you launched your instance.

  3. A table called "Allowed Connections" will appear in the lower right pane. A pop-up menu will let you choose "HTTP" as the connection method.

  4. The other values in that line of the table should be: tcp, 80, 80, 0.0.0.0/0

  5. Now hit your EC2 instance's server from the desktop in your browser. Use the Public DNS address that you used earlier to SSH in. You should see the lighttpd generic web page. If you don't, I can't help you because I am such a noob. 🙁

Step 4: Configure lighttpd to serve CGI.

  1. Back in the console program, cd to the configuration directory for lighttpd:
    cd /etc/lighttpd

  2. To enable CGI, you want to uncomment one line in the < modules.conf > file. (I could have enabled Fast CGI, but baby steps are best!) You can do this with the "ed" editor as follows:
    ed modules.conf
    /include "conf.d\/cgi.conf"/
    s/#//
    w
    q

  3. Create the directory where CGI programs will live. (The /etc/lighttpd/lighttpd.conf file determines where this will be.) We'll create our directory in the default location, so we don't have to do any editing of configuration files:
    cd /var/www/lighttpd
    mkdir cgi-bin
    chmod 755 cgi-bin

  4. Almost there! Of course you need to put a test CGI program into the cgi-bin directory. Here is one:
    cd cgi-bin
    ed
    a
    #!/usr/bin/python
    print "Content-type: text/html\n\n"
    print "<html><body>Hello, pyworld.</body></html>"
    .
    w hellopyworld.py
    q
    chmod 655 hellopyworld.py

  5. Restart your lighttpd server:
    /etc/init.d/lighttpd restart

  6. Test your CGI program. In your desktop's browser, hit this URL, substituting your EC2 instance's public DNS address:
    http://<<Public DNS>>/cgi-bin/hellopyworld.py

    For me, this was:
    http://ec2-174-129-110-23.compute-1.amazonaws.com/cgi-bin/hellopyworld.py

Step 5: That's it! Clean up, and give thanks!

  • To exit from the "sudo /bin/bash" command given earlier, type:
    exit

  • Acknowledgements: Heaps of thanks to:

    wiki.vpslink.com/Install_and_Configure_lighttpd

    www.cyberciti.biz/tips/lighttpd-howto-setup-cgi-bin-access-for-perl-programs.html

    aws.typepad.com/aws/2010/06/building-three-tier-architectures-with-security-groups.html

  • Good luck, amigos! I apologize for the non-traditional nature of this "question" but I have gotten so much help from Stackoverflow that I was eager to give something back.

Best Answer

(Strange post, so hopefully this won't be as strange a reply).

On the subject of security flaws: it is considered general bad practice to store cgi-bin scripts within the document root of the web server. Even the W3C eludes to it under "Are compiled languages such as C safer ..." in their World Wide Web Security FAQ:

Consider the following scenario. For convenience's sake, you've decided to identify CGI scripts to the server using the .cgi extension. Later on, you need to make a small change to an interpreted CGI script. You open it up with the Emacs text editor and modify the script. Unfortunately the edit leaves a backup copy of the script source code lying around in the document tree. Although the remote user can't obtain the source code by fetching the script itself, he can now obtain the backup copy by blindly requesting the URL:

    http://your-site/a/path/your_script.cgi~

(This is another good reason to limit CGI scripts to cgi-bin and to make sure that cgi-bin is separate from the document root.)

This is not as significant a threat as the ability to write a file within the document root. However, an attacker could obtain the source code of the cgi, devise a directed attack against it, and use it as a stepping stone into the server.

To mitigate this, you can add the following lines to the lighttpd.conf (or some variation therein) to direct cgi-bin to a directory separate from the /var/www/lighttpd document root.

$HTTP["url"] =~ "/cgi-bin/" { cgi.assign = ( "" => "" ) }
alias.url = ( "/cgi-bin/" => "/usr/lib/cgi-bin/" )

This requires both the cgi and alias modules for lighttpd.

Related Topic