Help us understand the problem. What is going on with this article?

Djangoのデプロイで追い詰められているあなたへ。Ubuntu18.04+NginxでDjango2.2デプロイ完全版

はじめに

自分が初心者だったこともあって、かなり初心者向けに書いたつもりです。
もしご不明な点やミスなどがあればコメントよろしくおねがいします。

完全版とは言いましたが、よくある記事とは違い、プロジェクトの作成からの説明は行いません。

Django3.0がリリースされた今かよって感じですが、おそらくDjango3.0でもそんなに変わらないと思います。
僕がやった範囲内では問題なく動作しました。

環境

  • Ubuntu18.04 LTS
  • 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アドレスでも構いません。

ローカルでの準備

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

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

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フォルダを作成

理由は後にわかります。

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

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

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/nginx.conf
# user www-data;
user webmaster;

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

/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;
    }
}

シンボリックリンク

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

ユーザー: webmasterを作成

sudo adduser webmaster

プロジェクトをクローン

先程ローカルでGitHubにPushしたプロジェクトをクローンします。
ここで、注意しなければならないのは、今作ったユーザー(webmaster)のユーザーディレクトリ(/home/webmaster/)上にクローンを作ることです。

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

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

GunicornでDaemon化

デーモン化

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=/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

確認

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

HTTPS化

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

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

さいごに

初心者的には結構大変ですが、できないうちに精神的に追い詰められても、途中で投げ出さず、一つ一つ確実にやっていけば必ずできます。
僕もできました。頑張ってください!!
はじめにも書きましたが、なにか抜けているかもしれませんので、ご不明な点がある方や、ミスを発見した方はコメントにお願いします。

kantacky
Reactにハマってます。 わからないことがいっぱいあるのでQiitaで調べまくります。
https://www.kantacky.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした