mod_wsgi

Introduction

This tutorial shows you how to easily publish your PyAMF applications with the Apache 2 webserver and mod_wsgi. Mod_wsgi is an Apache module which can host any Python application which supports the Python WSGI interface. This was tested with Python 2.5, Apache 2.0.55 and mod_wsgi 2.x.

This tutorial assumes you already installed the Apache webserver running (on 192.168.1.100). Flash applications will be able to access your PyAMF remoting gateway on http://192.168.1.100/flashservices/gateway.

Create your PyAMF application

Create a folder for your application:

mkdir /var/www/myApp

Create your application in /var/www/myApp/application.py:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from pyamf.remoting.gateway.wsgi import WSGIGateway

def echo(data):
   return data

services = {
   'echo': echo,
   # Add other exposed functions here
}

gateway = WSGIGateway(services)

WSGI startup file

Create a folder for the WSGI startup file:

mkdir /var/www/wsgi

Create the WSGI startup file for your application in /var/www/wsgi/myApp.wsgi:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import logging
from logging.handlers import RotatingFileHandler

import application as app


# logging level
LEVEL = logging.DEBUG

# a filename to append log messages to
LOG_FILENAME = '/var/log/apache2/myApp.log'

# max size in bytes before a new log file is created
MAX_SIZE = 2000

# max amount of log files before it rotates
BACKUP_COUNT = 5

# Set up a specific logger with our desired output level
logger = logging.getLogger('MyLogger')
logger.setLevel(LEVEL)

# Add the log message handler to the logger
handler = RotatingFileHandler(LOG_FILENAME,
			      maxBytes=MAX_SIZE,
			      backupCount=BACKUP_COUNT)

# log message formatter
formatter = logging.Formatter("%(asctime)s %(levelname)-5.5s [%(name)s] %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)


# hook up logger to gateway
app.gateway.logger = logger

# hook up gateway to mod_wsgi
application = app.gateway

About logging

When using mod_wsgi, unless you take specific action to catch exceptions and present the details in an alternate manner, the only place that details of uncaught exceptions will be recorded is in the Apache error log files. The Apache error log files are therefore your prime source of information when things go wrong.

This example tries to make your life easier by using a custom RotatingFile logger, that writes log messages to a file.

Setup Apache virtual host

Create a new virtual host or modify an existing one:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
WSGIPythonPath "/usr/src/pyamf:/var/www/myApp"

<VirtualHost 192.168.1.100:80>

        ServerName example.server.com

        CustomLog /var/log/apache2/myApp-access.log combined
        ErrorLog /var/log/apache2/myApp-error.log

	# Set this to 'warn' when you're done with debugging
        LogLevel debug

        # PyAMF remoting gateway
        WSGIScriptAlias /flashservices/gateway /var/www/wsgi/myApp.wsgi
        
        <Directory /var/www/wsgi>
                WSGIApplicationGroup %{GLOBAL}
                Order allow,deny  
                Allow from all 
        </Directory>

</VirtualHost>

This sample assumes you have a copy of the PyAMF source installed in /usr/src/pyamf but you can comment out line 1 if you installed PyAMF in your Python’s site-packages folder.

Make sure your Apache user (www-data) has access to your application files.

Restart Apache

That’s it! Your Adobe Flash Player and AMF clients will now be able to access your PyAMF application through http://192.168.1.100/flashservices/gateway.

Test the gateway

To test the gateway you can use a Python AMF client like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import logging
	
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s %(levelname)-5.5s [%(name)s] %(message)s'
)

from pyamf.remoting.client import RemotingService

url = 'http://192.168.1.108/flashservices/gateway'
gw = RemotingService(url, logger=logging)
service = gw.getService('echo')

print service('Hello World!')