Just installed and configured mod_python 3.2.8 on a CentOS 5 (Apache 2.2.3) server with Python 2.4.3. It is loaded fine by Apache.
I activated the mpinfo test page and it works. So I wrote a simple "Hello World" with the following code:
from mod_python import apache
def handler(req):
req.content_type = 'text/plain'
req.write("Hello World!")
req.flush()
return apache.OK
It outputs a blank page, with no text and no source. If I consciously create a syntax error I get the error output on the URL, for example (when I put a space before "def"):
Mod_python error: "PythonHandler mod_python.cgihandler"
Traceback (most recent call last):
File "/usr/lib/python2.4/site-packages/mod_python/apache.py", line 299, in HandlerDispatch
result = object(req)
File "/usr/lib/python2.4/site-packages/mod_python/cgihandler.py", line 96, in handler
imp.load_module(module_name, fd, path, desc)
File "/var/www/vhosts/localhost/httpdocs/mptest.py", line 3
def handler(req):
^
SyntaxError: invalid syntax
I have spent about five hours browsing different tutorials, faqs and trouble shooting guides but can't find a description of this exakt issue.
What do you think could be the issue/cause?
EDIT: Here is the Apache configuration for the site...
<Directory />
Options FollowSymLinks
AllowOverride None
AddHandler mod_python .py
PythonHandler mptest
PythonDebug On
</Directory>
EDIT 2: Ah, another thing I forgot to mention is that I intend to use mod_python to write Apache extensions. The application itself is written in PHP but I need to make some security tweeks on the server :)
Don't use mod_python.
A common mistake is to take mod_python as "mod_php, but for python" and that is not true. mod_python is more suited to writing apache extensions, not web applications.
The standartized protocol to use between python web applications and web servers (not only apache) is WSGI. Using it ensures that you can publish your application to any wsgi-compliant webserver (almost all modern web servers are wsgi-compliant)
On apache, use mod_wsgi instead.
Your example rewritten using the wsgi standard and mod_wsgi on apache:
mywebapp.py:
def application(environ, start_response):
start_response('200 OK', [('content-type', 'text/plain')])
return ['Hello World']
Apache configuration:
WSGIScriptAlias /myapp /usr/local/www/wsgi-scripts/mywebapp.py
<Directory /usr/local/www/wsgi-scripts>
Order allow,deny
Allow from all
</Directory>
Now just go to http://localhost/myapp and the script will run. Additionally, any access under this root (i.e. http://localhost/myapp/stuff/here) will be handled by this script.
It's a good idea to choose a web framework. CherryPy. Pylons. Django. They make things even easier.
A good website to look at is wsgi.org
Your original problem is that mod_python.cgihandler is being called to handle the request. This means your Python script file is being interpreted as a CGI script. Thus, no wonder it doesn't return anything.
You likely have conflicting definition in your Apache configuration which is enabling the mod_python.cgihandler.
I make a complete new answer for clarity...
I decided to install mod_wsgi instead. So I've set it up and when I go to my testfile I just see the page source. I haven't been spending any time on finding the issue yet, so I'll get back to you when I either solve the problem or decide that I need more help :)
Thank you :)
Related
I have a test django project that I have been using the django development server for. I want to start using an actual apache server to properly simulate a production environment. I am using Mac OS X.
I have been using this tutorial here, but in the first set of instructions I am getting a 403 from localhost. The browser says I do not have permission to access / on the server.
When I comment out the apache config line from the tutorial, WSGIScriptAlias / /Users/username/Projects/django_books/django_books/django.wsgi I can access localhost.
This is the contents of my django.wsgi file:
import os
import sys
os.environ['DJANGO_SETTINGS_MODULE'] = 'django_books.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
path = '/Users/username/Projects/django_books/django_books'
if path not in sys.path:
sys.path.append(path)
What is causing the 403 and why can't I see my django application?
EDIT
Directory structure:
django_books
apache (empty directory right now)
random_book
__init__.py
models.py
views.py
django_books
__init__.py
django.wsgi
settings.py
urls.py
views.py
wsgi.py
media
static
css
style.css
manage.py
2ND EDIT
Permissions on all the directories:
/Users/username/Projects/django_books/django_books/django.wsgi
-rw-r--r--
/Users/username/Projects/django_books/django_books
drwxr-xr-x
/Users/username/Projects/django_books/
drwxr-xr-x
/Users/username/Projects/
drwxr-xr-x
/Users/username/
drwxr-xr-x+
/Users/
drwxr-xr-x
According to my small experience I think you must add the following lines "just below the import sys line to place your project on the path" (so juste under "import sys") like it's said in the tutorial you quote. Also, erase the second "django_books" in your path because you want to link to your site not the app in your site ;-) ("mysite" in the tutorial, not mysite/mysite)
import os
import sys
path = '/Users/username/Projects/django_books'
if path not in sys.path:
sys.path.append(path)
os.environ['DJANGO_SETTINGS_MODULE'] = 'django_books.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
Bye
It's likely an issue related either to your Apache installation, python library, or the filesystem's permissions.
Testing Apache
You don't say it in your question, but I assume from your link you are working with Apache2 and mod_wsgi.
You can test if Apache and mod_wsgi (or your wsgi module) are working properly by placing a dummy wsgi script in the place of django.wsgi . This script (stolen from mod_wsgi's docs) doesn't rely on Django and helps make sure that Apache can read and execute the wsgi script:
# test version of django.wsgi
def application(environ, start_response):
status = '200 OK'
output = 'Hello World!'
response_headers = [('Content-type', 'text/plain'),
('Content-Length', str(len(output)))]
start_response(status, response_headers)
return [output]
And restart apache
sudo service apache2 restart
Go ahead and test the page. Did it work? Great. Undo the changes to the django.wsgi script, restart Apache and test again. If the Django site still doesn't work, we need to keep looking. If the test script didn't work, there may be a problem with your Apache installation. Check apache's error log for more information about what happened. On linux it's commonly at /var/log/apache2/error.log . mod_wsgi could be improperly installed, the script's daemon may not have appropriate permission to the wsgi file.
Correcting permission errors
Apache may not be able to read and execute the wsgi file. Running ls -l in the wsgi file's directory as indicated in other answers will tell you the user and group a file belongs to (and if that user and group can read, write, or execute a given file). It's common for a default installation to have the wsgi permissions like so:
-rw------- 1 www-data www-data 1470 Aug 29 16:00 django.wsgi
If you want to use a different user for the daemon process, you need to make sure that the apache conf file defines WSGIDaemonProccess
WSGIScriptAlias / /Users/username/Projects/django_books/django_books/django.wsgi
WSGIDaemonProcess wsgi_user processes=2 threads=15 display-name=%{GROUP}
WSGIProcessGroup wsgi_group
Testing changes to these files and restarting Apache can help narrow down what's up. Keep checking the Apache log files.
Apache Configuration
Django's tutorial on setting up mod_wsgi is good, but read through mod_wsgi's wiki as well. There are a lot of helpful things to consider in your apache conf file besides WSGIScriptAlias. Make sure there is a tag pointing to the folder with your wsgi file. If there are non-public files (like django project files) in that directory, either use the apache directory (update your apache conf file) or add a tag under the node to keep those other files private. While you're in there, you may notice other things that look wrong, like an improperly configured servername, multiple virtual hosts, or other errors.
Testing Python
If you're using virtualenv (do it), make sure that
1. The WSGIDaemonProcess variable defines the appropriate site-packages and the wsgi script's location in the variable's python-path attribute
2. The daemon has rights to read the site packages in your virtualenv.
3. Your wsgi script properly imports django and your site's settings.
Logging Apache
You can increase the level of logging reported by Apache by adding a few lines to your Apache conf file. This setup gives you very verbose logging that you may want during deployment (make sure to make a log folder):
LogLevel info
ErrorLog /Users/username/Projects/django_books/logs/apache_error.log
CustomLog /Users/username/Projects/django_books/logs/apache_access.log combined
I would suspect that the www-data (or whatever user apache is running as) doesn't have access to /Users/username/Projects/django_books/django_books.
su to that user and try and access that directory and the wsgi file within it.
To print all the relevant permissions:
ls -ld /Users /Users/username /Users/username/Projects /Users/username/Projects/django_books /Users/username/Projects/django_books/django_books /Users/username/Projects/django_books/django_books/django.wsgi
You should also check the apache error logs, they might tell you what is going wrong.
i'm trying to install django on a local test server [i know python+django has one] and i've already set up xampp hosting:
Apache 2.4, Python 2.7, mod_wsgi (compiled from source: https://code.google.com/p/modwsgi/wiki/InstallationOnWindows and using win32-ap22py27.mk, idk if the make file I used is okay since there are no errors upon starting apache and apache says it loads the wsgi module as well as my python)
wsgi.conf [that is included in httpd.conf]:
WSGIScriptAlias /wsgi "C:/xampp/htdocs/wsgi/scripts/test.wsgi"
AddHandler wsgi-script .wsgi
<Directory "C:/xampp/htdocs/wsgi/scripts">
Order deny,allow
Allow from all
</Directory>
and a generic test.wsgi file:
def application(env, start_response):
start_response("200 OK", [])
output = "<html>Hello World! Request: %s</html>"
output %= env['PATH_INFO']
return [output]
My problem is that I get an aborted connection on testing a wsgi app: **http://localhost/wsgi**
i've searched the internets and no luck
okay there must be something wrong with the make file and so therfore module
here if anyone interested(bookmark this thing):
http://www.lfd.uci.edu/~gohlke/pythonlibs/#mod_wsgi
using apache2.4 and python2.7 compatible mod_wsgi3.4 and now it works...
This topic is useful for Windows 10, xampp webserver as well.
I was struggling to find precompiled mod_wsgi.so for
Apache/2.4.27 (Win32)
Python/2.7.13
This [link][1] is useful to find the appropriate version of mod_wsgi.
IF you are lucky, you can find the precompiled version [here][1]
There is a step by step guidance available [here][1]
enter code here
[1]: https://github.com/GrahamDumpleton/mod_wsgi/blob/develop/win32/README.rst
[2]: http://www.lfd.uci.edu/~gohlke/pythonlibs/#mod_wsgi
[3]: https://everything2.com/title/Installing+Python+on+XAMPP
I am trying to run webapp2 under Python with Apache and mod_wsgi - specifically: Wampserver for Windows 7 with Apache 2.2.22. So far, I have failed miserably. :-(
I used the following example from https://developers.google.com/appengine/docs/python/gettingstartedpython27/usingwebapp:
import webapp2
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write('Hello, webapp World!')
app = webapp2.WSGIApplication([('/', MainPage)],
debug=True)
When I save this file as c:wamp\www\Python\hello.py, and browse to localhost/Python/hello.pyI get:
Not Found
The requested URL /python/hello.py was not found on this server.
However, let me state that mod_wsgi for Python within Apache seems to be running fine; the following code
def application(environ, start_response):
status = '200 OK'
output = 'Hello from Python!'
response_headers = [('Content-type', 'text/plain'),
('Content-Length', str(len(output)))]
start_response(status, response_headers)
return [output]
is located at c:\wamp\www\Python\test.py. When I go to localhost/Python/test.py, the browser says Hello from Python! as I would expect.
So far, I have only found out how to change the default name of the def (="application") to "something_else" by putting the line
WSGICallableObject something_else
into .htaccess.
But how can I get Apache to accept the variable app as a callable object? (So far, I have used Python mainly for programming outside of the web, so I hope this is not a dumb question.)
Any help is appreciated.
Update:
Graham asked me about the mod_wsgi configuration I am using in Apache configuration files and where I am adding it. I added
LoadModule wsgi_module modules/mod_wsgi.so
<Directory "c:/wamp/www/python">
Options +ExecCGI
AddHandler wsgi-script .py
Order allow,deny
Allow from all
</Directory>
to httpd.conf right at the end of all the "LoadModule" lines.
Some additional info on my configuration: I am using mod_wsgi-win32-ap22py27-3.3.so. (Of course I renamed it to mod_wsgi.so and placed it into c:\wamp\bin\apache\apache2.2.22\modules.) My Python command line says this about the version: Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win
32. The wamp server I am using is 32 bit. My operating system is Windows 7 Ultimate 64bit SP1.
Hope this helps with the diagnosis...
Install mod_wsgi from http://code.google.com/p/modwsgi/wiki/InstallationOnWindows and configure your httpd.conf properly.
I assume you have already added these 2 lines:
LoadModule wsgi_module modules/mod_wsgi.so
WSGICallableObject app
Install py-setuptools from http://pypi.python.org/pypi/setuptools then install Modules for your python
easy_install WebOb
easy_install Paste
easy_install webapp2
Create virtualhost
<VirtualHost *>
ServerAdmin admin#mydomain.com
DocumentRoot "/vhost/domains/mydomain/htdocs"
ServerName a.mydomain.net
WSGIScriptAlias / "/vhost/domains/mydomain/wsgi/main.py"
Alias /static/ "/vhost/domains/mydomain/htdocs/static/"
</VirtualHost>
File: main.py
import webapp2
class Hello(webapp2.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
self.response.out.write('hello world!')
application = webapp2.WSGIApplication([
('/', Hello)
], debug=True)
1) You need to install webapp2, WebOb, Paste prerequisites modules on hosting environment using pip or easy_install
2) Create wsgi.py file under website’s root folder (/var/www/website/wsgi.py).
#/var/www/website/wsgi.py
import webapp2
class Index(webapp2.RequestHandler):
def get(self):
output = 'webapp2 running on apache2'
self.response.headers = [('Content-type','text/plain'),('Content-length',str(len(output)))]
self.response.out.write(output)
application = webapp2.WSGIApplication([('/',Index)], debug=True)
3) Create apache2 configuration file under sites-available folder (/etc/apache2/sites-available/website.conf)
<VirtualHost *:80>
ServerName website
WSGIScriptAlias / "/var/www/ website /wsgi.py"
</VirtualHost>
4) Add “website” alias to “/etc/hosts” file.
5) Run following command to enable “/etc/apache2/sites-available/website.conf”
a2ensite website.conf
6) Reload and restart apache2 web server
service apache2 reload
/etc/init.d/apache2 restart
7) Apache web-server will automatically load “website” configuration on restart webapp2.WSGIApplication instance will point to mod_wsgi "application".
Please note above example is tested on an Ubuntu 13.10 operating system.
Have you not tried:
WSGICallableObject app
You could also change your code to say:
application = webapp2.WSGIApplication([('/', MainPage)], debug=True)
and avoid needing to tell mod_wsgi to look for a different name.
I haven't tried it myself just yet, but have you created another Python module, say runme.py, with the following code:
def main():
run_wsgi_app(yourmodule.app)
if __name__ == '__main__':
main()
(Note: I got this from https://developers.google.com/appengine/docs/python/python27/migrate27#wsgi
Got it! The line
app = webapp2.WSGIApplication([('/', MainPage)], debug=True)
should be:
app = webapp2.WSGIApplication([('/Python/hello.py', MainPage)], debug=True)
and then everything works! Arghh!
Many thanks to Graham for patiently pushing me in the right direction: The problem was indeed within the bounds of webapp2, as soon as WSGICallableObject was set to "app"!
For the benefit of anyone being stuck on a similar routing problem with webapp2: Check out http://webapp-improved.appspot.com/guide/routing.html. The first example on "simple routes" made me rewrite my call to webapp.WSGIApplication within minutes!
Update
Unfortunately, the above solution doesn't seem to be reliable: Today, I sometimes got a correct response from webapp2, and sometimes I got a 404 from webapp2.
Without changing a single line of code since yesterday.
I can't reproduce under what condition I get the 404 or the correct response. I am giving up on this for now. Which is sad, since I think that Python is such a cool language.
#Graham: Again, thanks for your help.
I am a beginner programmer. I started using Python and Bottle for a small web app to print a form, so far so good. The real issue is configuring Apache and mod_wsgi, as my knowledge is almost none.
My problem: I keep getting this error:
Error 404: Not Found
Sorry, the requested URL /factura/ caused an error: Not found
In work they gave me and address redirecting to a IP:port; after some days of reading Apache docs and looking examples through the web I managed to set up the configuration so my VirtualHost doesn't breaks the others virtualhosts already running. The config looks like this (based on the bottle tutorial deployment section):
Listen port
NameVirtualHost IP:port
<VirtualHost IP:port>
ServerName IP:port
WSGIDaemonProcess factura processes=1 threads=5
WSGIScriptAlias / /var/www/factura/app.wsgi
<Directory /var/www/factura>
WSGIProcessGroup factura
WSGIApplicationGroup %{GLOBAL}
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
My app.wsgi is almost the same as the one in the Bottle tutorial-deployment section. I only added the line sys.stdout = sys.stderr:
import sys, os, bottle
# Change working directory so relative paths (and template lookup) work again
sys.path = ['/var/www/factura'] + sys.path
os.chdir(os.path.dirname(__file__))
# Error output redirect
# Exception KeyError in 'threading' module
sys.stdout = sys.stderr
import factura
application = bottle.default_app()
Here is a bit of the python code which is related to Bottle:
from lib import bottle
app = bottle.Bottle()
#serves files in folder 'static'
#app.route('/static/:path#.+#', name='static')
def ...
#app.route("/factura")
#bottle.view("factura")
def ...
#app.route("/print_factura", method="POST")
def ...
I have read some of the others question similar to this, but I can't manage to see what I'mm missing. I suppose the problem is in app.wsgi?
UPDATE
file structure
/var/www/factura/ ## .py files
/views ## here is the web template
/static ## .css and .js of template
/lib ## package with bottle and peewee source files
/data ## inkscape file to play with
/bin ## backup stuff in repo, not used in code
Apache error log only shows
Exception KeyError: KeyError(-1211426160,) in <module 'threading' from '/usr/lib/python2.6/threading.pyc'> ignored
that is a warning from wsgi/python issues, harmless by wsgi issue 197
UPDATE 2 working
added #app.route("/factura/") notice the trail slash, that with the change in app import from factura import app as application those two together made it work
If you create your application explicitly:
app = bottle.Bottle()
then you should import it in your app.wsgi instead of application = bottle.default_app():
from factura import app as application
But what is far important is this. In your WSGI file, you do import bottle, yet in the app code file, you do from lib import bottle. As you have explained, you have two copies of Bottle: one installed server-wide, another under the lib directory.
That's why you were receiving 404 Not Found. You were actually working with one instance of the library (creating app), and then giving Apache a different (default_app) from a different instance of the library!
It started to work okay when you began to return the proper app.
I am running a Python script on Apache 2.2 with mod wsgi.
Is it possible to run pdb.set_trace() in a python script using daemon mode in wsgi?
Edit
The reason I want to use daemon mode instead of embedded mode is to have the capability to reload code without having to restart the Apache server every time (which embedded mode requires). I would like to be able to use code reloading without restarting Apache everytime and still be able to use pdb...
I had the same need to be able to use the amazingly powerful pdb, dropping a pdb.set_trace() wherever I wanted to debug some part of the Python server code.
Yes, Apache spawns the WSGI application in a place where it is out of your control [1]. But I found a good compromise is to
maintain your Apache WSGIScriptAlias
and also give yourself the option of starting your Python server in a terminal as well (testing locally and not through Apache anymore in this case)
So if one uses WSGIScriptAlias somewhat like this...
pointing to your python WSGI script called webserver.py
<VirtualHost *:443>
ServerName myawesomeserver
DocumentRoot /opt/local/apache2/htdocs
<Directory /opt/local/apache2/htdocs>
[...]
</Directory>
WSGIScriptAlias /myapp /opt/local/apache2/my_wsgi_scripts/webserver.py/
<Directory /opt/local/apache2/my_wsgi_scripts/>
[...]
</Directory>
[...]
SSLEngine on
[...]
</VirtualHost>
And so your webserver.py can have a simple switch to go between being used by Apache and getting started up for debugging manually.
Keep a flag in your config file such as, in some settings.py:
WEBPY_WSGI_IS_ON = True
And webserver.py :
import web
import settings
urls = (
'/', 'excellentWebClass',
'/store', 'evenClassier',)
if settings.WEBPY_WSGI_IS_ON is True:
# MODE #1: Non-interactive web.py ; using WSGI
# So whenever true, the Web.py application here will talk wsgi.
application = web.application(urls, globals()).wsgifunc()
class excellentWebClass:
def GET(self, name):
# Drop a pdb wherever you want only if running manually from terminal.
pdb.set_trace()
try:
f = open (name)
return f.read()
except IOError:
print 'Error: No such file %s' % name
if __name__ == "__main__":
# MODE #2: Interactive web.py , for debugging.
# Here you call it directly.
app = web.application(urls, globals())
app.run()
So when you want to test out your webserver interactively, you just run it from a terminal,
$ python webserver.py 8080
starting web...
http://0.0.0.0:8080/
[1] Footnote: There are some really complex ways of getting Apache child processes under your control, but I think the above is much simpler if you just want to debug your Python server code. And if there are actually easy ways, then I would love to learn about those too.