Placing code outside of document root problems with Apache and Django - python

I am having trouble fulfilling the Django recommendation for code placement. I have searched google and beyond trying all types of VirtualHost configurations. However I cannot get the Django site to work with Apache like it does with Django's built in test web server.
I am using Django 1.5.4 and mod_wsgi
The Django documentation states that:
Where should this code live?
If your background is in plain old PHP (with no use of modern frameworks), you’re probably used to putting code under the Web server’s document root (in a place such as /var/www). With Django, you don’t do that. It’s not a good idea to put any of this Python code within your Web server’s document root, because it risks the possibility that people may be able to view your code over the Web. That’s not good for security.
Put your code in some directory outside of the document root, such as /home/mycode.
And in trying to do that I am failing.
Here is an example of my directory structure: I have /home/user/djangoRoot which I want for the document root and /home/user/djangoCode for where I want to put the code. I have followed the tutorial running django-admin.py startproject djangoSite and all the folders and files are created as they should. Database sync works great. I can view the site when I use Django's built in testing web server. But I feel like something is wrong with my apache virtual host because I cannot view the site the same way with apache.
Again, in the spirit of keeping code out of the document root, I want djangoRoot as my root directory and djangoCode for my code directory (with djangoSite/djangoSite directories in it that were created after running the django-admin.py start project djangoSite command).
I have tried
Making the DjangoCode/DjangoSite my root directory, but I can see the file structure inthe browser
Eliminating the DocumentRoot from the VirtualHost as quite a few suggessted.
And I have tried what I gathered from django and the rest
None worked.
So here is my current apache virtualhost
WSGIPythonPath /home/user/djangoCode/djangoSite/djangoSite
<VirtualHost *:80>
ServerAdmin webmaster#localhost
ServerName example.com
ServerAlias www.example.com
DocumentRoot /home/user/djangoRoot
<Directory /home/user/djangoRoot>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>
WSGIScriptAlias /djangoRoot /home/user/djangoCode/djangoSite/djangoSite/wsgi.py
<Directory "/home/user/djangoCode/djangoSite/djangoSite/wsgi.py">
<Files wsgi.py>
Order deny,allow
Allow from all
</Files>
</Directory>
...
</VirtualHost>
This currently only allows me to see document root with no sign of django.
Is my virtual host configured wrong?
Am I taking this "code outside of document root too far"?

I really don't understand why you're finding this so hard, but you're clearly not following me at all. The point of the explanation in the docs is that the place where you code lives in your filesystem is completely independent from the point that Apache serves it at. The latter is given by the first parameter to WSGIScriptAlias. The former is given by the second parameter.
The document root is the default place for Apache to serve files from. But you're not serving files, you're running code to serve dynamic content. So, you proxy to the WSGI app, at the point given by the first parameter to WSGIScriptAlias. That is the root URL of your site. In the example you've given, that means that - assuming your domain name is example.com - your Django app will be accessible under example.com/djangoRoot. If you actually visited that URL in your browser, you'd see whatever page is configured under / in your urls.py. That is almost certainly not what you want. In the vast majority of cases, the first parameter - as shown in the docs - should just be /.
So I'm not sure why you think that goes against the security warning. Here, the document root stays at whatever it is by default - usually /var/www - but the code lives in /home/user/djangoCode/... and is served at /.

Related

How do I use python as a server-side language?

I am trying to use Python instead of PHP (just for educational purposes). I am testing my webpages on XAMPP and I already added python and cgi to configs.
I managed to make a very basic webpage with this code
#!/Python/python
print("Content-Type: text/plain;charset=utf-8")
print()
print("Hello World!")
Though, this is it. I can't find any info on how exactly do I serve webpages with Python 3+. Most of the info is outdated or controversial. Is there an up-to-date guide on how to use Python as a server-side language?
What Nicarus said was a valid sugestion but I also recommend some other things.
First, for your development environment you won't need to use xampp or wamp or such things, python has it's own HTTP server, although not the simplest thing to use, the libraries and frameworks I will explain next use that.
So, most python web developers don't use raw python to use python as their programming language for the web. Most developers use a framework or library of some kind. These frameworks range from being rather heavy and opinionated, like Django, to smaller ones like Flask. Most, if not all, of these frameworks provide some kind of easy and quick way to set up a development HTTP server for testing.
I would recommend looking up Django first since it has the most comprehensive tutorials and guides to get you started. Then, ones you're more comfortable in the Python language you can fairly easily use something else with less hand holding.
With django you can start here
Python can be a great side server language, but not in the way PHP is. It is highly recommended to use a framework, like flask.
In PHP you have different .php files (like index.php) that do a basic routing, but in python (with Flask and also some others frameworks) you must define the URI path within the function.
You can see here an example, from its webpage Flask
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
And if you look for a API REST framework, take a look to Falcon
For the purposes you mention, this current setup should work (at least for a while):
Apache Setup
Changes in httpd.conf
Change denied to granted
<Directory />
AllowOverride none
Require all granted
</Directory>
Look for Options +Indexes +FollowSynsLinks........ and add +ExecCGI to that line.
Options +Indexes +FollowSymLinks +Multiviews +ExecCGI
Look for AddHandler cgi-script .cgi and add .py to it
AddHandler cgi-script .cgi .py
Changes in httpd-vhosts.conf
<Directory "{Your directory}"/>
Options +Indexes +Includes +FollowSymLinks +MultiViews +ExecCGI
AllowOverride All
Require all granted
</Directory>
example.py
First line of Python code #!C:\{somepath}\python
You need to find the right path and bar convention ( /, \, //...) for the first and commented line of code. In your example is: #!/Python/python
Run this script.py to find it
import sys
print(sys.executable)
Paste the output next to #! and you should be able to test your test-code.py into your **www\ folder
If happens to be the case that it does not work, try different combinations of python, python.exe with different bar conventions like "/" "//" "\" next to the #! line.
To display an HTML file add print ('Content-type: text/html\n\n') on to your .py code.**
Full code
Note f on html_content = f'''<html>...
#!C:\Program Files (x86)\Python37-32\python
# -*- coding: utf-8 -*-
import cgi
stringvar = 'Hello variable'
intvar = 30
html_content = f'''<html>
<head><title>My first Python CGI app</title></head>
<body>
<p>Hello, 'world'!</p>
<p>This is a stringvar = {stringvar} </p>
<p>This is intvar = {intvar} </p>
</body>
</html>'''
print ('Content-type: text/html\n\n')
print (html_content)
"Most of the info is outdated or controversial"
Totally agree. I hope this works!

Name duplicates previous WSGI daemon definition

I'm changing the domain name of a site. For a period I want the old domain name and the new domain name to point to the site. I'm running a Python Django site.
My original Apache2 conf works fine and the basis is:
<VirtualHost *:80>
ServerAdmin name#gmail.com
ServerName originalsite.co.uk
ServerAlias www.originalsite.co.uk
DocumentRoot /var/www/originalsite
WSGIDaemonProcess originalsite python-path=/var/www/originalsite:/var/www/originalsite/env/lib/python2.7/site-packages
WSGIProcessGroup originalsite
WSGIScriptAlias / /var/www/originalsite/originalsite/wsgi.py
...
</VirtualHost>
I set up a new conf file with only the following changes:
ServerName newsite.co.uk
ServerAlias www.newsite.co.uk
And I'm getting the following error:
Name duplicates previous WSGI daemon definition.
How do I fix this? Thanks for your help
change originalsite name
not in the directory address just the name like
WSGIDaemonProcess somethingelse python-path=/var/www/originalsite:/var/www/originalsite/env/‌​lib/python2.7/site-p‌​ackages
and
WSGIProcessGroup somethingelse
If you're facing this issue while using certbot command to install multiple "Let's Encrypt Certificates" then it may be due to some bug in certbot, as discussed here. For a quick workaround, you can comment
WSGIScriptAlias
WSGIDaemonProcess
WSGIProcessGroup
to run certbot command and then remove the comments afterwards.
The reason for the error is because the name of a mod_wsgi daemon process group must be unique across the whole Apache installation. It is not possible to use the same daemon process group name in different VirtualHost definitions. This is necessary to avoid conflicts when working out what daemon process group is being referred to in certain situations.
I've solved this problem by commenting the below 3 lines in /etc/apache2/sites-enabled/000-default.conf
# WSGIDaemonProcess
# WSGIProcessGroup
# WSGIScriptAlias
then reload/restart Apache2.
And I leave them as is in /etc/apache2/sites-enabled/default-ssl.conf because it's duplicated in HTTP (non-SSL) and HTTPS (SSL)
I have the same problem with Apache2 configuration.
In my case I have duplicated 000-default.conf file in /etc/apache2/sites-enabled.
First I looking 'WSGIDaemon' string in Linux:
grep -iRl "WSGIDaemon" ./
Second analize every line. I found duplicated file on /etc/apache2/sites-enabled/000-default-copy.conf. After delete, checking syntax:
sudo apachectl configtest
return 'Syntax OK'. I spend on this 4 hours... I hope somebody use this :)
Although there are correct answers given, I was still confused when reading the answers. So here's some clarification for the particular case when enabling HTTP and HTTPS for a single site on Apache.
In one of your configuration files (let's say HTTP):
# Add this outside of VirtualHost scope to ensure it's global
WSGIDaemonProcess some_name python-path=/var/www/originalsite:/var/www/originalsite/env/‌​lib/python2.7/site-p‌​ackages
...
# Within VirtualHost
WSGIProcessGroup some_name
In the other configuration file (HTTPS):
WSGIProcessGroup some_name
That's it. What it does is link the same group in both the config files. The process name is defined only in one config files and that makes Apache happy.

Configuring apache2 conf for several python web.py apps

I am working on a small web dashboard -project that has backend implemented with python's web.py framework.
The dashboard has all sorts of widget's on it, one of which also has its backend implemented using web.py. The problem is that only one of the designated application entry points seem to function at a time. Both the dashboard's and the widget's apache configurations are placed in the same file. The original configuration file (that actually worked for a while) in apache2/conf.d/ looks like this:
WSGIPythonPath /var/www/ProjectDASHBOARD/api
WSGIScriptAlias /ProjectDASHBOARD/api /var/www/ProjectDASHBOARD/api/api.py/
AddType text/html .py
<Directory /var/www/ProjectDASHBOARD/api/>
Order deny,allow
Allow from all
</Directory>
# Stuff for graphingwidget
WSGIPythonPath /var/www/ProjectDASHBOARD/widgets/graphingwidget/api
WSGIScriptAlias /ProjectDASHBOARD/widgets/graphingwidget/api /var/www/ProjectDASHBOARD/widgets/graphingwidget/api/api.py/
AddType text/html .py
<Directory /var/www/ProjectDASHBOARD/widgets/graphingwidget/api/>
Order deny,allow
Allow from all
</Directory>
This alone does not work, there is also the next piece of code that is needed in both api.py files, checking their approriate paths and adding them if not found (excerpt from the widget's file):
import web
import json
import sys
path = '/var/www/ProjectDASHBOARD/widgets/graphingwidget/api'
if path not in sys.path:
sys.path.append(path)
A similiar check is done for the dashboard.
All of this indeed worked for a whole week, and then suddenly stopped working when trying to install from scratch, making it all the more confusing as to what is wrong. The error received when trying to access the api from a webpage is HTTP Error 500 Internal server error. Then after a few changes to the apache config file ONE of the api's started working:
WSGIPythonPath /var/www/ProjectDASHBOARD/widgets/graphingwidget/api
WSGIPythonPath /var/www/ProjectDASHBOARD/api
WSGIScriptAlias /ProjectDASHBOARD/api /var/www/ProjectDASHBOARD/api/api.py/
WSGIScriptAlias /ProjectDASHBOARD/widgets/graphingwidget/api /var/www/ProjectDASHBOARD/widgets/graphingwidget/api/api.py/
AddType text/html .py
<Directory /var/www/ProjectDASHBOARD/api/>
Order deny,allow
Allow from all
</Directory>
# Stuff for graphingwidget
AddType text/html .py
<Directory /var/www/ProjectDASHBOARD/widgets/graphingwidget/api/>
Order deny,allow
Allow from all
</Directory>
Basically just moved the paths to the beginning of the file, and switched the order around a little bit, and suddenly one of api's start to work again. Changing the order a little bit then makes the other api work and brakes the other one. I don't remember the correct order for the paths, but the point is that it used to work well, then it stopped working when installed to a fresh identical virtual machine, and only one of the api's work depending on the order of the paths.
Initially the configs were in different files, but it didn't work like that. Had all kinds of errors like "Target WSGI script 'path' cannot be loaded as Python module.", and only started to work when they were moved to the same file.
Im thinking here that somehow one of the paths is overwritten by the other, or that all this time the whole config has been fundamentally wrong and has been working only by sheer luck (for a whole week, without issues...)
Any clues as to what is wrong?
Sorry for the late return, but the case was basically had to carefully RTFM at http://webpy.org/install#apachemodwsgi and make use of .htaccess files.
No idea really why the solution in the original question worked as far as it did.

intermittent problem with two django apps on the same virtual host

I have two Django applications (appsystem and testapp) running in separate folders that are enabled in the same apache virtual host setting (see conf file at the end).
One application displays a page on the root of the domain and that one seems to always work fine but when I go to a URL that should go to the second application then it fails the first time complaining that it can't find the database table despite the fact I can see in the debug page that is loading the right settings.
If I refresh the page then it (testapp) works fine and continues to until I go back to a page from appssytem. If I do that and go back to testapp I must then refresh the page.
Both applications are using sqlite for authentication but removing the authentication and sqlite references from the settings file for appsystem didn't seem to make a difference.
The reason I've done it this way is because the idea is that the application that displays the root page (and some admin pages that have unique URLs) will list the other django application installed and display links to click through to.
I also suspect it may be session related because I can go directly to testapp in another browser and it works fine even on the first instance. Because of this I did give each django app its own value for SESSION_COOKIE_NAME but that doesn't seem to have helped.
Does anyone have an idea on what the problem may be?
<VirtualHost *:80>
ServerAdmin webmaster#localhost
DocumentRoot /app_www_root
RewriteEngine On
# the root of the box should show the system index - a list of installed apps
RewriteRule ^/$ /appsystem/system_index/ [PT]
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /app_www_root/>
Order allow,deny
allow from all
</Directory>
ErrorLog /var/log/apache2/error.log
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn
CustomLog /var/log/apache2/access.log combined
Include /etc/apache2/installed-apps/
## this is what gets pulled in by the include ##
Alias /testapp/static /testapp/static
Alias /testapp/logs /var/log/testapp
WSGIScriptAliasMatch ^/testapp /testapp/django.wsgi
<Directory "/testapp">
Order allow,deny
Allow from all
</Directory>
<Directory "/var/log/testapp">
Order allow,deny
Allow from all
</Directory>
<Location "/testapp/logs">
SetHandler none
Options +Indexes
</Location>
<Location "/testappl/static">
SetHandler none
Options -Indexes
Options +Includes
AddOutputFilter INCLUDES .html
</Location>
## end of included file ##
# wsgi docs advise against trailing slash below
WSGIScriptAlias /appsystem /app_sys/django.wsgi
</VirtualHost>
Have you read http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango at all?
I suspect your problem would be solved if you used mod_wsgi in daemon mode (i.e. via WSGIDaemonProcess).
Try running them in virtualenv with modwsgi.
FWIW, you have various things wrong with your configuration.
Why are you using WSGIScriptAliasMatch directive at all? You should just replace it with WSGIScriptAlias. Don't use WSGIScriptAliasMatch properly and it can stuff up reverse URL resolution.
Using 'SetHandler none' is not required. That is something you may have needed to do for mod_python but not mod_wsgi.
Using Location directive block to apply directives to static file resources as you are is bad practice. You should apply them to the specific directories using Directory directive instead.
As pointed out by others, you are better off using daemon mode. If doing so has worked but you delegate both applications to same single daemon mode process though, then you may have a multi process issue, ie., your application can't handle being run in multiple processes at the same time. If you delegated each to its own daemon process group, then you may have an issue with running them in same process even in case where in separate sub interpreters.

making HTTP authentication optional with mod-python

I've a web application that accesses multiple controller classes based on the parameters it is passed. For some of the controllers, I want users to authenticate themselves (by simple HTTP authentication), and for some I want public access.
Is there a way to make this happen? In my .htaccess file, I now have
AddHandler mod_python .py
PythonHandler handler
PythonAuthenHandler handler
PythonDebug On
AuthType Basic
AuthName "My Realm"
AuthBasicAuthoritative Off
require valid-user
The authenhandler is called correctly, but even when I just do
def authenhandler(req):
return apache.OK
the user is asked for a password (though any password that is entered is accepted)
I tried removing the Auth* stuff (and the require directive) from the .htaccess entirely, and just did the following in the normal handler for those cases where I do want authentication (and it was not found):
request.err_headers_out.add('WWW-Authenticate', 'Basic realm="My Realm")
return apache.HTTP_UNAUTHORIZED
which is what I understand what the server should do when not receiving correct authentication. That did not work either, however.
I come from a PHP background and I know that the latter is how it's done in PHP - but PHP sometimes does extra little pieces of undocumented magic to make this stuff actually work. Is this one of those cases?
Is there any way to optionally request authentication, depending on the URL passed, from the same handler?
There are a couple ways to specify authentication scope with Apache, the one most people are used to is gt;Directorylt; based - i.e. anything in or below a directory gets authenticated against htpasswd.
There's also gt;Locationlt;, which applies directives to content that live outside the filesystem such as mod_python registered code.
This is how you can set authentication on a 'virtual' path like /status, if you have mod_status enabled.
You can do the same thing with mod_python paths
<Location /python/app1/>
Order allow,deny
Allow from all
</Location>
<Location /python/app2/>
Order allow,deny
Allow from all
AuthType basic
AuthName "Protected Intranet Area"
AuthUserFile /etc/apache2/htpasswd
Require valid-user
</Location>
I should add - it's not necessarily clear if you mean 'some users should authenticate with a username and password and other users should only have to put in a username'
or
'some applications should require authentication 100% of the time, and other applications should be freely available 100% of the time'
My first answer sorts out the last query.

Categories

Resources