Multiple Django Virtual Hosts on Apache+mod_wsgi but only one gets served

3,121 views
Skip to first unread message

Chris Cuilla

unread,
Feb 6, 2012, 7:56:22 PM2/6/12
to modwsgi
I've been struggling to figure out the following problem and am hoping
someone else has seen this.

I have a server running Apache 2 w/mod_wsgi. I've setup multiple,
different Django apps. Each has its own virtual host configuration
(see below).

This is on a local test server and my client machines have /etc/hosts
configured to point both app_a and app_b hostnames to the same
machine.

The problem I have is that Apache is only serving app_a regardless of
whether I go to app_a or app_b in my browser.

Has anyone seen anything like this?

P.S. When configured as plain, vanilla virtual hosts (i.e., no
mod_wsgi) the virtual hosting works just fine.


<VirtualHost *:80>
ServerName app_a

<Directory /home/app_a/public_html/app_a/static>
Order deny,allow
Allow from all
</Directory>

<Directory /home/app_a/public_html/app_a/media>
Order deny,allow
Allow from all
</Directory>

<Directory /home/app_a/public_html/app_a>
Order deny,allow
Allow from all
</Directory>

LogLevel warn
ErrorLog /home/app_a/public_html/app_a/logs/apache_error.log
CustomLog /home/app_a/public_html/app_a/logs/apache_access.log
combined

WSGIDaemonProcess app_a user=www-data group=www-data threads=20
processes=2 display-name=app_a
WSGIProcessGroup app_a

WSGIScriptAlias / /home/app_a/public_html/app_a/app_a/app.wsgi
</VirtualHost>

<VirtualHost *:80>
ServerName app_b

<Directory /home/app_b/public_html/app_b/static>
Order deny,allow
Allow from all
</Directory>

<Directory /home/app_b/public_html/app_b/media>
Order deny,allow
Allow from all
</Directory>

<Directory /home/app_b/public_html/app_b>
Order deny,allow
Allow from all
</Directory>

LogLevel warn
ErrorLog /home/app_b/public_html/app_b/logs/apache_error.log
CustomLog /home/app_b/public_html/app_b/logs/apache_access.log
combined

WSGIDaemonProcess app_b user=www-data group=www-data threads=20
processes=2 display-name=app_b
WSGIProcessGroup app_b

WSGIScriptAlias / /home/app_b/public_html/app_b/app_b/app.wsgi
</VirtualHost>

Graham Dumpleton

unread,
Feb 6, 2012, 8:29:39 PM2/6/12
to mod...@googlegroups.com
There is likely something missing as far as enabling of name based
virtual hosts, or hostnames are not matching ServerName.

When there are VirtualHost's defined, if Apache can't map the host
name properly against the VirtualHost, then Apache will send the
request to the first VirtualHost definition it found. If that happened
to be the one for app_a, that would explain why everything goes to it.

First thing to check is that you have:

NameVirtualHost *:80

directive present and that it isn't commented out.

Then ensure that ServerName directive does have value the same as
actual host name using in the URL.

One other thing you can do is add in a default VirtualHost as very
first one, which from memory is defined as:

<VirtualHost __default__:80>
Deny from all
</VirtualHost>

With that in place, if named virtual host lookup is failing, will go
to that and you will get a forbidden error, rather than it going to
wrong virtual host.

Graham

> --
> You received this message because you are subscribed to the Google Groups "modwsgi" group.
> To post to this group, send email to mod...@googlegroups.com.
> To unsubscribe from this group, send email to modwsgi+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/modwsgi?hl=en.
>

Chris Cuilla

unread,
Feb 6, 2012, 8:55:58 PM2/6/12
to modwsgi
Graham -

Thanks for the response. A couple of things:

Virtual hosts works fine when they are not mod_wsgi ghosts. When they
just plain, vanilla it works just fine. Not sure that matters, but
seems like the problems is some how related to mod_wsgi config.

> First thing to check is that you have:
>
>   NameVirtualHost *:80
>
> directive present and that it isn't commented out.

Yeah, that's set.


> One other thing you can do is add in a default VirtualHost as very
> first one, which from memory is defined as:
>
> <VirtualHost __default__:80>
> Deny from all
> </VirtualHost>
>
> With that in place, if named virtual host lookup is failing, will go
> to that and you will get a forbidden error, rather than it going to
> wrong virtual host.

I tried that but it seems to shut out everything.

Thanks for the suggestions.

Graham Dumpleton

unread,
Feb 6, 2012, 9:08:39 PM2/6/12
to mod...@googlegroups.com
Next thing to try would be to replace the WSGI scripts with one which
echos WSGI environ.

http://code.google.com/p/modwsgi/wiki/DebuggingTechniques#Displaying_Request_Environment

Then compare what environ is for requests against different virtual
hosts to see if that gives a clue.

Strip any really sensitive information, trying not to change the
meaning, and post it.

Graham

Chris Cuilla

unread,
Feb 19, 2012, 4:59:30 PM2/19/12
to modwsgi
Sorry for the delay. Hope you're still out there. Here is the output
from the recommended debugging script for two apps (appa and appb)
configured at the same time on the same server:

PID: 13699
UID: 33
GID: 33

DOCUMENT_ROOT: '/home/appa/public_html/appa.com/'
GATEWAY_INTERFACE: 'CGI/1.1'
HTTP_ACCEPT: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/
*;q=0.8'
HTTP_ACCEPT_ENCODING: 'gzip, deflate'
HTTP_ACCEPT_LANGUAGE: 'en-us'
HTTP_CACHE_CONTROL: 'max-age=0'
HTTP_CONNECTION: 'keep-alive'
HTTP_COOKIE: 'csrftoken=a44bec4e72d4792845c65a8be67669a2'
HTTP_HOST: 'appa-test'
HTTP_USER_AGENT: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3)
AppleWebKit/534.53.11 (KHTML, like Gecko) Version/5.1.3 Safari/
534.53.10'
PATH_INFO: '/'
PATH_TRANSLATED: '/home/appa/public_html/appa.com/appa/app.wsgi/'
QUERY_STRING: ''
REMOTE_ADDR: '192.168.0.5'
REMOTE_PORT: '54460'
REQUEST_METHOD: 'GET'
REQUEST_URI: '/'
SCRIPT_FILENAME: '/home/appa/public_html/appa.com/appa/app.wsgi'
SCRIPT_NAME: ''
SERVER_ADDR: '192.168.0.254'
SERVER_ADMIN: 'ch...@appa.com'
SERVER_NAME: 'appa-test'
SERVER_PORT: '80'
SERVER_PROTOCOL: 'HTTP/1.1'
SERVER_SIGNATURE: '<address>Apache/2.2.20 (Ubuntu) Server at appa-test
Port 80</address>\n'
SERVER_SOFTWARE: 'Apache/2.2.20 (Ubuntu)'
mod_wsgi.application_group: 'appa-test|'
mod_wsgi.callable_object: 'application'
mod_wsgi.handler_script: ''
mod_wsgi.input_chunked: '0'
mod_wsgi.listener_host: ''
mod_wsgi.listener_port: '80'
mod_wsgi.process_group: 'appa'
mod_wsgi.request_handler: 'wsgi-script'
mod_wsgi.script_reloading: '1'
mod_wsgi.version: (3, 3)
wsgi.errors: <mod_wsgi.Log object at 0x2273a110>
wsgi.file_wrapper: <built-in method file_wrapper of mod_wsgi.Adapter
object at 0x226aade8>
wsgi.input: <mod_wsgi.Input object at 0x2273a020>
wsgi.multiprocess: True
wsgi.multithread: True
wsgi.run_once: False
wsgi.url_scheme: 'http'
wsgi.version: (1, 1)


PID: 13702
UID: 33
GID: 33

DOCUMENT_ROOT: '/home/appb/public_html/appb.ws/'
GATEWAY_INTERFACE: 'CGI/1.1'
HTTP_ACCEPT: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/
*;q=0.8'
HTTP_ACCEPT_ENCODING: 'gzip, deflate'
HTTP_ACCEPT_LANGUAGE: 'en-us'
HTTP_CACHE_CONTROL: 'max-age=0'
HTTP_CONNECTION: 'keep-alive'
HTTP_HOST: 'appb-test'
HTTP_USER_AGENT: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3)
AppleWebKit/534.53.11 (KHTML, like Gecko) Version/5.1.3 Safari/
534.53.10'
PATH_INFO: '/'
PATH_TRANSLATED: '/home/appb/public_html/appb.ws/appb/app.wsgi/'
QUERY_STRING: ''
REMOTE_ADDR: '192.168.0.5'
REMOTE_PORT: '54461'
REQUEST_METHOD: 'GET'
REQUEST_URI: '/'
SCRIPT_FILENAME: '/home/appb/public_html/appb.ws/appb/app.wsgi'
SCRIPT_NAME: ''
SERVER_ADDR: '192.168.0.254'
SERVER_ADMIN: 'ch...@appb.ws'
SERVER_NAME: 'appb-test'
SERVER_PORT: '80'
SERVER_PROTOCOL: 'HTTP/1.1'
SERVER_SIGNATURE: '<address>Apache/2.2.20 (Ubuntu) Server at appb-test
Port 80</address>\n'
SERVER_SOFTWARE: 'Apache/2.2.20 (Ubuntu)'
mod_wsgi.application_group: 'appb-test|'
mod_wsgi.callable_object: 'application'
mod_wsgi.handler_script: ''
mod_wsgi.input_chunked: '0'
mod_wsgi.listener_host: ''
mod_wsgi.listener_port: '80'
mod_wsgi.process_group: 'appb'
mod_wsgi.request_handler: 'wsgi-script'
mod_wsgi.script_reloading: '1'
mod_wsgi.version: (3, 3)
wsgi.errors: <mod_wsgi.Log object at 0x2273a110>
wsgi.file_wrapper: <built-in method file_wrapper of mod_wsgi.Adapter
object at 0x226aade8>
wsgi.input: <mod_wsgi.Input object at 0x2273a020>
wsgi.multiprocess: True
wsgi.multithread: True
wsgi.run_once: False
wsgi.url_scheme: 'http'
wsgi.version: (1, 1)


On Feb 6, 7:08 pm, Graham Dumpleton <graham.dumple...@gmail.com>
wrote:
> Next thing to try would be to replace the WSGI scripts with one which
> echos WSGI environ.
>
> http://code.google.com/p/modwsgi/wiki/DebuggingTechniques#Displaying_...
>
> Then compare what environ is for requests against different virtual
> hosts to see if that gives a clue.
>
> Strip any really sensitive information, trying not to change the
> meaning, and post it.
>
> Graham
>

Graham Dumpleton

unread,
Feb 19, 2012, 6:05:11 PM2/19/12
to mod...@googlegroups.com
Try again. This time use:

WSGIDaemonProcess app_??? user=www-data group=www-data

Ie., drop processes/threads option. That way each daemon process group
has only one process and so can meaningfully compare process IDs for
each to make sure different.

Also provide copies of the two WSGI script files using for Django setup.

Graham

Chris Cuilla

unread,
Feb 19, 2012, 6:37:49 PM2/19/12
to modwsgi
Here are the scripts. Note that both are the same except for the app
names:


import os
import sys

sys.path.insert(0, '/home/appa/public_html/appa.com')
sys.path.insert(0, '/home/appa/public_html/appa.com/appa')

os.environ['DJANGO_SETTINGS_MODULE'] = 'appa.settings'

import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()



import os
import sys

sys.path.insert(0, '/home/appb/public_html/appb.ws')
sys.path.insert(0, '/home/appb/public_html/appb.ws/appb')

os.environ['DJANGO_SETTINGS_MODULE'] = 'appb.settings'

import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()



On Feb 19, 4:05 pm, Graham Dumpleton <graham.dumple...@gmail.com>
wrote:
> Try again. This time use:
>
> WSGIDaemonProcess app_??? user=www-data group=www-data
>
> Ie., drop processes/threads option. That way each daemon process group
> has only one process and so can meaningfully compare process IDs for
> each to make sure different.
>
> Also provide copies of the two WSGI script files using for Django setup.
>
> Graham
>

Chris Cuilla

unread,
Feb 19, 2012, 6:41:07 PM2/19/12
to modwsgi
Changing the WSGIDaemonProcess app_??? user=www-data group=www-data as
suggested, it looks like each definitely has a different PID.

I'm guessing there's something in the scripts that I'm doing wrong.

Graham Dumpleton

unread,
Feb 20, 2012, 7:13:55 PM2/20/12
to mod...@googlegroups.com
Next you could amend your Django WSGI script files to have a simple
WSGI application wrapper around the Django one which rather than
return the WSGI environment information like with prior test, prints
it to Apache error log using 'print'. You could also print os.environ
so can confirm what DJANGO_SETTINGS_MODULE is set to. Plus what
sys.path is set to.

Graham

Brendon Stanton

unread,
May 22, 2012, 9:51:49 AM5/22/12
to mod...@googlegroups.com
I am having this same problem and wondered if anyone had discovered a solution.

Graham Dumpleton

unread,
May 22, 2012, 10:07:51 PM5/22/12
to mod...@googlegroups.com
On 22 May 2012 23:51, Brendon Stanton <bump...@gmail.com> wrote:
> I am having this same problem and wondered if anyone had discovered a
> solution.

The cause for this occurring in some cases has been hard to nail down.
Problem is that to sort it out may well need hacking up mod_wsgi to
get additional information out of it about what is going on. This is
something that has usually been beyond the people having the problem.

I note you have also posted at:

http://stackoverflow.com/questions/10695302/two-django-projects-conflicting-with-one-another

We can try and work through it here if still interested, but be warned
that am quite overloaded at the moment, so may be slow process.

To start with, ensure that have:

LogLevel info

at the minimum, rather than 'warn'.

Then monitoring messages from mod_wsgi about what process/application
context WSGI scripts are being loaded in.

A further step one could take is to ramp up to:

LogLevel debug

and add:

WSGIVerboseLogging On

You will need mod_wsgi 3.X at least from memory.

Finally, rather than sub domains I would have used separate daemon
process groups and delegated each web application to their own. That
ensures process level separation and avoids problems with environment
variable leakage.

If the issue is wrong interpreter selection within the process though,
then could see more memory used that necessary if not also forced to
use main interpreter of respect daemon processes.

Graham

Benjamin Bach

unread,
Jun 26, 2012, 9:37:34 AM6/26/12
to mod...@googlegroups.com

I'm currently running mod_wsgi 2.8 on Ubuntu Lucid, so the first thing I'll do is try to upgrade to mod_wsgi 3.X and report back if the problem has gone or not.

The problem persists on 3.X. Restarting Apache or the server does not work. Graham's suggestion to use "WSGIVerboseLogging" does not work, as this directive does not exist, nor in the documentation?

I have searched my whole codebase, and the only place that the "settings_alternative" string exists is in a single WSGI configuration that is only used in a single :443 virtual host.

I do not know how to progress with this error. However, I read the following in the modwsgi docs on Django projects:

Note that Django expects the name of the site settings file to be stored in the environment variable DJANGO_SETTINGS_MODULE. This means that it is impossible to run two Django sites within one Python sub interpreter. This isn't in general a problem with mod_wsgi however, as the default for mod_wsgi is to execute each WSGI application within the context of its own Python sub interpreter.

Can the problem be that the environment variable is mistakenly interchanged with another running instance

I'm running prefork MPM.

The WSGI file, project_alternative.wsgi, that loads the settings_alternative module looks like this:

import os
import sys
import site

activate_this = '/path/to/virtenv/bin/activate_this.py'
execfile(activate_this, dict(__file__=activate_this))

os.environ['DJANGO_SETTINGS_MODULE'] = 'settings_alternative'

PROJECT_PATH = os.path.abspath(os.path.split(__file__)[0])
PROJECT_PARENT = os.path.abspath(os.path.split(PROJECT_PATH)[0])
sys.path.insert(0, PROJECT_PATH)
sys.path.insert(0, PROJECT_PARENT)

Graham Dumpleton

unread,
Jun 26, 2012, 8:09:27 PM6/26/12
to mod...@googlegroups.com
On 26 June 2012 23:37, Benjamin Bach <benja...@gmail.com> wrote:
>
>> I'm currently running mod_wsgi 2.8 on Ubuntu Lucid, so the first thing
>> I'll do is try to upgrade to mod_wsgi 3.X and report back if the problem has
>> gone or not.
>
>
> The problem persists on 3.X. Restarting Apache or the server does not work.
> Graham's suggestion to use "WSGIVerboseLogging" does not work, as this
> directive does not exist, nor in the documentation?

Sorry, wrong name:

WSGIVerboseDebugging

> I have searched my whole codebase, and the only place that the
> "settings_alternative" string exists is in a single WSGI configuration that
> is only used in a single :443 virtual host.
>
> I do not know how to progress with this error. However, I read the following
> in the modwsgi docs on Django projects:
>
>> Note that Django expects the name of the site settings file to be stored
>> in the environment variable DJANGO_SETTINGS_MODULE. This means that it is
>> impossible to run two Django sites within one Python sub interpreter. This
>> isn't in general a problem with mod_wsgi however, as the default for
>> mod_wsgi is to execute each WSGI application within the context of its own
>> Python sub interpreter.
>
>
> Can the problem be that the environment variable is mistakenly interchanged
> with another running instance
>
> I'm running prefork MPM.

But are you using daemon mode?

Provide a sample of your mod_wsgi configuration for a site.

Graham

Benjamin Bach

unread,
Jul 3, 2012, 3:57:02 PM7/3/12
to mod...@googlegroups.com

On Wednesday, June 27, 2012 2:09:27 AM UTC+2, Graham Dumpleton wrote:
But are you using daemon mode?

Provide a sample of your mod_wsgi configuration for a site.

Thanks for responding, this is my Apache configuration:

<VirtualHost *:80>
    DocumentRoot /var/www
    ServerName example.com
    WSGIScriptAlias / /var/sites/example_com_site/wsgi.py
</VirtualHost>

The wsgi.py file is the default provided in the new Django 1.4 layout. It contains this line:

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example_com_site.settings")

Could it be that this environment variable is already set?

From the documentation of setdefault:

If key is in the dictionary, return its value. If not, insert key with a value of default and return default. default defaults to None.

 ...and maybe this is more correct?

os.environ['DJANGO_SETTINGS_MODULE'] = 'example_com_site.settings'

- Benjamin

Graham Dumpleton

unread,
Jul 3, 2012, 6:05:36 PM7/3/12
to mod...@googlegroups.com, mod...@googlegroups.com


If the auto generated wsgi.py is using setdefault they have broken it very badly. When running in a multiple sub interpreter process, the first wsgi.py in any sub interpreter will win for the whole process. This is because setting os.environ, pushes values back out to process scope and when next sub interpreter is created it will pick up the value of the environment variable leaked from the other sub interpreter.

I will have to look at original Django and if this is what they are doing, then yell a people about it.

To fix, don't use setdefault. Just use '=' to set value in os.environ.

Graham
--
You received this message because you are subscribed to the Google Groups "modwsgi" group.
To view this discussion on the web visit https://groups.google.com/d/msg/modwsgi/-/uqBtTkv1h6YJ.

Benjamin Bach

unread,
Jul 3, 2012, 7:07:41 PM7/3/12
to mod...@googlegroups.com


On Wednesday, July 4, 2012 12:05:36 AM UTC+2, Graham Dumpleton wrote:


If the auto generated wsgi.py is using setdefault they have broken it very badly. When running in a multiple sub interpreter process, the first wsgi.py in any sub interpreter will win for the whole process. This is because setting os.environ, pushes values back out to process scope and when next sub interpreter is created it will pick up the value of the environment variable leaked from the other sub interpreter.

I will have to look at original Django and if this is what they are doing, then yell a people about it.

To fix, don't use setdefault. Just use '=' to set value in os.environ.

Graham

Thanks, I will try with this solution ASAP and I think indeed judging from the symptoms that this was the sole cause.

The Django people have written their documentation about WSGI here:

https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/

I think it should clearly mention that this can have harmful effects, unfortunately it doesn't, and there is a wontfix on the issue here: https://code.djangoproject.com/ticket/18518

I'll open up a ticket for the documentation instead.

Thanks again,
Benjamin

Graham Dumpleton

unread,
Jul 3, 2012, 7:39:58 PM7/3/12
to mod...@googlegroups.com
Thanks for finding that existing ticket. I have added a comment but my
state of mind right now is such that not holding much hope that
anything will be done. If they want the existing behaviour for other
systems they could provide a check for when mod_wsgi and not do that,
but highly unlikely that they would add server specific checks.

Graham

Benjamin Bach

unread,
Jul 3, 2012, 7:46:34 PM7/3/12
to mod...@googlegroups.com

Thanks for finding that existing ticket. I have added a comment but my
state of mind right now is such that not holding much hope that
anything will be done. If they want the existing behaviour for other
systems they could provide a check for when mod_wsgi and not do that,
but highly unlikely that they would add server specific checks.

Graham


I have added this ticket for the documentation:

https://code.djangoproject.com/ticket/18559

I think it's a good compromise to have it noted in the documentation if the developers have already decided that they want this rather problematic setdefault behaviour.

thanks again,
Benjamin
Reply all
Reply to author
Forward
0 new messages