8
votes

I'm really struggling here. I have a simple Python Flask REST API that I've developed. The API runs fine in my local development environment (Mac OS X) and when directly executed via the console on my EC2 instance.

I want to move this service into production and as such would like to host it behind Apache running on the EC2 instance. This is where I keep hitting a wall and I can't seem to get past the configurations and errors. I've research several articles online and questions here, none seem to be able to help me.

I'm hoping someone here can please provide me with step-by-step directions on how to deploy my service to production behind Apache running on an Amazon Linux EC2 instance.

Here are the steps I've taken:

  1. Launched a basic Amazon Linux EC2 instance.
  2. Apply updates to the instance, sudo yum update
  3. Install Apache and WSIG, sudo yum install httpd24 mod24_wsgi
  4. Start Apache, sudo service httpd start
  5. Configure Apache to start automatically, sudo chkconfig httpd on
  6. Test by hitting the DNS of my EC2 box. I successfully get the Amazon Linux AMI test page.
  7. Adjust permissions on /var/www as follows
    • sudo groupadd www
    • sudo usermod -a -G www ec2-user
    • Logon/off and confirm membership, groups
    • sudo chown -R root:www /var/www
    • sudo chmod 2775 /var/www
    • find /var/www -type d -exec sudo chmod 2775 {} \;
    • find /var/www -type f -exec sudo chmod 0664 {} \;
  8. Test by hitting DNS of my EC2 box - still good so far.

Now that I know my instance is running, I would like to create two folders where I can test and run my Python Flask code. I do so as follows:

  1. I create two folders, one for development and one for production.
    • /var/www/rest-dev/
    • /var/www/rest-prod/
  2. I setup a virtual environment within each of the folders and install Flask.
    • virtualenv env
    • env/bin/pip install Flask
    • I then place a copy of my service in each folder.
    • Then I set permissions on app.py, chmod a+x app.py
    • I can successfully execute ./app.py and test the service by hitting the DNS name + port 5000. It works.

Now this is where I get tripped up. My goal is to be able to hit api.example.com and have my service's root load up. In the example code below, "Hello, World!" should simply display.

I've followed the tutorials found here with no luck.

http://peatiscoding.me/geek-stuff/mod_wsgi-apache-virtualenv/

http://webpy.org/cookbook/mod_wsgi-apache

http://www.jakowicz.com/flask-apache-wsgi/

After executing any of the steps in any of the articles above, I get an HTTP error page and nothing loads anymore, including the default Amazon Linux AMI test page. Below are the pieces of code and configurations that I've changed. I haven't changed my httpd.conf ... should I? There are probably several other things I'm missing.

Can someone please help me by providing me the necessary steps in detail to correct my mistakes?

Many thanks in advance!

When I view the error_log for HTTPD, it lists errors like this:

mod_wsgi (pid=8270): Target WSGI script '/var/www/rest-dev/deploy.wsgi' cannot be loaded as Python module.
mod_wsgi (pid=8270): Exception occurred processing WSGI script '/var/www/rest-dev/deploy.wsgi'.
Traceback (most recent call last):
  File "/var/www/rest-dev/deploy.wsgi", line 16, in <module>
    from app import app as application
  File "/var/www/rest-dev/app.py", line 2, in <module>
    from flask import Flask
ImportError: No module named flask

Here is my deploy.wsgi file, located in the rest-dev folder:

import os
import sys
import site

# Add virtualenv site packages
site.addsitedir(os.path.join(os.path.dirname(__file__),     'env/local/lib64/python2.7/site-packages'))

# Path of execution
sys.path.append('/var/www/rest-dev')

# Fired up virtualenv before include application
activate_env = os.path.expanduser(os.path.join(os.path.dirname(__file__), 'env/bin/activate_this.py'))
execfile(activate_env, dict(__file__=activate_env))

# import my_flask_app as application
from app import app as application

Here is my vhost.conf file located in /etc/httpd/conf.d/

<VirtualHost *:80>
        ServerName api.example.com

        WSGIDaemonProcess webtool user=ec2-user group=www threads=5 home=/var/www/rest-dev/
        WSGIScriptAlias / /var/www/rest-dev/deploy.wsgi

        <directory /var/www/rest-dev>
                WSGIProcessGroup webtool
                WSGIApplicationGroup %{GLOBAL}
                WSGIScriptReloading On
                Order deny,allow
                Allow from all
        </directory>
</VirtualHost>

Here is my app.py example service code for reference:

#!env/bin/python
from flask import Flask

app = Flask(__name__)

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

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)
1
The user and group settings in a WSGIDaemonProcess directive are only applied if apache is started as root, which it probably isn't here. That means all files and directories (including the virtualenv directories!) need to be accessible by the apache user. Are you sure they are?mata
I have no idea. How can I tell and change if necessary?K997
You can su to the apache user and see if you can access it (sudo su apache -s /bin/bash). If not, you can either make the directories world-readable (chmod a+rX venvdir) or owned by the apache-group and group-readable (chmod g+rX -R venvdir)...mata
I executed sudo su apache -s /bin/bash and I believe it worked. The prompt changed to [apache@ip-123-45-67-89 httpd]$K997
So now try to cd to the virtualenv and see if you can access the files...mata

1 Answers

5
votes

Turns out, in my deploy.wsgi file I'm referencing lib64 instead of just lib. All the site packages exist in lib.

After changing it and restarting Apache, I'm able to successfully hit my service from the URL.