Using Nginx and Apache to serve web application - django

I have a number of PHP sites running on Apache, however I am about to launch my first Django site.
I have successfully got WSGI working on Apache to handle the Python scripts but I am a bit stuck with using Nginx to serve my media files.
I know I need to make Apache listen on a different port and get Nginx to listen on port 80, then forward any non-media requests to Apache on port 8080.
What I really want to know is, is there an easy way to configure it to work with all of my existing sites or do I need to set up a separate record for every one of my current sites just to forward the requests to port 8080?
Any advice appreciated.
Thanks

If you scroll down a bit in the Django documentation about serving static files, they give you the information on how to make Apache serve the files for you so that you don't need nginx (assumes your media files are in /usr/local/wsgi/static/media/):
Alias /robots.txt /usr/local/wsgi/static/robots.txt
Alias /favicon.ico /usr/local/wsgi/static/favicon.ico
AliasMatch ^/([^/]*\.css) /usr/local/wsgi/static/styles/$1
Alias /media/ /usr/local/wsgi/static/media/
<Directory /usr/local/wsgi/static>
Order deny,allow
Allow from all
</Directory>
WSGIScriptAlias / /usr/local/wsgi/scripts/django.wsgi
<Directory /usr/local/wsgi/scripts>
Order allow,deny
Allow from all
</Directory>
If, however, you are dead set on using nginx, you would add your static directives in your server {} directive:
location /media/ {
access_log off; # who cares about static files?
alias /usr/local/wsgi/static/media/;
expires 30d; # enables caching.
}

Related

How to configure Apache to work with Django

I've followed the instructions on Django website for configuring Apache with my Django app on a CentOS 7 server. This included building mod_wsgi from sources to work with the installed python3.4.
Apache restarts without errors but when I hit my app with the URL
http://example.com/myapp/
I get a 503 error like:
Service Temporarily Unavailable
The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.
Apache/2.2.15 (CentOS) Server at example.com Port 80
I'm not sure how I troubleshoot what's wrong here. Can anyone help?
Details of the config:
My django app lives at /mnt/net/django/myapp
I've added the file wsgi.conf to my apache conf.d directory and it looks like this:
#LoadModule wsgi_module modules/mod_wsgi.so
# use python34 pip installes mod_wsgi
LoadModule wsgi_module "/usr/lib64/python3.4/site-packages/mod_wsgi/server/mod_wsgi-py34.cpython-34m.so"
#WSGIPythonHome "/usr"
Alias /robots.txt /mnt/net/django/myapp/static/robots.txt
Alias /favicon.ico /mnt/net/django/myapp/static/favicon.ico
Alias /media /mnt/net/django/myapp/media/
Alias /static/ /mnt/net/django/myapp/static/
<Directory /mnt/net/django/myapp/static>
Order deny,allow
Allow from all
</Directory>
<Directory /mnt/net/django/myapp/media>
Order deny,allow
Allow from all
</Directory>
# Allows URLs like example.com/myapp to forward to django
WSGIScriptAlias /myapp /mnt/net/django/myapp/myappsite/wsgi.py process-group=example.com
# Use the virtual env for the myapp site
#WSGIPythonHome /mnt/net/django/myapp/env-myapp-py3-4
# Need to use WSGIDaemon
WSGIDaemonProcess example.com python-home=/mnt/net/django/myapp/env-myapp-py3-4 python-path=/mnt/net/django/myapp
#WSGIPythonPath /mnt/net/django/myapp
<Directory /mnt/net/django/myapp/myappsite>
<Files wsgi.py>
Order deny,allow
Allow from all
</Files>
</Directory>
How to use Django with Apache and mod_wsgi -- follow this: I have done it myself many times, it is very straight forward.
Tip: Create a document and record everything you do whilst setting this up, this way if it doesn't work then you can retrace your steps, but if it does work... Great, you have your very own guide to setting up an Apache server for Django.
Solved my problem (mostly)
The problem is that mod_wsgi with a daemon process tries to write a socket file into the apache logs directory and permissions are denied.
Solution is to tell apache another place to write the socket like this:
WSGISocketPrefix /var/run/wsgi

apache + django + mod_wsgi conversion to https keeps going back to http

I've had a django (satchmo) site using Apache and mod_wsgi running fine for a couple of years now. Until now it has only served http, and I'm trying to convert the entire site to https. I have a signed ssl certificate which I believe is fine.
I have adapted my Apache configuration according to my understanding of the docs.
When I try to connect to the site using https, the browser connects fine on port 443, and the Apache server responds with the correct ssl certificate followed by the TLS key exchange etc (according to what I see in Wire Shark). At that point everything looks fine and there are no errors. But..
Once the ssl connection is established, the browser then initiates a "GET / HTTP/1.1" in a new TCP connection to port 80 (i.e. http). It's like it knew nothing about the https connection already in place.
Is it possible that django is at fault? I have not changed the django configuration at all, as I was under the impression that only Apache needs to know about it? (I don't use nginx - Apache handles all of the content.)
I can't "see" what is going on in the ssl conversation, but presumably django is telling the browser client to connect on port 80 somehow? Is that possible?
To make things simple, I now have a plain index.html page when you connect to http, and I've moved all of the django & mod_wsgi to port 443. If I connect straight to the http address, I get the simple index page, no problem.
When I try to connect to the https address, the browser effectively gets redirected to the index.html page. (I don't have any Redirect or Rewrite commands in Apache though.)
Here is my Apache configuration:
<VirtualHost *:80>
ServerName demo.pasta.co.za
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
DocumentRoot /var/www/http_site
</VirtualHost>
<VirtualHost *:443>
SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM
SSLCertificateFile /etc/ssl/private/pasta.co.za.crt
SSLCertificateKeyFile /etc/ssl/private/pasta.co.za.key
SSLCertificateChainFile /etc/ssl/private/root_bundle.crt
ServerName demo.pasta.co.za
Alias /favicon.ico /usr/local/django/pasta/static/favicon.ico
Alias /robots.txt /usr/local/django/pasta/static/robots.txt
AliasMatch ^/([^/]*\.css) /usr/local/django/pasta/store/static/$1
WSGIDaemonProcess demo.pasta.co.za processes=2 threads=25 display-name=%{GROUP}
WSGIProcessGroup demo.pasta.co.za
WSGIScriptAlias / /usr/local/django/pasta/apache/django.wsgi
<Directory /usr/local/django/pasta/apache>
Order allow,deny
Allow from all
</Directory>
Alias /static/admin/ /usr/share/pyshared/django/contrib/admin/static/admin/
Alias /static/images/ /usr/local/django/pasta/store/static/images/
Alias /static/ /usr/local/django/pasta/store/static/
Alias /media/ /usr/local/django/pasta/store/static/
<Directory /usr/local/django/pasta/store/static>
Order deny,allow
Options -Indexes
Allow from all
</Directory>
<Directory /usr/share/pyshared/django/contrib/admin/static/admin>
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
And here is my mod_wsgi file:
import os, sys
sys.path.insert (0,"/usr/local/django/pasta/store")
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()
There are dozens of examples on SO where people accomplish what I'm trying to do with more or less what I have above.
What am I missing? It feels like I've left out something really obvious.
I have Debian stable running django v1.4.5 python v2.7.3 and apache v2.2.22 with mod-wsgi v3.3-4.
Many thanks!
Accepted answer for satchmo nginx redirect to https then to http and back by mipadi ...
Satchmo includes a piece of middleware called satchmo_store.shop.SSLMiddleware.SSLRedirect, which automatically does redirecting to SSL/non-SSL portions of the site. You have to set up URLs to be served via SSL if you want them to be served via SSL, otherwise the middleware redirects to a non-SSL page. From the docs:
This middleware answers the problem of redirecting to (and from) a SSL secured path by stating what paths should be secured in urls.py file. To secure a path, add the additional view_kwarg 'SSL':True to the view_kwargs.
For example
urlpatterns = patterns('some_site.some_app.views',
(r'^test/secure/$','test_secure',{'SSL':True}),
)
All paths where 'SSL':False or where the kwarg of 'SSL' is not specified are routed to an unsecure path.
For example
urlpatterns = patterns('some_site.some_app.views',
(r'^test/unsecure1/$','test_unsecure',{'SSL':False}),
(r'^test/unsecure2/$','test_unsecure'),
)
In your case, since you're serving the entire site via SSL, you can probably just disable that middleware in your settings.py file.
(From my experiance you need to change quite a few urlpatterns in a few files.)

how to serve website with apache over the internet?

I have somehow managed to serve both my project app and its static files on the apache. But only I can see my webpage, by typing localhost and by my IPv4 address. And I can't see my webpage from the other's computer. In my http.conf, it is Listen 80. I don't know much about this. I even registered on a free dynamic DNS provider, but even from that url I can only see It works message. I really suck at these things. Please guide me here. Thank you.
snippet of http.conf:
WSGIScriptAlias / C:/Users/robin/web/etc/etc/etc/wsgi.py
WSGIPythonPath C:/Users/robin/web/etc/etc
<Directory C:/Users/robin/web/etc/etc>
<Files wsgi.py>
Order deny,allow
Allow from all
</Files>
</Directory>
#Alias /robots.txt /path/to/mysite.com/static/robots.txt
#Alias /favicon.ico /path/to/mysite.com/static/favicon.ico
AliasMatch ^/([^/]*\.css) C:/Users/robin/web/etc/etc/static/styles/$1
#Alias /media/ /path/to/mysite.com/media/
Alias /static/ C:/Users/robin/web/etc/etc/static/
<Directory C:/Users/robin/web/etc/etc/static>
Order deny,allow
Allow from all
</Directory>
#<Directory /path/to/mysite.com/media>
#Order deny,allow
#Allow from all
#</Directory>
WSGIScriptAlias / C:/Users/robin/web/etc/etc/etc/wsgi.py
<Directory C:/Users/robin/web/etc/etc/etc>
<Files wsgi.py>
Order allow,deny
Allow from all
</Files>
</Directory>
You need to do the following:
1. Ensure that the server is publicly accessible
To do this you need to ensure
Port 80 is routed through your router to the servers internal IP address. This is called NAT. If you are using a Cisco router you can see the instructions here.
Any firewalls are configured not to block the traffic on port 80. If you are using Linux you would most likely need to configure iptables. If you are using Windows you can do this on the windows firewall. If you are using a third party firewall you need to search google to find out how to do it.
You need to ensure you are using the public ip address to connect. You can find this by using a website such as http://whatismyipaddress.com/
2. Setup the virtual hosts on apache
The reason you are only seeing the "It Works" message is because Apache is pointing to the default web root on the server for that domain name. To fix this, you need to setup a virtualhost for the domain name, and point it to the root directory of your application. Instruction for this can be found here.
Under for virtual hosts in your apache config, you could add something like this:
NameVirtualHost *:80
<VirtualHost *:80>
ServerAdmin [email]#[address].com
DocumentRoot [directory root]
ServerName [registered domain name without www eg: something.com]
ServerAlias *.[registered domain name without www]
</VirtualHost>
The "NameVirtualHost *:80" might already exist, so search the config first. Usually it is in there and commented out by default, so you might just need to remove the #.
Note: ALWAYS backup the config by copying the contents to another file. Also restart apache after you make the adjustment.

Django + mod_wsgi: Can someone advise me on my setup and rewrite rules

This is my first time deploying Django to a recently acquired Linode server and I'm curious if someone can look over my deployment and help me fix some nagging issues and advise me whether i'm doing things incorrectly.
Directory Structure
home\
-public\
-example.com\
-public\
-.htaccess
-index.html
-log\
-application\
-mysite\
-mysite\
-manage.py
-static\
-myapp\
-logs\
How is this for deployment structure for Django?
Incorrect URL Naming
I've hosted the Django application called 'myapp' on my domain 'example.com'. Following the instructions on the Django website I've made it so that the urls.py for the app must begin with '/myapp'. This has resulted in the domain for the app becoming 'example.com/myapp'.
How can I set it so that example.com is simply the Django app I've written?
I'd like to simply navigate to example.com and it load my app instead of example.com/myapp.
Even weirder is that I would've thought that example.com would load my index.html file however it tries to find a URL mapping for Django instead...
Django Log File Writing Permissions
Whenever I SSH onto my machine to either 'syncdb' or 'collectstatic', the logging module creates the log file I've named in my settings.py file. This causes problems for me because I am the owner of the file and apache2 (www-data) cannot write to it. It's just annoying having to manually delete the log file after every command before I restart the apache server.
Here is my /etc/apache2/sites-available/example.com file:
# domain: example.com
# public: /home/setheron/public/example.com/
WSGIPythonPath /home/setheron/public/example.com/applications/mysite:/home/setheron/env/lib/python2.7/site-packages
<VirtualHost *:80>
# Admin email, Server Name (domain name), and any aliases
ServerAdmin setheron#setheron.com
ServerName www.example.example.com
ServerAlias example.com
WSGIScriptAlias / /home/setheron/public/example.com/applications/mysite/mysite/wsgi.py
Alias /static/ /home/setheron/public/example.com/applications/mysite/static/
<Directory /home/setheron/public/example.com/applications/mysite/static/>
Order deny,allow
Allow from all
</Directory>
<Directory /home/setheron/public/example.com/applications/mysite/mysite>
<Files wsgi.py>
Order deny,allow
Allow from all
</Files>
</Directory>
# Index file and Document Root (where the public files are located)
DirectoryIndex index.html index.php
DocumentRoot /home/setheron/public/example.com/public
# Log file locations
LogLevel warn
ErrorLog /home/setheron/public/example.com/log/error.log
CustomLog /home/setheron/public/example.com/log/access.log combined
</VirtualHost>
If you want Django serving the entire site, get rid of your public directory, indexes and whatnot. Other than /static, you should only need your WSGIScriptAlias directive. Fix the urls.py to say that your site should be coming from /, rather than /myapp.

Nginx/Apache serving wrong website

I have nginx as a reverse proxy to apache serving static files for django sites. I have 3 django sites on the server that are working (and have been working for over a year now) but when I try to add a new one either nginx or apache is serving one of the ones that already exist.
For example site A.com & B.com are already on the server. I am attempting to add C.com. I copied over the nginx/apache config files, linked them properly and changed the settings in them properly, restarted nginx & apache sucessfully with no errors but when I try to go to C.com it loads A.com! The DNS has been confirmed as being accurate by Rackspace. I have looked in the log files with no obvious luck. I am assuming this is apache since it is actually rendering the django code for A.com or could nginx be be giving apache the wrong directive?
Also I attempted to unlink one of the working sites that was pointed to the new django code ("C.com", and working!) and then relink (add to sites-enabled) in both nginx & apache and it too now will not work! It just redirects or defaults to A.com.
I've been digging around google with no luck other than apache/nginx defaults but nothing on how to fix this! Any help or direction would be appreciated!
Here are example nginx & apache config files:
nginx
server {
listen 111.111.111.111:80;
server_name mynewdomain.com;
rewrite ^/(.*) http://www.mynewdomain.com/$1 permanent;
}
server {
listen 111.111.111.111:80;
server_name www.mynewdomain.com;
location / {
proxy_pass http://127.0.0.1:8080/;
include /etc/nginx/proxy.conf;
}
location /media {
root /home/django/mynewdomain;
expires 24h;
}
}
apache:
<VirtualHost 127.0.0.1:8080>
ServerName www.mynewdomain.com
ServerAlias mynewdomain.com *.mynewdomain.com
<Directory /home/django/mynewdomain/>
Order deny,allow
Allow from all
</Directory>
Loglevel warn
CustomLog /var/log/apache2/mynewdomain.com.access.log combined
ErrorLog /var/log/apache2/mynewdomain.com.error.log
WSGIDaemonProcess mynewdomain.com user=www-data group=www-data threads=25
WSGIProcessGroup mynewdomain.com
WSGIScriptAlias / /home/django/mynewdomain/apache/django.wsgi
</VirtualHost>
Thanks in advance.
You are missing a line like this in your nginx config, you can place it anywhere in the server block:
proxy_set_header Host $host;