Single-file deploy Django to a generic Ubuntu host

Full-automatic, copy-paste Nginx/Gunicorn/Let’s Encrypt HTTPS set up in minutes

Django Viewflow
4 min readDec 4, 2019

Fresh Django project deployment always looks a bit cumbersome. Bunch of script files, configurations, and container infrastructure setup time could take more time than an actual MVP project. This article describes a way to deploy to a generic Ubuntu host, just with a single tool — Ansible, and the one-file deployment script.

The deployment could be really handy to get into production just after startproject/startapp commands, and before hiring a first member of your DevOps team.

If you already use Pipenv and Django-Environ just grab deploy.yml put it into your project and go down to “Let’s deploy” section

Project set up

Here is the quick tutorial, how to get from ./manage.py start project to a codebase that is ready to deploy.

The only tool that we need on the host is the Pipenv. If you already have python set up on your machine, it’s likely that you already have pip tool installed. So just run

pip install --user pipenv

Or you could install pipenv tool globally with your system package manager. Installation details could be found in the Pipenv documentation.

Let’s create a directory for our project and go into it

mkdir mysite && cd mysite/

It’s time to install project dependencies. Pipenv creates a separate virtual environment to install packages into and Pipfile to keep the project dependencies list.

pipenv install django django-environ --python=python3.7

Start the Django project

pipenv run django-admin startproject config .

Please note the last dot. It means we are creating a project within the current directory. The pipenv run command activates the virtual environment with installed packages and executes the command. When you need to run the project ./manage.py command, you may activate the virtual environment with pipenv shell or run the command directly as pipenv run ./manage.py ...

At this time we have following set up

mysite/
├── config/
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
├── Pipfile
└── Pipfile.lock

For deploying, let’s modify config/settings.py to use django-environ instead of hardcoded values.

You may follow django-enviton tutorial, or get sample code from this article. Set up DEBUG,SECRET_KEY, ALLOWED_HOSTS andDATABASES configuration parameters:

import os
import environ
from pathlib import Path
# Build paths inside the project
BASE_DIR = Path(__file__).resolve(strict=True).parents[1]
# configure django-environ to run in dev mode without .env file
env = environ.Env(
DATABASE_URL=(str, 'sqlite:///sqlite.db'),
DOMAIN_NAME=(str, '127.0.0.1'),
DEBUG=(bool, False),
SECRET_KEY=(str, '{{ secret_key }}'),
)
env.read_env(BASE_DIR / '.env') if os.path.exists(BASE_DIR / '.env') else None
DEBUG = env.bool('DEBUG')ALLOWED_HOSTS = [env.str('DOMAIN_NAME')]SECRET_KEY = env.str('SECRET_KEY')DATABASES = {
'default': env.db()
}

In addition, set up folders for static/ files and uploaded media/

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

Let’s deploy

It’s time to deploy. At this moment you should get the domain, have running a Linux host in a cloud, and proper DNS configuration. Check that you have the ssh access to your server, with your domain name

ssh root@yourdomain.com

You may also create a user with sudo rights and use it instead root

We're going to use Ansible to deploy our project, let’s install it with pipenv as a development dependency:

pipenv install -d ansible

And run the deployment. During the first time, you will be asked for an email for Let’s Encrypt certificate registration.

pipenv run ansible-playbook -i yourdomain.com, -u root deploy.yml

Use a proper domain name instead of yourdomain.com and custom user, if you have it, instead of root. Please note the comma after the domain name. It’s required and tells Ansible that we have provided a domain name, instead of an inventory file name.

What you’ve just done

  • All code from the local folder was synchronized to /srv/yourdomain.com on your server
  • Postgresql / Nginx / Gunicorn tools installed
  • Let’s encrypt certificated requested and installed

https://yourdomain.com — ready to serve to you!

Have a problem?

Please read the troubleshooting guide at the repository Feel free to report bugs or ask questions in issues!

FAQ

  • Do you have ready to use project template?

Sure, just start with it:

django-admin.py startproject --template=https://github.com/viewflow/django-skinny-deploy/archive/template.zip mysite
  • What about celery and channels?

That’s our issue #1 and #2

  • Is it suitable for production?

For a small-sized project, you do the best that can be done in a few minutes. In addition, you need to go through the Django deployment checklist, hardened your server at least with fail2ban installation and set up backups.

Actually, start with setting up backups first, please.

  • Why no docker?

That would be one of the next articles! Docker adds a lot of complexity to a whole setup, but it can’t be avoided for complex projects. Subscribe to get notified on how to use Helm to set up k8s cluster for a Django project.

  • Why no poetry?

Many poetry design decisions would make this tutorial longer. Besides that currently pre-released 1.0 version is broken, whereas previous stable 0.12 has major show stoppers like #522

--

--