Deploying to Production

TODO: Document Jenkins CI/CD setup.

Apache httpd mod_wsgi

Our preferred environment for running Django apps is with mod_wsgi under Apache httpd. At CUIT, this is generally done with Puppet. For simplicity, I’ll just show some sample files:

/etc/httpd/conf.d/wsgi.conf:

# The WSGI Apache module configuration file is being
# managed by Puppet an changes will be overwritten.
<IfModule mod_wsgi.c>
  WSGISocketPrefix /var/run/wsgi
  WSGIPythonHome "/var/www/django-jsonapi-training/env"
  WSGIPythonPath "/var/www/django-jsonapi-training/env/lib/python3.6/site-packages"
</IfModule>

/etc/httpd/conf.d/wsgi.load:

LoadModule wsgi_module modules/mod_wsgi_python3.6.so

/etc/httpd/conf.d/10-myserver.cc.columbia.edu:

# ************************************
# Vhost template in module puppetlabs-apache
# Managed by Puppet
# ************************************

<VirtualHost *:8443>
  ServerName myserver.cc.columbia.edu

  ## Vhost docroot
  DocumentRoot "/var/www/django-jsonapi-training"

  ## Directories, there should at least be a declaration for /var/www/django-jsonapi-training

  <Directory "/var/www/django-jsonapi-training">
    Options Indexes FollowSymLinks MultiViews
    AllowOverride All
    Order allow,deny
    Allow from all
  </Directory>

  ## Logging
  ErrorLog "/var/log/httpd/myserver.cc.columbia.edu_error_ssl.log"
  ServerSignature Off
  CustomLog "/var/log/httpd/myserver.cc.columbia.edu_access_ssl.log" "virtualhost_snat" 

  ## SSL directives
  SSLEngine on
  SSLCertificateFile      "/etc/pki/tls/certs/localhost.crt"
  SSLCertificateKeyFile   "/etc/pki/tls/private/localhost.key"
  SSLCertificateChainFile "/etc/pki/tls/certs/localhost.csr"
  SSLCACertificatePath    "/etc/pki/tls/certs"
  SSLCACertificateFile    "/etc/pki/tls/certs/intermediateCAbundle.crt"
  WSGIDaemonProcess django-jsonapi-training
  WSGIProcessGroup django-jsonapi-training
  WSGIScriptAlias / "/var/www/django-jsonapi-training/wsgi.py"
  WSGIPassAuthorization On
  WSGIChunkedRequest On
</VirtualHost>

and /var/www/django-jsonapi-training/wsgi.py:

"""
Generated by Puppet. DO NOT EDIT.

WSGI config for django-jsonapi-training project.

It exposes the WSGI callable as a module-level variable named ``application``.

https://modwsgi.readthedocs.io/en/develop/user-guides/virtual-environments.html
"""

import sys
import site
import os

# Calculate path to site-packages directory.
python_home = "/var/www/django-jsonapi-training/env"
python_version = ".".join(map(str, sys.version_info[:2]))
site_packages = python_home + "/lib/python%s/site-packages" % python_version

# Add the site-packages directory.
site.addsitedir(site_packages)

from django.core.wsgi import get_wsgi_application

os.environ["DJANGO_SETTINGS_MODULE"] = "training.settings"
os.environ["DJANGO_SECRET_KEY"] = "123456789012345687890"
os.environ["DJANGO_DEBUG"] = "false"
os.environ["DJANGO_SQLSERVER"] = "true"
os.environ["DJANGO_SQLSERVER_DB"] = "mydb"
os.environ["DJANGO_SQLSERVER_USER"] = "myuser"
os.environ["DJANGO_SQLSERVER_PASS"] = "mypass"
os.environ["DJANGO_SQLSERVER_HOST"] = "mydbhost"
os.environ["OAUTH2_SERVER"] = "https://oauth-test.cc.columbia.edu"
os.environ["RESOURCE_SERVER_ID"] = "demo_resource_server"
os.environ["RESOURCE_SERVER_SECRET"] = "wL0pgS5RcNOgdOSSmejzZNA605d3MtkoXMVSDaJxmaTU70XnYQPOabBAYtfkWXay"

application = get_wsgi_application()

Make careful note to have WSGIPassAuthorization On or the Authorization header will not be passed through to the Django app. Alternatively, look into mod_auth_openidc and use the REMOTE_USER. I have not tested this approach. It depends on whether your backend server needs to introspect the Bearer token.