Apache/mod_wsgi daemon mode not working - django

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.

Related

Django Apache2 VirtualEnv - no response from server

So I am trying to migrate my app to a new production server. I'm not getting a reply from the server Apache server when I access it. The server is on AWS and it's a standard Apache config with just one site enabled:
<VirtualHost *:80>
Alias /static/ /home/ubuntu/myapp/myapp/myapp/static
Alias /media/ /home/ubuntu/myapp/myapp/myapp/media
<Directory /home/ubuntu/myapp/myapp/myapp/static>
Require all granted
</Directory>
<Directory /home/ubuntu/myapp/myapp/myapp/media>
Require all granted
</Directory>
<Directory /home/ubuntu/myapp/myapp/myapp>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
WSGIDaemonProcess myapp python-home=/home/ubuntu/myapp/myapp/myapp python-path=/home/ubuntu/myapp:/home/ubuntu/myapp/lib/python3.6/site-packages
WSGIProcessGroup myapp
WSGIScriptAlias / /home/ubuntu/myapp/myapp/myapp/myapp/wsgi.py
ErrorLog /var/log/apache2/myapp_error.log
LogLevel warn
CustomLog /var/log/apache2/myapp_access.log combined
</VirtualHost>
I have made sure that all files are owned by the ubuntu user and that www-data has group rights.
The wsgi file is the original, but I added a print statement to see the folder it's checking for the application:
"""
WSGI config for match2 project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
"""
import os, sys
print(sys.path)
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
application = get_wsgi_application()
Eventually, the error log will produce:
Timeout when reading response headers from daemon process 'myapp': /home/ubuntu/myapp/myapp/myapp/myapp/wsgi.py
I'd appreciate any advice.
Timeout when reading response headers from daemon process 'myapp' means your application is taking to long to handle the request. This could be because it is deadlocked, or is waiting on backend service.
Add WSGIApplicationGroup to your virtual host configuration.
<VirtualHost *:80>
# config remaining parts
WSGIApplicationGroup %{GLOBAL}
# config remaining parts
</VirtualHost>
From docs
... forces the WSGI application to run in the main Python interpreter context of each process. This is preferred in this scenario as some third party packages for Python which include C extensions will not run in the Python sub interpreter contexts which mod_wsgi would use by default. By using the main Python interpreter context you eliminate the possibility of such third party packages for Python causing problems.
A similar case link.
Also:
Looking at this,
python-home=/home/ubuntu/myapp/myapp/myapp python-path=/home/ubuntu/myapp:/home/ubuntu/myapp/lib/python3.6/site-packages
I think you have the wrong path for python-home. Make sure python-home path is correctly provided. Activate your virtual environment and run the command to get the python-home path [docs].
python -c 'import sys; print(sys.prefix)'

Can't Deploy Mezzanine CMS using Apache/Ubuntu

I'm trying to become better with deploying a website from scratch so I setup a new Nanode from Linode using the latest Ubuntu (19.04 I think).
I followed the instructions to install Mezzanine CMS (Django Based) and it all went fine, I was able to run the dev server to test the website fine on port 8000.
I did install UFW and right now only activity on port 80 is not rejected. Also I have mysql database running with Mezzanine not Djangos default SQLlite.
I installed Apache and WSGI. At first Apache would not restart due to some configuration issue which I think I've since worked out.
I have a domain alexmerced which is on godaddy, but I have a DNS "a" records which is pointing to my linodes IP address "mezz.alexmerced.com"
Mezzanine is still a fresh install so I haven't really changed anything outside of the WSGI and settings.py.
I currently get a forbidden error when I type the URL or IP address, the permissions of the application directory is 755.
below are my configuration file settings to see if I made any mistakes.
django_project.conf (the only conf file enabled in the /sites-available/ directory
<VirtualHost *:80>
ServerName mezz.alexmerced.com
ServerAdmin mezzanine#localhost
DocumentRoot /mymezz
WSGIScriptAlias / /mymezz/mymezz/wsgi.py
Alias /static /mymezz/static/
<Directory /mymezz/>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
here is the wsgi.py file
"""
WSGI config for mymezz project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
from mezzanine.utils.conf import real_project_name
os.environ.setdefault("DJANGO_SETTINGS_MODULE",
"%s.settings" % real_project_name("mymezz"))
application = get_wsgi_application()
other stuff I read on asked me to add the following to my settings.py
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.join(PROJECT_ROOT, ".."))
settings_module = "%s.settings" % PROJECT_ROOT.split(os.sep)[-1]
os.environ["DJANGO_SETTINGS_MODULE"] = settings_module
and
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
I never did figure this out with Apache, but I did successfully deploy this blog using Nginx and Uwsgi, just be careful regarding the path your virtual environment once completed I realized that was the problem I was having apache.

How does mod_wsgi know and execute the application?

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.

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.

Django multi-threaded and mod_wsgi

First of all my site is up and running OK. There is no critical issues.
I want to understand a couple of things though.
I'll start with an overview of my system.
It's a django-powered site located on a CentOS 5.3 VPS with 256MB RAM, under apache with mod_wsgi.
The django application runs as a Daemon process with 1 threads.
What I need in my application is:
1. Initialize logging (currently it is working, but I get double logging every time)
2. Start to daemon threads to do some background work
Now, I have read and implemented the solution offered in
http://blog.dscpl.com.au/2010/03/improved-wsgi-script-for-use-with.html
but it didn't help much.
Basically I had to manually disable worker MPM (only prefork MPM is running) and configure the daemon process to be with one process and one thread (for some reason it does not work with any other combination).
But what is weird is that the site is running and it is creating the 2 background threads.
1. How does that happen?
2. Does my settings mean that concurrent requests will not be handled on my site?
Here is some configuration from my site
httpd.conf
WSGIScriptAlias / /var/www/NiceHouse/trunk/apache/django.wsgi
WSGISocketPrefix run/wsgi
<VirtualHost *:80>
WSGIDaemonProcess site-1 user=**** group=**** threads=1
WSGIProcessGroup site-1
ServerName *****
ServerAlias *****
ServerAdmin *****
#DocumentRoot /usr/local/www/documents
#Alias /robots.txt /usr/local/www/documents/robots.txt
#Alias /favicon.ico /usr/local/www/documents/favicon.ico
Alias /media/ /usr/lib/python2.4/site-packages/django/contrib/admin/media/
Alias /site_media/ /var/www/NiceHouse/trunk/media/
Alias /phpmyadmin /var/www/phpmyadmin/
#<Directory /usr/local/www/documents>
#Order allow,deny
#Allow from all
#</Directory>
WSGIScriptAlias / /var/www/NiceHouse/trunk/apache/django.wsgi
#<Directory /usr/local/www/wsgi-scripts>
#Order allow,deny
#Allow from all
#</Directory>
</VirtualHost>
swtune.conf
<IfModule prefork.c>
StartServers 1
MinSpareServers 1
MaxSpareServers 3
ServerLimit 50
MaxClients 50
MaxRequestsPerChild 1000
</IfModule>
django.wsgi
import sys
import os
os.environ['PYTHON_EGG_CACHE']='/tmp/hoge'
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
sys.path.insert(0,'/var/www/NiceHouse/trunk')
import settings
import django.core.management
django.core.management.setup_environ(settings)
utility = django.core.management.ManagementUtility()
command = utility.fetch_command('runserver')
command.validate()
import django.conf
import django.utils
django.utils.translation.activate(django.conf.settings.LANGUAGE_CODE)
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
I'll appreciate any help
Thanks, Elad
You may be getting double logging for a number of reasons. First is where have you put the logging? If you have stuck logging in settings.py file, then it will get executed twice with that WSGI script file contents you are using. The blog post explains how settings file is imported twice.
BTW, you didn't even copy the WSGI script file correctly. That in the blog post does not set DJANGO_SETTINGS_MODULE environment variable.
You may also be seeing double logging if you yourself are importing a module with the logging in it via two different paths. That is, qualified and not qualified by site package name. From memory this problem is also mention in blog post.
In respect of background threads, although you have specified threads=1, mod_wsgi has a few separate threads of its own to make sure things are working correctly and kill off process if deemed it is dead locked.
BTW, you really should get worker MPM going if you aren't using mod_php. You are only going to waste memory by using prefork MPM.