How does mod_wsgi know and execute the application? - django

I'm tying to setup Apache/2.2.22 (Debian) mod_wsgi/3.3 Python/2.7.3
I manage to get the WSGIScriptAlias executed, but only the top level module code, not the application defined therein.
Apache configuration:
LoadModule wsgi_module /usr/lib/apache2/modules/mod_wsgi.so
WSGIScriptAlias /testurl /home/django/test/test/wsgi_test.py
<Directory /home/django/test/test>
<Files wsgi_test.py>
Order deny,allow
Allow from all
</Files>
</Directory>
wsgi_test.py:
#!/usr/bin/python
import sys
print >> sys.stderr, "I'm wsgi_test"
def application(environ, start_response):
print >> sys.stderr, 'in application'
status = '200 OK'
output = 'hello World'
response_headers = [('Content-type', 'text/plain'),
('Content-Length', str(len(output)))]
start_response(status, response_headers)
return [output]
When requesting the url using a browser the wsgi_test.py script gets executed ("I'm wsgi_test" appearing in the apache error log). However, no page is served (500 internal server error) and there is an additional error log entry Premature end of script headers: wsgi_test.py.
As a second test, I used a simple script, which correctly serves 'Hello World':
wsgi_test2.py:
#!/usr/bin/python
import sys
print 'Content-type: text/plain\n\n'
print 'Hello World'
My question:
How does mod_wsgi know and execute the application?
From the above tests, I conclude that wsgi_test.py is immediately executed. Since there is no executable code but only a definition of application, the script does not output anything and thus the server complains about the missing html headers. How do I tell the system to run the application?

The mod_wsgi module does not execute the script in the way that you are likely thinking. That is, it doesn't run them as a program.
Your Apache configuration is likely setup so that files with .py extension are being executed as a CGI script and so this is not actually being handled by mod_wsgi. This would explain the behaviour you are seeing.
Either disable AddHandler directive which makes .py files CGI scripts, or rename your WSGI scripts to have a .wsgi extension and change the WSGIScriptAlias directive to match.
When this is done, then mod_wsgi will load the WSGI script into memory and then run the Python code in the memory of the server processes. So not as a separate program execution.
If you ensure that the LogLevel directive in Apache is set to info if currently set to warn, then you should see a lot more messages logged by mod_wsgi about when it is loading the WSGI script to run it the first time. This will confirm that mod_wsgi is handling them.

Related

XAMPP with WSGI not rendering django page

I am trying to run django on XAMPP Apache server and followed the steps mentioned here. Here are the changes in Apache config:[![enter image description here][1]][1]
When access the application in browser below is the result instead of django page:
[![enter image description here][2]][2]
Please help what I am missing in this ?
#Razenstein: Following are errors in Apache log:
AH02102: C:/xampp/htdocs/polls/mysite/mysite/wsgi.py is not executable; ensure interpreted scripts have "#!" or "'!" first line (9)Bad file descriptor: [client 127.0.0.1:58357] AH01222: don't know how to spawn child process: C:/xampp/htdocs/polls/mysite/mysite/wsgi.py
The application is running fine with built in python server. After correcting Alias getting "500 | Internal Server Error"
[1]: https://i.stack.imgur.com/w2R0Y.png
[2]: https://i.stack.imgur.com/vl8Da.png
ok, this error message says that Apache tries to execute wsgi.py as a cgi script and not as python. A possible reason is, that you tried to deploy your app on Apache with some wrong commands that are still in the httpd.conf or vhosts-httpd.conf. This typically happens if you follow one (bad?) tutorial without success, switch to another one and forgot to clean the the code from the first trial (only a guess!). There is all kinds of strange turorials out there and sometimes it is also difficult to understand if they are for Windows or Unix.
Something like the follwing would cause that behavior:
Alias / C:/xampp/htdocs/polls/mysite/mysite/wsgi.py
<Directory C:/xampp/htdocs/polls/mysite/mysite>
Options +ExecCGI
AddHandler cgi-script .cgi .pl .asp .py
Require all granted
</Directory>
please search in your httpd.conf and vhosts-httpd.conf if you have left something similar.
your "WSGIScriptAlias ...." is overwritten by that and not active.

How I can run /myapp/my_app.py by default when accessing `localhost` using Bottle?

Desired Behaviour
I want to serve content created by the file at:
/myapp/my_app.py
when accessing localhost.
Question
I know that if I add the following to test.py and run the file directly, the results will be accessible at localhost:8080:
from bottle import route, run
#route('/')
def hello():
return "Hello World!"
run(host='localhost', port=8080, debug=True)
But how do I trigger this file to run by default when accessing localhost?
Environment
Linux Mint 17
MongoDB
RockMongo (Apache2, PHP, MongoDB Driver)
What I've Tried
I installed mod_wsgi and created /var/www/html/myapp/app.wsgi with this content:
import bottle
import os
os.chdir(os.path.dirname(__file__))
#route('/')
def hello():
return "Hello World!"
application = bottle.default_app()
And then restarted Apache.
But going to localhost just shows a file directory.
I then created /etc/apache2/sites-enabled/mygreatapp.conf with this content:
<VirtualHost *>
ServerName google.com
WSGIScriptAlias / /var/www/html/myapp/app.wsgi
<Directory /var/www/html/myapp>
WSGIProcessGroup yourapp
WSGIApplicationGroup %{GLOBAL}
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
But I still just see a file directory.
Official Instructions
http://bottlepy.org/docs/dev/deployment.html#apache-mod-wsgi
Further Information
Troubleshooting
See if mod_wsgi is loaded
apache2ctl -M
...
wsgi_module (shared)
Definitions
For my own reference, I'm trying to fully comprehend several elements that I think are involved in the process, feel free to correct if my understandings are wrong:
WSGI - A convention for how applications should communicate with servers.
It does not exist anywhere else other than as words in the PEP 3333 - Source
mod_wsgi - An Apache module that allows Python files to communicate with Apache.
Web Framework - See a list of them here: https://wiki.python.org/moin/WebFrameworks
Web Server - http://en.wikipedia.org/wiki/Web_server
Apache Server - http://en.wikipedia.org/wiki/Apache_HTTP_Server
I finally have "Hello World!" displaying in the browser at localhost.
I will paste the various required configs and files below.
I'm a newb so I don't know if this is definitive or best practise.
/var/www/html/myapp/app.wsgi
# view the effect of import method:
http://stackoverflow.com/a/2452639/1063287
import bottle
import os
os.chdir(os.path.dirname(__file__))
# note i am using bottle.route and not just route
#bottle.route('/')
def hello():
return "Hello World!"
application = bottle.default_app()
/etc/apache2/sites-available/000-default.conf (note: this is the default .conf file)
<VirtualHost *:80>
ServerAdmin webmaster#localhost
DocumentRoot /var/www/html
WSGIScriptAlias / /var/www/html/myapp/app.wsgi # just added this
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Viewing the Apache error log is what eventually led me to try a few different things:
sudo tail -100 /var/log/apache2/error.log
Where I saw things like:
Exception occurred processing WSGI script '/var/www/html/myapp/app.wsgi'.
Traceback (most recent call last):
File "/var/www/html/myapp/app.wsgi", line 8, in <module>
#route('/')
NameError: name 'route' is not defined
This was only after I had made the step of not using a new .conf file and just modifying the default one.
So for some reason it didn't like any new .conf files.

Apache/mod_wsgi daemon mode not working

I have problems getting mod_wsgi to run in daemon mode on my Debian/Apache/Python2.6/Django setup. In my virtual host config file I have
<VirtualHost *:80>
ServerName mysite.com
WSGIDaemonProcess mysite.com processes=2 threads=15
WSGIProcessGroup mysite.com
WSGIScriptAlias / /path/to/mysite/wsgi/django.wsgi
<Directory /path/to/mysite/wsgi/>
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
set up. To test activation of daemon mode, I use this wsgi script:
import sys
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
def application(environ, start_response):
print >> sys.stderr, 'mod_wsgi.process_group = %s' % repr(environ['mod_wsgi.process_group'])
from django.core.handlers.wsgi import WSGIHandler
_application = WSGIHandler()
return _application(environ, start_response)
and the resulting log file always says:
mod_wsgi.process_group = ''
which, accroding to the documentation, indicates that daemon mode is not being used. I checked my setup multiple times, the versions of Apache, mod_wsgi and Python are matching and my setup is correct according to all the HOWTO's I've read out there. What could I be missing?
Edit: FYI my application is running fine in embedded mode, I just wanted to switch to daemon mode and found out it is not activated using the wsgi script above.
It turned out that a symlink wasn't set correctly so my config changes never loaded in Apache. Sorry for wasting your time, I thought I checked everything thoroughly before posting.
The line mod_wsgi.process_group = '' implies that you are still operating in embedded mode (as you note). mod_wsgi daemon mode will not work on Apache 1.x so I assume that you are running 2.x (as you also note).
You could try setting the apache
LogLevel info
so that there is more helpful information in the log file. I'm also assuming that you've forced apache to restart
# /etc/init.d/apache2 restart
this shouldn't be necessary in daemon mode so much, but if you were in embedded mode previously you will need to reload your config files.

Apache hangs with mod_wsgi + django

I have had Apache + mod_wsgi + django running. For some reason, something has changed on the server and now apache completely hangs--it stops responding to all other requests and has to be stopped and started--when I post a request. Eventually we see a "Premature end of script headers: django.wsgi" error.
We did a strace and one thing I saw that seemed suspicious was "GATEWAY_INTERFACE\0CGI/1.1\0SERVER_PROTOCOL..." (We also see a shutdown being issued.)
Is "GATEWAY_INTERFACE\0CGI/1.1" specifying that it is set up for CGI rather then WSGI? (I have read that premature end of script can results if it is set as CGI.)
Our virtualhost specifies:
WSGIDaemonProcess [host] threads=25
WSGIProcessGroup [host]
WSGIScriptAlias / /path/to/apache/django.wsgi
and I see nothing to do with CGI in the httpd.conf just loading the WSGI module.
Here, try this one:
http://www.foxhop.net/django-virtualenv-apache-mod_wsgi
Remember to add python and project paths to syspath.

Apache Permission for a bat file w/ Django

I have seen a lot of similar questions, but still i am failing. I have win XP, Apache 2.2, Django 1.4, Python 2.7 and mod_wsgi 3.3. All i am trying to do is when you hit the page the bat file executes and which echoes hi. This works when i run it on the django internal dev server. But when i got to Apache, it fails and in the error.log i get the message
The system cannot write to the specified device.
The system cannot write to the specified device.
The system cannot write to the specified device.
The system cannot write to the specified device.
The system cannot write to the specified device.
I have not seen that error in many other places. Most people seem to get "Permission denied". I still think the permissions are wrong. So when i run it is the django internal server i get in the console:
Validating models...
0 errors found
Django version 1.4, using settings 'testsite.settings'
Development server is running at http:`//127.0.0.1:8000/
Quit the server with CTRL-BREAK.
C:\Sites\cprm>echo hi
hi
[18/Sep/2012 14:58:45] "GET / HTTP/1.1" 200 63
That seems fine. The only thing throwing me off that I'm running from /testsite and not /cprm. I could just cd .. before. Anyway, so since in the internal server it is writing to the console, i guess i need to do the equivalent in apache. I'm not sure where the apache console is. I tried adding permission to the apache log file as that is where the error gets generated. I'm not sure that is equivalent to the regular console.
My Apache file looks like this (ignore back ticks):
<`VirtualHost *>
ServerName http://example.com:80
WSGIScriptAlias /cprm "C:/sites/cprm/wsgi.py"
WSGIScriptAlias /testsite "C:/sites/testsite/wsgi.py"
<Directory "C:/sites">
AllowOverride None
Options None
Order allow,deny
Allow from all
</Directory>
<Directory "C:/Program Files/Apache Software Foundation/Apache2.2/logs">
AllowOverride None
Options None
Order allow,deny
Allow from all
</Directory>
<`/VirtualHost>
My view just looks like this:
from django.http import HttpResponse
import datetime, os
def home(request):
os.system('C:/Sites/testsite/testsite/test.bat')
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)
It's basically just a quick test I tried doing.
EDIT
Hi pacha. Thanks for the response. I have done some reading on the topic now. So I made the changes you indicated. My wsgi.py file looks like such:
import os, sys
path = 'C:/Sites/testsite'
if path not in sys.path:
sys.path.append(path)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testsite.settings")
sys.stdout = sys.stderr
print 'hi'
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
Then when i go to error.log, i do in fact see 'hi' printed. So that is good. However, the test.bat file w/ the echo hello does not execute and i still get the same message. And thanks for the permission advice. I am now no longer using virtual. I am not ready for that yet. Any other ideas for what I could try?
Things to check
Permissions what are the user permissions on the file
C:/Sites/testsite/testsite/test.bat?
Are they read for the same user that is running the Apache Process?
Have you installed python for all logged in users not just for?
Have you reviewed your Apache conf directives?
User/Group: The name (or #number) of the user/group to run httpd as.
It is usually good practice to create a dedicated user and group for
running httpd, as with most system services.
User carlos
Group Administrators
Does that same user have permissions to read the file on the file system?
<Directory "C:/Sites/testsite/testsite/">
AllowOverride None
Options None
Order deny,allow
Allow from all
</Directory>
Your problem seems to be related to how the standard output is handled. WSGI disables standard output by default. That's why your program works fine in the development server (which redirects the output to the terminal where the server was launched) but doesn't work with Apache.
You can enable stdout in WSGI using a configuration directive that you put in your virtual host conf file (together with the other WSGI directives):
WSGIRestrictStdout Off
However, take into account that Apache isn't associated to any terminal. If you want to see the output of your program then one thing you can do is to redirect the standard output to the standard error stream by adding this to your WSGI file:
sys.stdout = sys.stderr
Restart Apache an you should see any output of your application (or any child process, as it is your case) in the error.log file of Apache.
Note: Don't add the Apache log files directory to your virtual host configuration. You aren't granting permissions to Apache over those files but allowing anyone to see them, which is as you can imagine a non-trivial security risk.
Update
Avoiding permission problems
You may want to try to use WSGI in daemon mode. That way the web application can be executed under your username (much like when using the internal development server). In your case, the configuration directives should be something along the lines:
WSGIDaemonProcess site1 user=<USERNAME> group=<GROUP> processes=1 threads=1
WSGIScriptAlias /testsite "C:/sites/testsite/wsgi.py"
<Directory "C:/sites/testsite/">
WSGIProcessGroup site1
WSGIApplicationGroup %{GLOBAL}
Order allow,deny
Allow from all
</Directory>
You have to substitute <USERNAME> and <GROUP> by your username and group in your Windows machine (it may work by just setting the username though). This is usually a nice way of avoiding permission issues since your application will be executed in a very similar way to how it is executed by the development server. (Notice that we're using just one process and one thread just to make Apache behave even more closely to how the development server does. You surely want to change those values in production to higher values).
You can check the daemon mode documentation here
Executing your script
To call external program from Python code, the module subprocess is usually preferred over os.system calls. The former allows you to have much more control over how the new process has to be executed whereas the later just passes the call to the operating system.
You can try the subprocess.check_output function. It executes a script/program and allows you to capture its output:
print subprocess.check_output(['C:\Sites\testsite\testsite\test.bat'], shell=True)
It has the additional advantage that you can capture the output in a string variable. (Btw, you may or may not need the shell=True param in Windows when calling a bat script, I'm not sure about that).