JavaScript is not available.
New Article

Ubuntu18.04 + Nginx + Gunicorn + Python3 でDjangoデプロイ完全版

この記事は、Qiitaにて投稿したものを一部変更したものです。

環境

  • Ubuntu18.04 LTS(16.04~はOK)
  • Nginx1.14.0(最新版ならOK)
  • Python3.8.0(3.x.xならOK)
  • Django2.2.8(2.2.xならOK、おそらく3.0でもいける)

前提

  • プロジェクトの名前は “YourProjectName”
  • アプリの名前は “YourAppName”
  • 好ましくはないが、SECRET_KEYは、開発環境・本番環境ともに、もとのsettings.pyファイルに記載されていたものを使用します。
  • 好ましくはないが、データベースは、開発環境・本番環境ともに、sqlite3を使用します。
  • static、media、templatesフォルダは、トップディレクトリにて一括管理されているものとします。
  • ホスト名(ドメインの名前)はYourHostNameとします。グローバルIPアドレスでも構いません。

ローカルでの準備

準備完了段階でのディレクトリ構造

YourProjectName
        ├ 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

YourProjectName/settings.pyを書き変える

書き換えるというよりも作り変えるといったほうが的確かもしれません。

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'),
    }
}

詳しくは後日追記。

トップディレクトリにcollected_staticフォルダを作成

理由は後にわかります。

準備完了段階でのディレクトリ構造

YourProjectName
        ├ 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

GitHubにPush

開発環境から本番環境にデータを移すときに今後の開発の事も考えGitHubを使用します。

.gitignoreで__pychache__、db.sqlite3、collected_static/*を指定して、gitの対象から除外しておくことをおすすめします。

サーバーでの操作

準備も大変だったかと思いますが、これからが本番です。

一応書いておきますが、これからはサーバー上での操作です。

ファイアーウォールの設定

80番ポートを開けてください。

sudo systemctl restart で必ずファイアーウォールのサービスを再起動してください。

Nginxのインストール

sudo apt install nginx

Nginxの設定

この段階で、ブラウザにドメインを打ち込むとWelcome to nginx!と出てくるはずです。

出てこなかった場合、インストールに失敗したか、ファイアーウォールの設定がうまく行っていないか、ドメインやネームサーバー周りの設定がうまく行っていない可能性があります。

まず、次の部分を編集してください。

/etc/nginx/sites-available/YourProjectName

server {
    server_name YourHostName;

    location /static {
        alias /var/www/YourProjectName/collected_static;
    }

    location /media {
        alias /var/www/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;
    }
}

シンボリックリンク

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

プロジェクトをクローン

先程ローカルでGitHubにPushしたプロジェクトを”/var/www”にクローンします。

Pythonの環境構築

よく、仮想環境を構築する記事がよくあり、その方が好ましいのですが、面倒くさい上、なぜかうまくいかなかったので、普通にやります。

Python3.8をインストール

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

pipでパッケージをインストール

ここで必要となるのが、Djangoはもちろん、Gunicornというパッケージです。

sudo python3.8 -m pip install django gunicorn

他にも作成したプロジェクトに必要なパッケージがあれば必ずインストールしてください。

今回、Gunicornの動作確認は省略します。

migrateとcollectstatic

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

サービスを追加

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

以下のファイルを新規作成してください。

/etc/systemd/system/YourProjectName.service

[Unit]
Description=gunicorn
After=network.target

[Service]
WorkingDirectory=/var/www/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

確認

ブラウザにYourHostNameを打ち込むと、見れるはずです。

HTTPS化

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

あとは、案内に従うのみです。ここだけすごい簡単。

さいごに

初心者的には結構大変ですが、できないうちに精神的に追い詰められても、途中で投げ出さず、一つ一つ確実にやっていけば必ずできます。

ご不明な点がある方や、ミスを発見した方、どうしてもできなくて頭痛い…なんていう方はコメントお願いします!!

Leave a Reply

Your email address will not be published. Required fields are marked *