Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save pmutua/4992e51e08eaaccf5bb7c85eca7ebe58 to your computer and use it in GitHub Desktop.

Select an option

Save pmutua/4992e51e08eaaccf5bb7c85eca7ebe58 to your computer and use it in GitHub Desktop.
Basic Django Server Deployment for Staging & Production

Basic Django Server Deployment for Staging & Production

Contents

Ubuntu Setup

  1. Login to server as the root user account.
  2. Run sever upgrades
$ apt-get update
$ apt-get upgrade
  1. Set server hostname.
$ hostnamectl set-hostname <server name>
  1. Add your new hostname to the /etc/hosts file.
$ nano /etc/hosts
...
127.0.1.1 <host name>
...
  1. Set the timezone for the server.
$ dpkg-reconfigure tzdata
  1. Create a user account to connect to server remotely.
$ adduser <username>
  1. Add user to the sudo group.
$ moduser -aG sudo <username>
  1. Switch to the new user account and move to their home directory
$ su <username>
$ cd ~
  1. Create a SSH key-pair on the local computer with an appropriate program (e.g. Putty, ssh-keygen); copy the public key as a single line:
ssh-rsa AAAAAAAA....123BC== your-rsa-key
  1. Create an SSH folder.
$ mkdir ~/.ssh
  1. Create an authorized_keys file and copy your public key into it.
$ nano ~/.ssh/authorized_keys
  1. Update the permissions to the SSH directory and files.
$ chmod 700 -R ~/.ssh
$ chmod 600 ~/.ssh/authorized_keys
  1. Logout and test that your SSH access works before proceeding.
  2. Once you have confirmed SSH access is working, update the SSH settings to disallow root logins, password authentication.
$ sudo nano /etc/ssh/sshd_config
...
PermitRootLogin no
...
PasswordAuthentication no
...
  1. Restart the SSH service.
$ sudo systemctl restart ssh.
  1. Configure the Universal Firewall (UFW) to allow SSH, HTTP, and HTTPS connections.
$ sudo ufw allow 22
$ sudo ufw allow 80
$ sudo ufw allow 443
  1. Enable UFW.
$ sudo ufw enable
> Command may disrupt existing ssh connections. Proceed with operation (y|n)?
$ y
  1. Install Fail2Ban.
$ sudo apt-get install fail2ban
  1. Create a local version of the Fail2ban configuration file and jail file.
$ sudo cp /etc/fail2ban/fail2ban.conf /etc/fail2ban/fail2ban.local
$ sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
  1. Start and enable Fail2Ban.
$ sudo systemctl start fail2ban
$ sudo systemctl enable fail2ban
  1. Create a user account to manage and run the Django application.
$ adduser <Django username>
  1. Grant any sudo commands that this user may need. You will want to limit these for security purposes. For example, to allow the user to restart services:
$ sudo visudo
...
# User privilege specification
root  ALL=(ALL:ALL) ALL
<user>  ALL=(ALL:ALL) /bin/systemctl restart
...

Add GitHub SSH Key

See the GitHub Help topics on Generating a new SSH key and Add the SSH key to your GitHub account for all details on this process.

  1. If not done already, create an .ssh directory
$ mkdir .ssh
  1. Create an SSH key for your Ubuntu user
$ ssh-keygen -t rsa -b 4096 -C "<your_email@example.com>"
  1. Complete the prompts to finish the creation process. If you need to use this SSH key for CI/CD purposes, you will probably leave the passphrase blank.
  2. Go to the settings for your GitHub user and then to the SSH and GPG keys section.
  1. Click on the New SSH key button and enter in a title and your key. You can quickly get your key by using the following command:
$ cat .ssh/id_rsa.pub
> ssh-rsa AAAA...== example@email.com
  1. If you have multiple SSH keys for your account you may need to add an SSH Configuration file to ensure the ssh-agent uses the right key:
$ nano .ssh/config
...
Host <name-to-identify-host> github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/<path_to_private_key>
  IdentitiesOnly yes
...

Install Python 3.x, Pip, and PipEnv

  1. Install your required python version and update any required sym links.
$ sudo apt-get install python3.x python3.x-dev
$ sudo unlink /usr/bin/python3
$ sudo ln -s /usr/bin/python3.x /usr/bin/python3
  1. Install pip and confirm the installation.
$ sudo apt install python3-pip
$ pip3 --version
pip 9.0.1 from /usr/lib/python3/dist-packages (python 3.x)
  1. Update pip.
$ sudo python3 -m pip install --upgrade pip
  1. Install pipenv.
$ sudo pip3 install pipenv

PostgreSQL Setup

  1. Install required packages
$ sudo apt-get install postgresql postgresql-contrib
  1. Log into a Postgres session
$ sudo -u postgres psql
  1. Create a database for the Django project
CREATE DATABASE <database_name>;
  1. Create a Postgres user for the Django project
CREATE USER <user_name> WITH PASSWORD '<user_password>';
  1. Set some sane defaults for the Django user
ALTER ROLE <user_name> SET client_encoding TO 'utf8';
ALTER ROLE <user_name> SET default_transaction_isolation TO 'read committed';
ALTER ROLE <user_name> SET timezone TO 'UTC';
  1. Grant all required privileges on the database to the database user
GRANT ALL PRIVILEGES ON DATABASE <database_name> TO <user_name>;
  1. If this is a development environment, you may want your user to have additional access to reset the database. The following commands will easily allow this via the django-extensions package. DO NOT PROVIDE THIS ACCESS IN LIVE ENVIRONMENTS AS IT CAN RESULT IN COMPLETE DATA LOSS.
ALTER USER <user_name> CREATEDB;
ALTER DATABASE <database_name> OWNER TO <user_name>;
  1. Exit the Psql shell
\q

Redis Setup

  1. Install Redis
$ sudo apt-get install redis-server
  1. Enable Redis to start on system boot
$ sudo systemctl enable redis-server.service
  1. Set some basic settings in the Redis configuration file (run as a daemon)
$ sudo nano /etc/redis/redis.conf
...
daemonize yes
...
  1. Restart the Redis service for the changes to take effect
$ sudo systemctl restart redis.service
  1. Confirm Redis is working with some basic commands with redis-cli
$ redis-cli

127.0.0.1:6379> ping
PONG
127.0.0.1:6379> SET <key> <value>
OK
127.0.0.1:6379> GET '<key>'
"<value>"
127.0.0.1:6379> KEYS *
1) "<key>"
127.0.0.1:6379> EXIT

Django Setup

  1. If needed, install and update your python, pip, and pipenv packages.
  2. If not done already, switch to the user account that will be running the Django app.
$ sudo su <user>
$ cd ~
  1. Clone the git repository containing the Django app (this assumes you are using a SSH authentication).
$ git clone <site:repository.git>
  1. Change to the repository directory and create your virtual environment.
$ pipenv install --dev
  1. Run any deployment scripts or commands (e.g. make deploy). You will probably need to setup environment variables, collect static files, etc.

uWSGI Setup

  1. If needed, install and update your python, pip, and pipenv packages.
  2. Install uWSGI
$ sudo pip3 install uwsgi
  1. Test that uWSGI and the django project are working properly
$ uwsgi --http :8080 --home <path/to/environment> --chdir <path/to/django/project> --wsgi-file <path/to/django/project/wsgi/file/wsgi.py>
  1. Setup the uWSGI configuration file
$ sudo nano /etc/uwsgi/sites/<site_init_file.ini>
[uwsgi]
project = <project name>
base = /home/<user directory>
pipenv = <name of pipenv environment directory>

chdir = %(base)/%(project)
home = %(base)/.local/share/virtualenvs/%(pipenv)
module = <path.to.project.wsgi.module>:application

master = true
processes = 5

socket = %(base)/%(project)/%(project).sock
chmod-socket = 666
vacuum = true

logto = <location for logs>
env = DJANGO_SETTINGS_MODULE=<path.to.project.settings.module>

uid=<user>
gid=<user>

ignore-sigpipe = true
ignore-write-errors = true
ignore-write-exceptions = true
enable-threads = true
  1. Setup the systemd script to run the uWSGI Emperor Service on startup
$ sudo nano /etc/systemd/system/uwsgi.service
[Unit]
Description=uWSGI Emperor service
After=syslog.target

[Service]
ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all

[Install]
WantedBy=multi-user.target
  1. Refresh systemctl.
$ sudo systemctl daemon-reload
  1. Start the uWSGI service.
$ sudo systemctl start uwsgi
  1. Set uWSGI to start on system boot.
$ sudo systemctl enable uwsgi
  1. Check the UWSGI service status for any issues.
$ sudo systemctl status uwsgi

SSL & Nginx Setup

  1. Install Nginx.
$ sudo apt-get install nginx
  1. Create a server block configuration file for your site.
$ sudo nano /etc/nginx/sites-available/<site_name>
server {
    listen 80;
    server_name <urls for site>;

    # Logging details
    access_log <path/to/access/log>;
    error_log <path/to/error/log>;

    # Deny illegal host headers
    if ($host !~* ^(<path.to.site.com>|<www.path.to.site.com)$) {
      return 444;
    }

    # Settings for uwsgi (if needed)
    location / {
        include         uwsgi_params;
        uwsgi_pass      unix:<path/to/uwsgi/socket>;
    }
}
  1. Create a sym for your server block to the sites-enabled folder.
$ sudo ln -s /etc/nginx/sites-available/<site_name> /etc/nginx/sites-enabled
  1. Confirm your configuration for any issues.
$ sudo nginx -t
  1. Restart the Nginx and UWSGI service to load the new configurations.
$ sudo systemctl restart nginx
$ sudo systemctl restart uwsgi
  1. Install Certbot to setup a SSL certificate.
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install python-certbot-nginx
  1. Generate the needed certificate(s). You will need to ensure your DNS settings are pointing to the server correctly before proceeding with these steps.
$ sudo certbot --nginx -d <site_url.com> -d <www.site_url.com>
  1. Set up the certificate for auto renewal by generating a cron job.
$ sudo crontab -e
...
30 3 * * 5 /usr/bin/certbot renew --quiet
...
  1. Update your Nginx server blocks to make use of the SSL certificate (if you didn't do it automatically).
$ sudo nano /etc/nginx/sites-available/<site_name>
server {
    listen 80;
    listen [::]:80;
    server_name <server_name>;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    ssl_certificate <path/to/certificate>
    ssl_certificate_key <path/to/certificate/key>
    ...
}
  1. If desired, generate a new Diffie-Hellman parameter (you can save it at /etc/ssl/certs/dhparam.pem if you need a location).
$ sudo openssl dhparam -out <path/to/save/file.pem> 2048
  1. If you created a new Diffie-Hellman parameter, you will need to update your Nginx server block to point to the new file.
$ sudo nano /etc/nginx/sites-available/<site_name>
...
ssl_dhparam <path/to/save/file.pem>;
...
  1. Confirm that your configuration is correct.
$ sudo nginx -t
  1. Restart the Nginx service to update any configuration changes.
$ sudo systemctl reload nginx
  1. You can test out your SSL certificate at SSL Labs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment