views:

319

answers:

2

I'm using nginx as a reverse proxy to apache/mod_wsgi and Django. Currently everything is working fine with / aliasing my wsgi file, and /media aliasing my media directory. However, I want to set it up so that /media/foo/bar also aliases my wsgi file such that /media/foo/example.txt will serve example.txt with apache, but /media/foo/bar/example.txt will be passed along to my urls.py in Django.

I've tried adding another WSGIScriptAlias to my apache.conf above my Alias for /media/, but /media/foo/bar/example.txt is still being served by apache. My apache.conf currently looks like this:

<VirtualHost *:8080>
    #DocumentRoot /var/www/mydomain.com/public
    ServerName mydomain.com
    ErrorLog /var/www/mydomain.com/logs/apache_error_log
    CustomLog /var/www/mydomain.com/logs/apache_access_log common

    WSGIScriptAlias /media/foo/bar /var/www/mydomain.com/src/myproject/server/django.wsgi
    Alias /media/ /var/www/mydomain.com/public/media/
    <Directory /var/www/mydomain.com/public/media>
        Order deny,allow
        Allow from all
    </Directory>

    WSGIScriptAlias / /var/www/mydomain.com/src/myproject/server/django.wsgi

    <Directory /var/www/mydomain.com/src/myproject/server>
        Order allow,deny
        Allow from all
    </Directory>
</VirtualHost>
+1  A: 

The quick hack would be to move mod_wsgi ahead of mod_alias in your Apache config, but that would actually result in /media being processed by your Django app instead.

If AliasMatch supports lookahead regexps you should be able to do this:

AliasMatch /media/(?!foo) …

That should avoid this problem - that said, I'm tempted to recommend serving media from another hostname (media.example.org) since that gets some nice client performance benefits due to parallelism and simplifies server optimization questions.

Chris Adams
Changing the order of LoadModule line for mod_alias and mod_wsgi in Apache configuration when using Apache 2.X will not make any difference. Neither will changing the order of Alias and WSGIScriptAlias directives. This is because mod_wsgi always defers to mod_alias directives regardless of order. It is only in Apache 1.3 where order matters in LoadModule lines and that is because Apache 1.3 didn't have a means for modules internally to define the precedence order in respect to other modules.
Graham Dumpleton
Turns out the lookahead negation didn't actually work. It failed to match /media/foo, but then it also failed to match anything else... Still working on finding a workable solution.
Josh Ourisman
+2  A: 

Because Alias and WSGIScriptAlias are at different precedence levels, you cannot create a multi level overlapping set of URLs of more than 2 levels which alternates between use of them. The solution is to use Alias/AliasMatch directives for all sub URLs, that way they are evaluated at same level of precedence. One can still use WSGIScriptAlias for root of site.

Thus try using following with directives in order such that most nested URL patterns earlier than outer URLs.

<VirtualHost *:8080>
#DocumentRoot /var/www/mydomain.com/public
ServerName mydomain.com
ErrorLog /var/www/mydomain.com/logs/apache_error_log
CustomLog /var/www/mydomain.com/logs/apache_access_log common

AliasMatch ^/(media/foo/bar/.*) /var/www/mydomain.com/src/myproject/server/django.wsgi/$1
Alias /media/ /var/www/mydomain.com/public/media/
WSGIScriptAlias / /var/www/mydomain.com/src/myproject/server/django.wsgi

<Directory /var/www/mydomain.com/src/myproject/server>
    Options ExecCGI
    AddHandler wsgi-script .wsgi
    # WSGIApplicationGroup %{GLOBAL}
    Order allow,deny
    Allow from all
</Directory>

<Directory /var/www/mydomain.com/public/media>
    Order deny,allow
    Allow from all
</Directory>
</VirtualHost>

The AliasMatch is used for the most nested as we need to adjust the value of SCRIPT_NAME, ie., mount point, seen by Django application so that request still seems to be for Django instance mounted at root. If don't do that, urls.py patterns will not work as you expect for that sub URL. Use of AliasMatch and adding matched sub pattern to RHS after script path using $1 achieves that.

Although Django mounted via two different directives, calculated SCRIPT_NAME should be same for both and so same Python sub interpreter should be used. If for some reason you think your memory use is twice what you expect, ie., two instances of Django running in different sub interpreters, you can force them to run in same by uncommenting WSGIApplicationGroup directive above. This shouldn't be required though and if think you do need it, better off going to mod_wsgi mailing list and can instruct you on how to verify whether doing as it should be and what is wrong.

Graham Dumpleton
Ok, this works! I did have to make one change however, I just had to add a trailing slash to the Alias / like this: Alias / /var/www/mydomain.com/src/myproject/server/django.wsgi/Without that it would try and go to /var/www/mydomain.com/src/myproject/django.wsgifavicon.ico and fail.
Josh Ourisman
Odd, the Alias and ScriptAlias behave different to each other for root of site and different again to WSGIScriptAlias. I may be able to fix up mod_wsgi to cope with where ScriptAlias used for root of site but mapped to mod_wsgi, but if Alias used then doesn't even come through to mod_wsgi unless that trailing slash added as you point out. Anyway, I have changed example to use WSGIScriptAlias for root of site and only use Alias directives for sub URLs. That then works without needing the trailing slash you had to add.
Graham Dumpleton