We use proxy servers all the time: we have a main server (eg http://edwards.sdsu.edu/) that serves applications (eg. http://edwards.sdsu.edu/GenomePeek) but the application itself runs on different hardware than the webserver.
Here, we show how to host a Django project on a proxy server using the apache web server and make it accessible.
First, you need your Django application up and running in your development location. Second, you need an apache server running. You should ensure that you have installed
mod_wsgi (for that, your operating system distro probably has a library you can install [e.g. with
dnf]). On the host that is exposed to the internet, you need
mod_proxy installed as well.
I am not going to show you how to do those here, there are plenty of tutorials on setting up servers. This is explicitly how to set the widgets on your host, your server, and within Django.
- The external server: https://edwards.sdsu.edu is exposed to the internet
- The server behind the proxy: http://22.214.171.124 (not its real IP addresss!)
- On that server (126.96.36.199) there is a user called
robwith a Django web application called
- We are going to make the web application appear on https://edwards.sdsu.edu/phages (it doesn’t appear there at the moment)
On the external server
This is the machine exposed to the internet, and is just a proxy server. It is going to accept the requests to https://edwards.sdsu.edu/phages and return the pages from the Django web application.
/etc/httpd/conf.d create a file called
proxypass.conf that has these two lines:
ProxyPass /phages http://188.8.131.52/phages ProxyPassReverse /phages http://184.108.40.206/phages
And now restart the
service httpd restart
systemctl restart httpd
On the application server
The main things that we need to do are:
- Set up the application server (optional)
- Set up mod_wsgi for the server
- Change permissions so that the apache user can access the application
- Configure the application
Set up the application server
This is a completely optional step. I am starting from a plain CentOS8 install and had to make a couple of tweaks:
# install apache and python virtual environment dnf install httpd mod_wsgi virtualenv # allow access through the firewall firewall-cmd --zone=public --permanent --add-service=http --add-service=https firewall-cmd --reload firewall-cmd --list-all # install elinks to test the server yum --enablerepo=PowerTools install elinks # start and enable the httpd server systemctl start httpd.service systemctl enable httpd.service
Set up mod_wsgi
There are two good tutorials that help with this set up, on the Django documentation page and on Digital Oceans. Most of the information here comes from those two sites, but I had to tweak some issues.
We are going to set up the Django wsgi call as a Daemon Process
/etc/httpd/conf.d create a file called
WSGIDaemonProcess phages python-path=/home/rob/phages:/home/rob/phages/venv/lib/python3.6/site-packages WSGIProcessGroup phages WSGIScriptAlias /phages /home/rob/phages/phages/wsgi.py Alias /static /home/rob/phages/static/ <Directory /home/rob/phages/static> Require all granted </Directory> <Directory /home/rob/phages/phages> <Files wsgi.py> Require all granted </Files> </Directory>
This sets up several items:
WSGIDaemonProcess phages python-path=/home/rob/phages:/home/rob/phages/venv/lib/python3.6/site-packagesis the WSGI Daemon. This provides it access to the root level of the phages application, and also the specific location of the site-packages in the virtual environment for this application
WSGIProcessGroup phagesjust sets up a specific process group for this application. It means that if I have two web applications on this server, they won’t stomp over each other (see the Django documentation for more information)
WSGIScriptAlias /phages /home/rob/phages/phages/wsgi.pytells the server that if a request is made to
/phagesto redirect it to the
wsgi.pyscript in my application (this is what Django uses to process your requests).
Alias /static /home/rob/phages/static/sets up any static pages in your application. Don’t forget to run
<Directory /home/rob/phages/static>provides access to all the files to everyone
<Directory /home/rob/phages/phages>only provides access to
Set up permissions
We need to set the permissions and ownership of some of our files so that apache can access them. Note, I strongly recommend you
ls -l each of these before and after
chmodding them to check the permissions!
apache user to your user’s group
usermod -a -G rob apache
Provide access to the users home directory
chmod 710 /home/rob
Provide access to the sqlite database in the web application
chmod 664 ~rob/phages/db.sqlite3
Allow the user to write to the database
chown :apache /home/rob/phages/db.sqlite3
Allow apache to access the project
chown :apache /home/rob/phages
apache to access the home directories in SELinux. If you are using SELinux (you should), you will need to set the appropriate boolean. First, find out which one:
grep httpd /var/log/audit/audit.log | audit2allow
and then check and set the status of that boolean:
getsebool httpd_read_user_content setsebool httpd_read_user_content on getsebool httpd_read_user_content
You may need to revisit this step later if you get an error when running the apache server.
Set additional permissions
Another approach to checking SELinux booleans is to use
audit2why -a | less
This will show you more detailed error messages. One in particular is worth paying attention to if it refers to a library (for example, a file ending
Missing type enforcement (TE) allow rule.
This probably means that you need to set the appropriate settings to ensure that apache is allowed to execute this code block.
chcon -R -h -t httpd_sys_script_exec_t ./venv/lib/python3.6/site-packages/FastaValidator.cpython-36m-x86_64-linux-gnu.so
Set up the Django application
Clone your repository using git
Set up a new virtual environment for your application and then activate it and use pip to install the requirements
cd phages virtualenv venv source venv/bin/activate pip3 install -r requirements.txt
Note at this point you might need to find your
site-packages to confirm the entries you added to
ls -d $PWD/$(find . -name site-packages -printf '%P\n')
Now you should be able to use the normal
manage.py to run a server on the local machine, changing the IP address as appropriate
python3 manage.py runserver 220.127.116.11
and then test that server. Note, if you are using a terminal I recommend using
You may need to edit
settings.py to make sure you can access the machine. You will need to add your outside server (the one that has the proxy on it) to
We will collect all the static files so that they are served properly:
python3 manage.py collectstatic
Now you should be able to access your site using
mod_wsgi and apache.
Start at your base URL:
If you can not access the website:
- Check you
/var/log/httpd/error_logwhile loading the page. If you see a
client denied by server configurationthen:
- Check the file that is actually trying to be accessed by that error
audit2allowto make sure SELinux is not blocking access (see above)
- restart the httpd server to make sure all changes have been applied
systemctl restart httpd.service
Cleaning up Django
Reset your SECRET_KEY and turn of DEBUG
SECRET_KEY is used in a variety of places to control access, but it is used on a per-instance basis. You should be able to reset your secret key between runs of the server.
First, generate a new secret key by starting a python console in your virtual env that has Django installed:
from django.core.management.utils import get_random_secret_key print(get_random_secret_key())
This will give you a new secret key that you can use in your application. We will put this in
local_settings.py which, by default, is ignored in version control. Create a file called in your applications (in the same directory as
local_settings.py that has these two lines:
DEBUG = False SECRET_KEY = '(v3u!gc)nf-qbwka=2%p!rsmvyjs9w8mwzv!sd1fu)w2#0ch%_'
Note: Change the SECRET_KEY to be one that is not published on a website!
settings.py and remove the two lines that define DEBUG and SECRET_KEY and instead, add this line
from .local_settings import SECRET_KEY, DEBUG
Now you can save
settings.py in version control with no issues. You just need to remember to make a
local_settings.py file on your development machine!
Note: You may also want to move
Check for deployment
Start by running the django built in tests for deployment:
python manage.py check --deploy
Writing to the server
The directions above are great for a standalone server that is going to only read from the SQL database, however there are some additional considerations that you should think about if you intend to write to the server.
First, SELinux (for good reasons) makes it very hard for apache to write to a user’s home directory. There are workarounds online, but the more appropriate solution is to move your application out of user space and into its own space, for example under
Once you have moved the directory, you will need to set the SELinux settings:
chcon -Rv --type=httpd_sys_rw_content_t /var/www/phages/
and ensure the permissions are set as above, and then you should be able to write to