[PYTHON] To you who are cornered by deploying Django. Django 2.2 deployment full version on Ubuntu 18.04 + Nginx

Introduction

Since I was a beginner, I intend to write it for beginners. If you have any questions or mistakes, please leave a comment.

I said it's a complete version, but unlike most articles, I won't explain it from the creation of the project.

It feels like Django 3.0 has just been released, but I don't think it will change that much with Django 3.0. It worked fine within the range I did.

environment

Premise

Local preparation

Directory structure at the ready stage

YourProjekutName
        ├ YourProjectName
        │     ├ __init__.py
        │     ├ settings
        │     │     ├ __init__.py
        │     │     ├ base.py
        │     │     ├ local.py
        │     │     └ production.py
        │     ├ urls.py
        │     └ wsgi.py
        ├ YourAppName
        │     ├ migrations
        │     │     └ __init__.py
        │     ├ __init__.py
        │     ├ admin.py
        │     ├ apps.py
        │     ├ models.py
        │     ├ tests.py
        │     ├ urls.py
        │     └ views.py
        ├ collected_static
        ├ media
        ├ static
        │     ├ css
        │     ├ images
        │     └ js
        └ templates

Rewrite YourProjectName / settings.py

It may be more accurate to remake it than to rewrite it.

YourProjectName/settings/base.py


import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

INSTALLED_APPS = [
    'YourAppName',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'YourProjectName.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'django.template.context_processors.static',
            ],
        },
    },
]

WSGI_APPLICATION = 'YourProjectName.wsgi.application'

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'Asia/Tokyo'

USE_I18N = True

USE_L10N = True

USE_TZ = True

STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
STATIC_ROOT = os.path.join(BASE_DIR, 'collected_static')

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

YourProjectName/settings/local.py


from .base import *

SECRET_KEY = 'Secret Key Written on settings.py'

DEBUG = True

ALLOWED_HOSTS = []

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

YoutProjectName/settings/production.py


from .base import *

SECRET_KEY = 'Secret Key Written on settings.py'

DEBUG = False

ALLOWED_HOSTS = ['YourHostName']

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

Details will be added later.

Create a collected_static folder in the top directory

I'll see why later.

Directory structure at the ready stage

YourProjekutName
        ├ YourProjectName
        │     ├ __init__.py
        │     ├ settings
        │     │     ├ __init__.py
        │     │     ├ base.py
        │     │     ├ local.py
        │     │     └ production.py
        │     ├ urls.py
        │     └ wsgi.py
        ├ YourAppName
        │     ├ migrations
        │     │     └ __init__.py
        │     ├ __init__.py
        │     ├ admin.py
        │     ├ apps.py
        │     ├ models.py
        │     ├ tests.py
        │     ├ urls.py
        │     └ views.py
        ├ collected_static
        ├ media
        ├ static
        │     ├ css
        │     ├ images
        │     └ js
        └ templates

Push to GitHub

When moving data from the development environment to the production environment, I will use GitHub considering future development. It is recommended to specify \ _ \ _ pychache \ _ \ _, db.sqlite3, collected_static / * in .gitignore to exclude it from git target.

Operation on the server

I think it was difficult to prepare, but now it's time to go live. I will write it for the time being, but from now on, it will be an operation on the server.

Firewall settings

Please open port 80. Be sure to restart the firewall service with sudo systemctl restart.

Nginx installation

sudo apt install nginx

Nginx settings

At this stage, type in your domain in your browser and you should see Welcome to nginx !. If it does not appear, the installation may have failed, the firewall settings may not be correct, or the settings around the domain or name server may not be correct.

First, edit the following part.

/etc/nginx/nginx.conf


# user www-data;
user webmaster;

Please create a new file below.

/etc/nginx/sites-available/YourProjectName


server {
    server_name YourHostName;

    location /static {
        alias /home/webmaster/YourProjectName/collected_static;
    }

    location /media {
        alias /home/webmaster/YourProjectName/media;
    }

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header X-Forwarded_For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Symbolic link

sudo ln -s /etc/nginx/sites-available/YourProjectName /etc/nginx/sites-enabled/YourProjectName

User: Create webmaster

sudo adduser webmaster

Clone project

Clone the project you just pushed to GitHub locally. The important thing to note here is to clone it in the user directory (/ home / webmaster /) of the user (webmaster) you just created.

Python environment construction

Often, there are many articles about building virtual environments, which is preferable, but it's annoying and for some reason it didn't work, so I'll do it normally.

Install Python 3.8

sudo apt install python3.8 python3.8-dev python3-pip

Install package with pip

What you need here is a package called Gunicorn as well as Django.

sudo python3.8 -m pip install django gunicorn

Be sure to install any other packages required for the created project.

This time, the operation check of Gunicorn is omitted.

migrate and collectstatic

python3.8 manage.py makemigrations --settings YourProjectsName.settings.production
python3.8 manage.py migrate --settings YourProjectsName.settings.production
python3.8 manage.py collectstatic --settings YourProjectsName.settings.production

Daemon with Gunicorn

Daemonization

sudo gunicorn --daemon --bind 127.0.0.1:8080 YourProjectName.wsgi:application

Add service

Please create a new file below.

/etc/systemd/system/YourProjectName.service


[Unit]
Description=gunicorn
After=network.target

[Service]
WorkingDirectory=/home/webmaster/YourProjectName
ExecStart=/usr/local/bin/gunicorn --bind 127.0.0.1:8080 YourProjectName.wsgi:application

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl restart nginx
sudo systemctl restart YourProjectName

Verification

Type YourHostName in your browser and you should see it.

HTTPS conversion

sudo apt install certbot python-certbot-nginx
sudo certbot --nginx
sudo certbot renew --dry-run

All you have to do is follow the instructions. Only here is really easy.

at the end

It's quite difficult for beginners, but even if you're mentally cornered before you can do it, you can definitely do it one by one without throwing it out on the way. I was able to do it too. Please do your best!! As I wrote at the beginning, there may be something missing, so if you have any questions or if you find a mistake, please leave a comment.

Recommended Posts

To you who are cornered by deploying Django. Django 2.2 deployment full version on Ubuntu 18.04 + Nginx
What I found by deploying Django on EC2
Deploy Django apps on Ubuntu + Nginx + MySQL (Build)
Memo of deploying Django × Postgresql on Docker to Heroku
Allows you to select by name from Django User Name