ducin
ducin

Reputation: 26467

apache2, mod_wsgi, python web app (bottle framework)

Note: I guess the bottle framework is not relevant here. Wsgi is.

I've managed to configure my apache to work with wsgi and one-file web application based on python bottle framework. Below files are what I've got right now - apache uses virtualenv and runs a single wsgi/py file containing everything.

virtual host:

<VirtualHost *:80>
    ServerName bottle-test

    WSGIDaemonProcess bottle-test user=www-data group=www-data processes=1 threads=5
    WSGIScriptAlias / /home/tducin/Development/Python/bottle-test/src/app.wsgi

    <Directory /home/tducin/Development/Python/bottle-test/src>
        WSGIProcessGroup bottle-test
        WSGIApplicationGroup %{GLOBAL}
        Order deny,allow
        Allow from all
    </Directory>
    ErrorLog /var/log/apache2/wsgi/error-bottle.log
    CustomLog /var/log/apache2/wsgi/access-bottle.log combined
</VirtualHost>

httpd.conf (this is where my virtualenv resides):

WSGIPythonHome /home/tducin/Development/Python/bottle-test

And finally, this is app.wsgi:

import os

# Change working directory so relative paths (and template lookup) work again
os.chdir(os.path.dirname(__file__))

import bottle

app = bottle.Bottle()

@app.route('/')
def siema():
    return bottle.template('<h1>SIEMA {{arg}}!</h1>', arg='Janie')

@app.route('/hello/<name>')
def hello(name):
    return bottle.template('<b>Hello {{name}}</b>!', name=name)

application = app

What I want to do is to separate the wsgi layer from the rest of the application. I've tried few times to import the application from another file, but I was getting Failed to import module error each time. Does anyone know how to separate wsgi from application?


edit: I moved httpd.conf to wsgi.conf (it is loaded) and now I've got the following:

WSGIPythonHome /home/tducin/Development/Python/bottle-test
WSGIPythonPath /home/tducin/Development/Python/bottle-test/src

The problem is that now I've got error 500, apache error logs are:

[Wed Feb 05 09:24:32 2014] [error] [client 127.0.0.1] mod_wsgi (pid=4260): Target WSGI script '/home/tducin/Development/Python/bottle-test/src/app.wsgi' cannot be loaded as Python module.
[Wed Feb 05 09:24:32 2014] [error] [client 127.0.0.1] mod_wsgi (pid=4260): Exception occurred processing WSGI script '/home/tducin/Development/Python/bottle-test/src/app.wsgi'.
[Wed Feb 05 09:24:32 2014] [error] [client 127.0.0.1] Traceback (most recent call last):
[Wed Feb 05 09:24:32 2014] [error] [client 127.0.0.1]   File "/home/tducin/Development/Python/bottle-test/src/app.wsgi", line 7, in <module>
[Wed Feb 05 09:24:32 2014] [error] [client 127.0.0.1]     import server
[Wed Feb 05 09:24:32 2014] [error] [client 127.0.0.1] ImportError: No module named server

src/server.py contains bottle application stuff. The app.wsgi file has got full executable permissions:

-rwxrwxr-x 1 tducin tducin  377 Feb  5 09:22 app.wsgi

Upvotes: 1

Views: 3580

Answers (3)

H. U.
H. U.

Reputation: 637

The following approach worked for me.
step 1: Configure the virtual Host:
Linux Path : /etc/apache2/sites-available/default

<VirtualHost *:80>
    ServerAdmin webmaster@localhost

    WSGIDaemonProcess my_working_dir user=www-data group=www-data
    WSGIScriptAlias /my_working_dir /var/www/my_working_dir/app.wsgi

    <Directory /var/www/my_working_dir>
               WSGIProcessGroup my_working_dir
               WSGIApplicationGroup %{GLOBAL}
               Order deny,allow
               Allow from all
    </Directory>
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Step 2: configure app.wsgi file.
path: /var/www/my_working_dir/app.wsgi

import sys, os

# Change working directory so relative paths (and template lookup) work again
os.chdir(os.path.dirname(__file__))
sys.path.append(os.path.dirname(__file__))

# ... build or import your bottle application here ...
# Do NOT use bottle.run() with mod_wsgi

import bottle
from rs import app as application
from bottle import route
import hello_world
application=bottle.default_app()

Note: Import a file without using .py extension. (import hello_world)

Step 3: Create hello_world.py
Path : /var/www/my_working_dir/hello_world.py

from bottle import route, run

@route('/hello')
def hello():
    return "Hello World!"

#Comment out the localhost part, to test Apache configuration. 
#run(host='localhost', port=8080, debug=True)

step 4: Restart your apache server & test your api with Curl:
$ curl -i GET "http://[hostname]/hello"

Output:

HTTP/1.1 200 OK
Date: Thu, 06 Aug 2015 21:51:54 GMT
Server: Apache/2.2.22 (Ubuntu)
Content-Length: 12
Content-Type: text/html; charset=UTF-8

Upvotes: 8

leodotcloud
leodotcloud

Reputation: 1960

I tried Graham's suggestion but it didn't work for me.

Here is what worked for me:
[BTW, I am working on OSX. Please adjust the paths, user, group according to your operating system]

/Library/WebServer/Documents/hello_app/app.wsgi:

import sys

sys.path.insert(0, "/Library/WebServer/Documents/hello_app")

import bottle
import hello
application = bottle.default_app()

/Library/WebServer/Documents/hello_app/hello.py:

from bottle import route

@route('/hello')
def hello():
    return "Hello World!"

/etc/apache2/extra/httpd-vhosts.conf:

<VirtualHost *:80>
    ServerName xyz.com

    WSGIDaemonProcess hello_app user=_www group=_www processes=1 threads=5
    WSGIScriptAlias /v1 /Library/WebServer/Documents/hello_app/app.wsgi

    <Directory /Library/WebServer/Documents/hello_app>
        WSGIProcessGroup hello_app
        WSGIApplicationGroup %{GLOBAL}
        Order deny,allow
        Allow from all
    </Directory>
</VirtualHost>

Don't forget to restart your apache server.

Check the app in the web browser

Upvotes: 0

Graham Dumpleton
Graham Dumpleton

Reputation: 58533

Using Apache/mod_wsgi, it does not look in the current working directory of the process for modules when imported. This is by virtue of how things when work Python is used in embedded systems. You thus need to tell mod_wsgi which additional directories should be added into the Python module search path. Assuming the directory where the additional modules is is the same as your WSGI script, use:

WSGIPythonPath /home/tducin/Development/Python/bottle-test/src

BTW, it is bad practice in WSGI applications to rely on the current working directory being a specific value and use relative path names in config file/template access. IOW, it is not a good idea to use:

os.chdir(os.path.dirname(__file__))

You should always calculate file system paths dynamically based on a configured root directory value or from os.path.dirname(__file__). That is, like you are doing, but just use it as input to os.chdir(), use it to construct proper absolute path names for files instead.

Upvotes: 2

Related Questions