2018-10-08 23:33:08 -04:00
2018-09-19 20:56:13 -04:00
2018-09-27 21:58:28 -04:00

Django Setup for CentOS 7

Install

vim vars
# django project settings
export user=""              <-- give the user you want to own the site
export projectname=""       <-- give your project a friendly name
export hostname=""          <-- add your hostname (can be an IP address)
export usegit=False         <-- if you have an existing project, set to True
export giturl=""            <-- put the url for the git repo here
export gitkey=""            <-- put the path to the ssh key git will use here
sudo ./install.sh

Reset

If anything goes wrong with the project and you don't want to perform a full uninstall:

sudo ./reset

will reset the project but leave the dependencies installed. You can rerun the installer with different variables to fix what was incorrect. WARNING: This will delete your project (including your database)

Uninstall

To completely remove every trace of the project from your server:

sudo ./uninstall

This will completely remove everything.

A more detailed explanation

vars

# Django project settings
user="centos"
projectname="mysite"
hostname="centos.duco.net"
letsencrypt=False

# set True if CentOS minimal install
install_epel_release=False

# general install settings
logdir="/var/log/djangosetup/"
yumlogloc=$logdir"yum.log"
yumlogmsg="See $yumlogloc for more info."
firelogloc=$logdir"firewall.log"
firelogmsg="See $firelogloc for more info."
pylogloc=$logdir"python.log"
pylogmsg="See $pylogloc for more info."
djalogloc=$logdir"django.log"
djamsg="See $djalogloc for more info."
gunicornlogloc=$logdir"gunicorn.log"
nginxlogloc=$logdir"nginx.log"

# Python settings
pylink="https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz"

These variables can (and should) be changed to match your configuration needs. For example: any of the "logloc" log location variables can be changed to log somewhere else. The "logmsg" log message variables can be changed to reflect different log locations or output a custom message.

The Django Project Settings variables should be changed to match your configuration. You have (essentially) 3 options for user configuration:

  1. user = "[primary (sudo) user here]"
  2. user = "nginx"
  3. user = "[other user]"

My recommendation is to use nginx as the user. The installer takes care of creating a home directory for nginx and setting permissions. Of course there is no problem with specifying another user. The installer will automatically add a user and assign permissions. Setting the user to the primary sudo account is risky but the installer won't complain if you do it quietly.

The projectname variable can be whatever you want. When Django starts the project it will use this name.

The hostname will be inserted into "ALLOWED_HOSTS" in your app settings. Multiple hosts are not supported at the moment so set this to the address you'll test with. You can add additional hosts by manually editing settings.py.

install_epel_release=True

If you are installing this on a system with the minimal CentOS build you'll need install_epel_release to be True. epel_release installs nginx. Kinda hard to run the site without that.

Install

Dependencies

In order for this script to work its magic you'll need a few packages provided by Yum. This part is likely to break due to Yum's inconsistency accross distributions, firewall and proxy configurations, and whether CentOS had its morning coffee.

# check if root
if [[ $EUID -ne 0 ]]; then
   echo -e "This script must be run as root" 
   exit 1
fi
cd /root/

tput setaf 2
echo -e "Installing dependencies"
tput setaf 0
# create necessary dirs
if [ ! -d $logdir ] ; then
	mkdir $logdir
fi
if [ $install_epel_release = True ] ; then
    yum -y install epel-release 1>> $yumlogloc 2>> $yumlogloc 3>> $pylogloc
fi

The first part of the script is fairly straight forward. If you aren't root user, the installer can't use yum and won't work. After checking if you are the root user it creates the necessary directories to prevent future complaints and installs the aforementioned epel-release package if you want it.

# install dependencies
packages=(gcc wget nginx libsqlite3x-devel.x86_64 postgresql-server postgresql-devel postgresql-contrib bzip2-devel zlib-devel libffi-devel openssl-devel policycoreutils-python.x86_64)
for package in ${packages[@]};
do
    echo -e "\tInstalling $package"
    yum -y install $package 1>> $yumlogloc 2>> $yumlogloc 3>> $yumlogloc
    if [ $? -ne 0 ] ; then
        echo -e "yum failed to install $package. $yumlogmsg"
        exit 1
    fi
done

The next part of the script installs yum dependencies. The script verifies that the installation goes smoothly and exits if an error occurs.

Firewall

# set firewall
echo -e "firewall-cmd --zone=public --add-port=80/tcp --permanent" > $firelogloc
firewall-cmd --zone=public --add-port=80/tcp --permanent >> $firelogloc
if [ $? -ne 0 ] ; then
	echo -e "firewall failed to update port 80 correctly (this may not be an issue). $firelogmsg"
fi

echo -e "firewall-cmd --zone=public --add-port=443/tcp --permanent" >> $firelogloc
firewall-cmd --zone=public --add-port=443/tcp --permanent >> $firelogloc
if [ $? -ne 0 ] ; then
	echo -e "firewall failed to update port 443 correctly, (this may not be an issue). $firelogmsg"
fi

echo -e "firewall-cmd --reload" >> $firelogloc
firewall-cmd --reload >> $firelogloc
if [ $? -ne 0 ] ; then
	echo -e "firewall failed to reload, (this may not be an issue). $firelogmsg"
fi

echo -e "semanage permissive -a httpd_t" >> $firelogloc
semanage permissive -a httpd_t >> $firelogloc
if [ $? -ne 0 ] ; then
	echo -e "semanage failed to set permissive. See $firelogmsg"
	exit 1
fi

The firewall commands are specific to a CentOS 7 minimal install. You may not need them. The installer doesn't really care if they fail because they aren't mission critical. It'll yell at you and that's about it.

The semanage command fixes an issue where the websocket would be inaccessible after an install.

Python

wget $pylink 1> $pylogloc 2>> $pylogloc
if [ $? -ne 0 ] ; then
	echo -e "Failed to fetch python, make sure wget is installed and $pylink is what you're after. $pylogmsg"
    exit 1
fi

After configuring the firewall the script will fetch Python from the link provided.

echo -e "\tConfigure"
./configure --prefix /usr/src/python37 1>> $pylogloc 2>> $pylogloc
if [ $? -ne 0 ] ; then
	echo -e "./configure failed. $pylogmsg"
    exit 1
fi
echo -e "\tMake"
make 1>> $pylogloc 2>> $pylogloc
if [ $? -ne 0 ] ; then
	echo -e "make failed. $pylogmsg"
    exit 1
fi
echo -e "\tMake altinstall"
make altinstall 1>> $pylogloc 2>> $pylogloc
if [ $? -ne 0 ] ; then
	echo -e "make altinstall failed. $pylogmsg"
    exit 1
fi

If you've ever installed Python from source this part should look familiar. The script uses wget to download the version of python provided by $pylink. It uses alt install to prevent conflict with previous versions of Python (I've been told CentOS will break if it can't find Python 2, a real problem if you use make install).

You could get rid of this section and do it yourself with another version of Python. As long as Python can be found at $pyinstalldir and it has Django support the installer will continue to chug along happily.

The script will automatically update pip and install virtualenv.

Django

id -u $user > /dev/null
if [ $? = 0 ]; then
    adduser $user
fi
if [ ! -d "/home/$user" ] ; then
	mkdir /home/$user
    chown -R $user:$user /home/$user
fi
mkdir /home/$user/$projectname
if [ $? -ne 0 ] ; then
	echo -e "Failed to create $projectname directory. $djamsg"
    exit 1
fi

Installing Django starts by checking if the user you provided exists. If it doesn't then it adds the user and creates a home directory. It then creates the project directory using the provided project name.

echo -e "\tCreating venv"
cd /home/$user/
/usr/src/python37/bin/python3.7 -m virtualenv $projectname/venv 1>> $djalogloc 2>> $djalogloc
if [ $? -ne 0 ] ; then
	echo -e "Failed to create virtual environment. $djamsg"
    exit 1
fi
source $projectname/venv/bin/activate >> $djalogloc
if [ $? -ne 0 ] ; then
	echo -e "Failed to source virtual environment. $djamsg"
    exit 1
fi

The next part of the script creates a virtual environment based on your Python install.

# pip installs
pips=(django gunicorn psycopg2-binary)
for pip in ${pips[@]};
do
    echo -e "\tInstalling $pip"
    pip install $pip >> $djalogloc
    if [ $? -ne 0 ] ; then
    	echo -e "Failed to install $pip. $djamsg"
      exit 1
    fi
done

The script then installs the necessary pip packages.

# start django project
echo -e "\tStarting django project"
cd $projectname
django-admin startproject $projectname >> $djalogloc
if [ $? -ne 0 ] ; then
	echo -e "Failed to start project $projectname with django-admin. $djamsg"
    exit 1
fi

Next the script starts the Django project. You'll notice that the project structure looks like this:

[projectname]/
├──  [projectname]/
│    ├── [projectname]/
│    │   ├── __init__.py
│    │   ├── settings.py
│    │   ├── urls.py
│    │   └── wsgi.py
│    └── manage.py
└──  venv/

When making changes to nginx or gunicorn it's important to keep this structure in mind. There are 3 folders called $projectname.

After this, the script updates allowed hosts, collects static, and makes migrations.

Gunicorn

echo -e "
[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=$user
Group=nginx
WorkingDirectory=/home/$user/$projectname/$projectname
ExecStart=/home/$user/$projectname/venv/bin/gunicorn --workers 3 --bind unix:/home/$user/$projectname/$projectname.sock $projectname.wsgi:application

[Install]
WantedBy=multi-user.target" > /etc/systemd/system/gunicorn.service

The gunicorn and nginx installs are very similar. The gunicorn "install" is just a .service file that gets placed in /etc/systemd/system/. As seen above, the install command just echoes the service file into the right place.

Nginx

echo -e "
server {
    listen 80;
    server_name $hostname;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/$user/$projectname/$projectname;
    }

    location / {
        proxy_set_header Host \$http_host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
        proxy_pass http://unix:/home/$user/$projectname/$projectname.sock;
    }
}" > /etc/nginx/conf.d/$projectname.conf

The nginx install copies a configuration file to the nginx configuration directory. The only complication here is:

if [ ! $user = "nginx" ] ; then
    sed -i "s/user nginx/user $user nginx/" /etc/nginx/nginx.conf
fi

Which inserts the specified user (if not nginx) into nginx.conf. The script finishes by enabling gunicorn and nginx at startup.

Description
Automatic django-gunicorn-nginx installer for CentOS
Readme MIT 108 KiB