Using Apache to proxy requests based on URL parameter - django

I have a back-end application (Django) that requires its static content (assets like images, scripts, stylesheets, etc.) to be served by a web server.
At current, I have my Django application serving on localhost:5000. I have this sitting behind an Apache2 server virtual host that is using mod_proxy to send requests to the Django app in the back.
I need to configure my VHost so that all of the URI requests for domain.com/static/asset will serve the asset from /path/to/asset statically, while everything else gets proxied to the back-end app localhost:5000.
My VHost config looks like this at the moment, the commented bits don't work properly.
<VirtualHost *:80>
ServerName www.domain.com
ServerAlias domain.com
ServerAdmin info#domain.com
ErrorLog ${APACHE_LOG_DIR}/domain_error.log
CustomLog ${APACHE_LOG_DIR}/domain_access.log combined
ProxyRequests Off
ProxyVia Off
<Proxy *>
Require all granted
</Proxy>
# DocumentRoot /path/to/static
# <Directory /path/to/static/>
# Require all granted
# </Directory>
ProxyPass / http://localhost:5000/
ProxyPassReverse / http://localhost:5000/
</VirtualHost>

Related

Apache Reverse Proxy using mod_proxy

0 Introduction
I'm trying to setup a server with a main website hosted on ports 80 and 443 (let's call it example.com) and a section on this website that serves umami analytics hosted on port 3000 (let's call it umami.example.com) using a reverse proxy.
I'm using Django and Apache (with mod_wsgi as hinted from the django project) and I have to setup DNS using Cloudflare.
The main website works as intended, redirecting http traffic to https (more on that on the Apache section) and I'm tring to add this section under umami.example.com but every request ends up in a 404 error given by my main website.
Currently I'm trying to make the umami part work using a reverse proxy (as shown in the first section of the Apache Config)
####################################################################
1 DNS
DNS are configured using Cloudflare with 3 A records:
example.com -> server IP address
umami -> same server ip
www -> again same ip
and some MX and TXT ones.
####################################################################
2 Apache Config
<VirtualHost _default_:80>
ServerAdmin admin#example.com
ServerName umami.example.com
ProxyPass "/" "http://127.0.0.1:3000/"
ProxyPassReverse "/" "http://127.0.0.1:3000/"
</VirtualHost>
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
<VirtualHost _default_:443>
ServerAdmin admin#example.com
ServerName example.com
ServerAlias www.example.com
Alias /static /mainfolder/static
DocumentRoot /mainfolder/django-folder
<Directory /mainfolder/django-folder/static>
Require all granted
</Directory>
<Directory /mainfolder/django-folder/django-app>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
WSGIDaemonProcess django-folder python-path=/mainfolder/django-folder python-home=/usr/local/env
WSGIProcessGroup django-folder
WSGIScriptAlias / /mainfolder/django-folder/django-app/wsgi.py
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
</VirtualHost>
####################################################################
3 What I've tried
Connecting directly to the IP address bypassing the DNS (port 80) makes no difference.
Connecting directly to the IP address bypassing the DNS (port 3000) works as intended.
Swapping places on the Apache Config works like this:
When the reverse proxy comes first (the config is as posted) then connecting to the 80 port serves the analytics website.
When the redirect comes first (swapped) connecting to the 80 port redirects to the HTTPS website
Adding and removing ProxyPreserveHost makes no difference.

Adding a Django site breaks my virtual hosts on CentOS 7

I have a CentOS 7 server with about 20 domains all managed automatically with a vhosts file in /etc/httpd/conf.d.
I am trying to learn Django and wanted to set up a single domain using it, so I added a specific virtualhost to the .conf file.
The result is that the Django domain works fine but all the other sites are broken (try to use Django but cause errors).
The Django domain has two folders: djangodomain.com for static files and djangodomain.app for the Python files.
How can I integrate a single Django domain into my existing many-domain virtual host setup?
Existing vhosts.conf:
<VirtualHost *:80>
serveradmin username#domain.com
serveradmin username#domain.com
usecanonicalname off
# www.site.com ยป site.com
rewriteengine on
rewritecond %{HTTP_HOST} ^www\.(.*)$ [nc]
rewriterule ^(.*)$ http://%1 [r=301,l]
# file locations
virtualdocumentroot "/home/username/%0"
<directory "/home/username/*">
allowoverride all
require all granted
options indexes followsymlinks
options +execcgi
options +includes
</directory>
</VirtualHost>
What I added that broke all but the Django site:
<VirtualHost djangodomain.com:80>
ServerName djangodomain.com
ServerAlias www.djangodomain.com
ServerAdmin user#domain.com
DocumentRoot /home/username/djangodomain.com
WSGIScriptAlias / /home/username/djangodomain.app/django.wsgi
<Directory /home/username/djangodomain.app>
Order allow,deny
Allow from all
</Directory>
Alias /robots.txt /home/username/djangodomain.com/robots.txt
Alias /favicon.ico /home/username/djangodomain.com/favicon.ico
Alias /images /home/username/djangodomain.com/images
Alias /static /home/username/djangodomain.com/static
ErrorLog /home/username/djangodomain.logs/error.log
CustomLog /home/username/djangodomain.logs/access.log combined
</VirtualHost>
Crossposted to unix.stackexchange.com
When Apache gets an HTTP request, it needs to know what virtual host is supposed to process this request. Now, the way it works is. Apache picks up the IP address that the client request came into (the server IP, not the client) and it goes through the list of virtual host definitions to find any virtual hosts defined for that IP. If there is more than one, it will look at the Host header and try to match it to a particular ServerName or ServerAlias directive. If it still cannot find one, it will look for a default virtual host.
You have two virtual host definitions. One if the default vhost on port 80 <VirtualHost *:80>. It is the default because it has * for IP. The other is specific for the IP address <VirtualHost djangodomain.com:80>. The IP it uses is whatever djangodomain.com resolves to.
So any request that comes to that IP will be handled by the IP specific config before it might be allowed to drop into default.
To fix this, you need to replace your django virtual host directive with <VirtualHost *:80>, same as your other vhosts. This should put them all at the same parsing priority and it will just use the Host header to figure out the rest.
The said, if you are running a web server with 20+ vhosts, you really need to have better understanding on how it works. Read up on HTTP and web hosting when you have the time.

How to configure apache2 on ubuntu for django restful services

I have django restful services on my ubuntu server which are running on port 84.
When the request is send, it come through the apache2 server which is running on port 80.
Now let say my server ip is "xx.xx.xx.10" and when i call with this url http://xx.xx.xx.10/user where user is the rest service running on django rest framework on port 84. Then the request should go to my django rest service through apache2 and return the desired output.
I tried by using the below configuration in the apache2 :-
<VirtualHost *:80>
WSGIScriptAlias / /myproject/myapp/test/wsgi.py
<Directory "/myproject/myapp/test/">
<Files "wsgi.py">
Require all granted
</Files>
</Directory>
</VirtualHost>
but this is giving internal error saying that test.settings does not exits.
is this the right way to configure the restful services running on different port on apache server.
Did you specify a python path? If you don't, import mysite will not work.
WSGIPythonPath /path/to/mysite.com
For more info see: Django docs modWSGI
I have solved this issued by using the below configurations :-
<VirtualHost *:80>
ServerName mydomain
ServerAlias *.mydomain
ProxyRequests off
ProxyPass / http://localhost:84/
ProxyPassReverse / http://localhost:84/
</VirtualHost>

Reconfiguring Apache to serve website root from new php source and specific sub-urls from old django site

How do I make a django website (in a apache/mod_wsgi/django setup) which is configured to serve from the root url, serve only for specific sub-url but not the root url? The root url shall be served from a new source (php). All this with a minimum of reconfiguration.
Currently the condensed virtualhost config looks like this
<VirtualHost *:80>
ServerAdmin admin#mysite.com
ServerName mysite.com
# mappings to django
WSGIScriptAlias / /opt/mysite/mysite.wsgi
<Directory /opt/mysite>
Order allow,deny
Allow from all
</Directory>
# mappings to wordpress
Alias /wp/ /var/www/mysiteWP/
<Location "/var/www/mysiteWP/">
Options -Indexes
</Location>
Alias /show/ /var/www/mysiteWP/
Alias /collection/ /var/www/mysiteWP/
</VirtualHost>
As you can see django and php(wordpress) are running side by side. Wordpress just serving mysite.com/show/ and mysite.com/collection/. Django is serving the rest, including the root url mysite.com. This configuration works.
What I want to do now, is, I want to make wordpress serve everything except some specific urls which should be served by django. E.g. django should just serve mysite.com/shop/ and mysite.com/news/ but nothing else, also excluding mysite.com.
How would I do this with a minimum of reconfiguration?
Thanks for your answers and hints.
Props to Graham Dumpleton. He answered another question of the exact same kind in this Q&A: Django (wsgi) and Wordpress coexisting in Apache virtualhost.
In short, after configuring Apache so the root url is served from php, the solution to route specific sub urls to django, but making it think its mount point is still the root, is WSGIScriptAliasMatch.
To this (example)problem the simple addition to the apache virtual host config was this:
WSGIScriptAliasMatch ^(/(shop|news)) /opt/mysite/mysite.wsgi$1
The whole virtual host config for this example is:
<VirtualHost *:80>
ServerAdmin admin#mysite.com
ServerName mysite.com
# mappings to django
WSGIScriptAliasMatch ^(/(shop|news)) /opt/mysite/mysite.wsgi$1
<Directory /opt/mysite>
Order allow,deny
Allow from all
</Directory>
# mappings to wordpress
DocumentRoot /var/www/mysiteWP/
<Location "/var/www/mysiteWP/">
Options -Indexes
</Location>
</VirtualHost>

apache mod_wsgi basic authentication for django app

I've finished a first website based on django and I'm ready to deploy on a liveserver. However, I don't want this site to be visible to the public for now while tweaking and testing.
On PHP sites I always used basic http authentication via .htaccess to make last changes. This is a two liner which denies access for the whole site.
Ideally I want to run a environment like this:
static.mydomain.com (served by apache2 for static files)
mydomain.com (served by apache2 with mod_wsgi latest stable release -> available for public)
dev.mydomain.com (served by apache2 with mod_wsgi dev/testing -> not available for public (basic authentication))
Can this be done with django/apache2/mod_wsgi?
You could setup basic auth for your virtual host dev.mydomain.com. Look at http://httpd.apache.org/docs/2.2/mod/mod_auth_basic.html and http://httpd.apache.org/docs/2.2/vhosts/name-based.html for more details
EDIT: Your virtual host config will look somthing like:
<VirtualHost *:80>
ServerName mydomain.com
DocumentRoot /srv/www/wsgi
<Directory /srv/www/wsgi>
Order allow,deny
Allow from all
</Directory>
WSGIScriptAlias / /srv/www/wsgi/app.wsgi
</VirtualHost>
<VirtualHost *:80>
ServerName dev.mydomain.com
DocumentRoot /srv/www/wsgi-dev
<Directory /srv/www/wsgi-dev>
Order allow,deny
Allow from all
</Directory>
WSGIScriptAlias / /srv/www/wsgi-dev/app.wsgi
<Location />
AuthType Basic
AuthName "Restricted Files"
AuthUserFile /usr/local/apache/passwd/passwords
Require valid-user
</Location>
</VirtualHost>
mod_wsgi doesn't care if you use HTTP auth over it. The only provision would be that if you want it to be visible to the WSGI application then you'd need to use WSGIPassAuthorization, but this is not a concern in this case since Django has its own authentication scheme independent of HTTP auth.