Sentdex Django Deploy

by sentdex
80 deployments · 65 still active · last rev. 6 months ago

Initial setup and basic configuration for a Django project in Production. The script setup gets you to the point your domain name pointing to a basic django "it works" example.

Compatible with: Ubuntu 16.04 LTS, Ubuntu 18.04 LTS
# Sentdex's Django tutorial serie deployment script
# Learn more:
# UDF tags (adds fields during deployment using that StackScript):
# <UDF name="domain" Label="Domain name (if you have a domain pointing to IP address of that host) otherwise leave empty" default="" example="" />
# <UDF name="project_name" Label="Django project name" default="mysite" example="mysite" />
# <UDF name="server_type" Label="Server type" default="production" oneOf="production,test" />

# Update package list
apt-get update

# First we need to set some environmental variables
# If domain is empty, set default domain eg.
# First get public IP by checking for it in default route to external host
# Then get PTR record from revdns query, and strip trailing period
if [ -z $DOMAIN ]
    # Needed to use `host` utility
    apt-get install -y dnsutils
    # Get IP for default route for external connections
    IP=`ip route get | head -1 | awk '{print $7}'`
    # Get domain from PTR record
    DOMAIN=`host $IP | awk '{print $5}' | rev | cut -c 2- | rev`

# If project name is empty - set to mysite
if [ -z $PROJECT_NAME ]

# Install pip for Python 3
# First install official pip, then update it
apt-get install -y python3-pip
python3 -m pip install --upgrade pip

# Install Django and TinyMCE for Django
python3 -m pip install django django-tinymce4-lite

# Create and enter www root folder
mkdir /var/www
cd /var/www

# And create Django project
django-admin startproject $PROJECT_NAME

# Enter project's folder

# If production deployment, we need to set couple of things
if [[ $SERVER_TYPE == "production" ]]

    # Set allowed host to domain name in project's
    # Example of result - replaces
    # ALLOWED_HOSTS = []
    # with
    # ALLOWED_HOSTS = ['']
    # or with a domain name user entered
    sed -i -E "s/ALLOWED_HOSTS = \[[^]]*\]/ALLOWED_HOSTS = ['$DOMAIN']/" $PROJECT_NAME/
    # Disable debug mode in project
    sed -i "s/DEBUG = True/DEBUG = False/" $PROJECT_NAME/
    # Add "It works" app
    python3 startapp it_works
    # Add new app in urls - first add import (include) in - before:
    # from django.urls import path
    # after:
    # from django.urls import path, include
    sed -i "s/from django.urls import path/&, include/" $PROJECT_NAME/
    # Then add our new path in urlpatterns:
    # path('', include('it_works.urls')),
    sed -i "/urlpatterns = \[/a\ \ \ \ path('', include('it_works.urls'))," $PROJECT_NAME/
    # Create in new app
    cat > it_works/ <<EOF
from django.urls import path
from . import views

app_name = 'it_works'

urlpatterns = [
    path("", views.homepage, name="homepage"),

    # Create in new app
    cat >> it_works/ <<EOF
from django.http import HttpResponse
def homepage(request):
    return HttpResponse("It works! (served from Django)")

# ELSE part of IF statement above
# Test deployment (not production)
    # Set allowed host to wildcard (good enough for testing)
    sed -i -E "s/ALLOWED_HOSTS = \[[^]]*\]/ALLOWED_HOSTS = ['*']/" $PROJECT_NAME/

    # There's no need to create anything here like above
    # Django will serve default page because DEBUG = False

# Install Apache and mod_wsgi for Python 3
apt-get install -y apache2 libapache2-mod-wsgi-py3

# Disable Apache's signatures (security) on error pages / in headers
# Adds at the end of Ahace config file
cat >> /etc/apache2/apache2.conf <<EOF

# Disable server signatures
ServerTokens Prod
ServerSignature Off

# If production deployment
if [[ $SERVER_TYPE == "production" ]]

    # Replace default virtualhost in Apache to show 404 Not Found instead of serving our site
    cat > /etc/apache2/sites-available/000-default.conf <<EOF
<VirtualHost *:80>
    ServerName _
    Redirect 404 /

# Else if test deployment
    # Disable default vhost so even when requesting by IP, Apache will server our Django project
    a2dissite 000-default

# Create new virtualhost for our project:
cat > /etc/apache2/sites-available/$PROJECT_NAME.conf <<EOF
<VirtualHost *:80>
    ServerName $DOMAIN

    ErrorLog \${APACHE_LOG_DIR}/$PROJECT_NAME-error.log
    CustomLog \${APACHE_LOG_DIR}/$PROJECT_NAME-access.log combined

    WSGIDaemonProcess $PROJECT_NAME processes=2 threads=25 python-path=/var/www/$PROJECT_NAME
    WSGIProcessGroup $PROJECT_NAME
    WSGIScriptAlias / /var/www/$PROJECT_NAME/$PROJECT_NAME/

    Alias /robots.txt /var/www/$PROJECT_NAME/static/robots.txt
    Alias /favicon.ico /var/www/$PROJECT_NAME/static/favicon.ico
    Alias /static/ /var/www/$PROJECT_NAME/static/
    Alias /media/ /var/www/$PROJECT_NAME/media/

    <Directory /var/www/mysite/$PROJECT_NAME>
            Require all granted

    <Directory /var/www/$PROJECT_NAME/static>
        Require all granted

    <Directory /var/www/$PROJECT_NAME/media>
        Require all granted

# Enable our vhost in Apache
a2ensite $PROJECT_NAME

# Reload Apache (loads new configuration)
systemctl reload apache2