ConoHa VPSにDjangoアプリをデプロイする方法【Nginx,Gunicorn】

ConoHaVPSにDjangoアプリケーションを本格的にデプロイしてみましょう。いったんアプリケーションイメージを構築してから、Djangoでよく使われるNginx、Gunicornといった構成で実装します。

目次

ConoHa VPSでサーバーを構築する

Conoha VPSに登録し、コントロールパネルからDjangoのアプリケーションイメージを選択します。

ConoHa VPSでDjangoのアプリケーションイメージを使ってサーバーを構築

今回はローカルからサーバーにSSH接続するので下にスクロールしてオプションのSSH KEYからキーの新規作成。

「+追加」を押すと画像のようなポップアップがでるので秘密鍵を「ダウンロード」します。

オプションのSSH KEYからキーの新規作成

このキーはVPSへの接続に使用するので大切に保管しましょう。

SSH Key の項目を「キーを選択」、パブリックキーを選択できていることを確認して、VPSサーバーを追加(契約)します。

VPSサーバーを追加(契約)

VPSにSSH接続

ではダウンロードした秘密鍵を使ってVPSにSSH接続してみましょう。

ツールはTeraTermを使います。

これはConohaVPSに公式記事があるのでそちらを参照。

※一般ユーザー用のフォルダの所有者はその一般ユーザーにしておくこと。

公開鍵認証(SSH)での接続

これで記載されているURLにいくとDjangoの初期画面が確認できます。

Djangoの初期画面

Ubuntuのユーザー管理

初期設定

VPSに接続できたらまずはUbuntuのアップデートを実行します。

sudo apt-get update
sudo apt-get upgrade

結構時間がかかります。

一般ユーザーを作成

アップデートが完了したら一般ユーザーを作成しましょう。

sudo adduser 任意のユーザー名

実行するとそのままこのユーザーのパスワードを聞かれるので設定します。

管理者権限付与

作成したユーザーに管理者権限付与を付与します。

gpasswd -a ユーザー名 sudo

これでこのユーザーで sudo コマンドが実行できるようになりました。

一般ユーザー用のSSHキーの生成と設置

これはConohaVPSに公式記事があるのでそちらを参照。

一般ユーザーで公開鍵認証を使用してSSHログインする

ルートユーザーでのログインを禁止

ConohaVPSの公式記事を参照。

rootログインを禁止する

Nginxのインストールと設定

nginxをインストール

sudo apt-get install -y nginx
apache2を停止、自動起動も停止
sudo systemctl stop apache2
sudo systemctl disable apache2
Nginxを起動・自動起動設定
sudo systemctl start nginx
sudo systemctl enable nginx
nginxの設定ファイルを作成して開く
sudo vi /etc/nginx/conf.d/mysite.conf
nginxの設定を編集
server {
    listen  80;
    server_name IPアドレス;

    location /static {
        alias /usr/share/nginx/html/static;
    }

    location /media {
        alias /usr/share/nginx/html/media;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        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;
    }
}

設定ファイルを保存したら、Nginxを再起動します。

sudo systemctl restart nginx

Djangoアプリのデプロイと設定

Djangoアプリの設置

djangoディレクトリに移動

cd /home/django

サンプルプロジェクトの削除

sudo rm -r sample

git clone で GitHub から持ってくるか、SFTPソフトでファイルをアップロードします。

Gitの場合

サーバーにGitをインストールします。

sudo apt install git

GitHubからプロジェクトをcloneします。

git clone リポジトリのURL

これでGitHubにアップしてあったフォルダとファイルをUbuntuサーバーにアップできました。

あとは .gitignore で除外していたファイルをローカルからアップします。

SFTPソフトを使う場合

WinSCPを設定します。

ConohaVPSの公式記事を参照。

SFTPを使ってファイルをアップロードする(WinSCP編)

ライブラリのインストール

ローカル環境と同じ環境になるようライブラリをインストールします。

手動でpipインストールしてもいいですが、requirements.txt を利用してローカルで使っていたライブラリをインストールする方法が楽です。

cd /home/django/プロジェクトフォルダ
sudo pip install -r requirements.txt

※が、問題が起きる場合があり(起きた)結局手動でpipインストールしたら解決したりした。

ALLOWED_HOSTSを編集

settings.pyを開きます。

cd /home/django/プロジェクトフォルダ
vi settings.py

settings.pyの中身を次のように編集します。

ALLOWED_HOSTS = ['IPアドレス']

いったん動作確認

この時点で runserver するとDjangoの動作が確認できます。

Djangoの設定ファイルを編集

問題なさそうならデータベースをとりあえずサンプルデータベースと紐づけたり、静的ファイルのパスも編集して、開発モード(DEBUG)もFalseにしておきましょう。

サンプルデータベースの情報はConohaVPSにログインした時に表示されています。

今回は環境変数の管理はdjango-environを使います。

Djangoアプリで環境変数をdjango-environで管理する

SECRET_KEY=django-insecure-*************************************
DEBUG=False

DATABASE_ENGINE=django.db.backends.mysql
DATABASE_DB=sampleapp_db
DATABASE_USER=sampleapp_user
DATABASE_PASSWORD=********
DATABASE_HOST=localhost
DATABASE_PORT=3306
import os
import environ

env = environ.Env()
env.read_env('.env')

SECRET_KEY = env('SECRET_KEY')
DEBUG = env('DEBUG')

ALLOWED_HOSTS = ['IPアドレス']

DATABASES = {
    'default': {
        'ENGINE': env.get_value('DATABASE_ENGINE'),
        'NAME': env.get_value('DATABASE_DB'),
        'USER': env.get_value('DATABASE_USER'),
        'PASSWORD': env.get_value('DATABASE_PASSWORD'),
        'HOST': env.get_value('DATABASE_HOST'),
        'PORT': env.get_value('DATABASE_PORT'),
    }
}

LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'

STATIC_URL = '/static/'
STATIC_ROOT = '/usr/share/nginx/html/static' # 静的ファイルを集める場所(STATIC_ROOT)を指定
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')] # 追加の静的ファイル探索パス

MEDIA_URL = '/media/'
MEDIA_ROOT = '/usr/share/nginx/html/media'

とりあえずでサンプルデータベースと紐づけていて、マイグレートしていないので、ここから先ブラウザで動作を確認してもProgrammingErrorなどになります。

静的ファイルを収集

静的ファイルを先ほど記載したパスに収集します。

cd /home/django/プロジェクト名
sudo python3 manage.py collectstatic

Gunicornのインストールと起動

開発用の runserver の代わりに アプリケーションサーバーとして Gunicorn を使いましょう。

Gunicorn をインストールします。

sudo pip3 install gunicorn

gunicornを起動してみましょう。

cd /home/django/プロジェクトフォルダ
gunicorn config.wsgi:application --bind 127.0.0.1:8000
[2023-03-09 11:54:04 +0900] [69128] [INFO] Starting gunicorn 20.1.0
[2023-03-09 11:54:04 +0900] [69128] [INFO] Listening at: http://127.0.0.1:8000 (69128)
[2023-03-09 11:54:04 +0900] [69128] [INFO] Using worker: sync
[2023-03-09 11:54:04 +0900] [69130] [INFO] Booting worker with pid: 69130

こんな感じになっていればGunicornは起動できています。

Ctrl+C で一度終了して、今度はdaemonオプションを付けてバックグラウンドで起動しましょう。

cd /home/django/プロジェクトフォルダ
gunicorn config.wsgi:application --bind 127.0.0.1:8000 --daemon

プロセスを確認するには次のコマンド。

sudo ps aux | grep gunicorn

あるいは今回の場合こちらの方がわかりやすいかもしれない。

sudo lsof -i:8000

今後Djangoファイルの編集を反映するには

前述のコマンドで起動中のプロセスのID(PID)を確認します。

次のように表示されます。

gunicorn 69147 root    5u  IPv4 130015      0t0  TCP localhost:8000 (LISTEN)
gunicorn 69149 root    5u  IPv4 130015      0t0  TCP localhost:8000 (LISTEN)

どちらのプロセスを停止しても問題ありませんが、一般的に最も古いプロセス、つまりPIDの小さい方のプロセスを停止します。

sudo kill 69147

片方を止めれば両方とも止まります。

Gunicornを再び起動します。

cd /home/django/プロジェクトフォルダ
gunicorn config.wsgi:application --bind 127.0.0.1:8000 --daemon

MySQL(MariaDB)の設定

MySQLに実際のアプリで使用するデータベースを作成しましょう。

まずはMySQL(MariaDB)にログインします。

mysql -u root -p

MySQLのrootパスワードが求められます。これはConohaVPSのログイン時に表示されています。

Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 35
Server version: 10.7.8-MariaDB-1:10.7.8+maria~ubu2004 mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>

データベースの作成

アプリで使用するデータベースを作成します。

MariaDB [(none)]> create database データベース名;
データベースにユーザーを作成し、パスワードを設定します。
MariaDB [(none)]> create user 'ユーザー名'@'localhost' IDENTIFIED BY 'パスワード';
ユーザーにすべての権限を付与します。
MariaDB [(none)]> grant all privileges on データベース名.* to ユーザー名@localhost IDENTIFIED BY 'パスワード';
MySQLからログアウトします。
MariaDB [(none)]> \q

作成したデータベースをDjangoアプリに紐づけ

.envを編集し、作成したデータベースをDjangoアプリに紐づけます。

DATABASE_ENGINE=django.db.backends.mysql
DATABASE_DB=データベース名
DATABASE_USER=ユーザー名
DATABASE_PASSWORD=パスワード
DATABASE_HOST=localhost
DATABASE_PORT=3306

マイグレート

Djangoのマイグレーションファイルの内容をデータベースに反映しましょう。

sudo python3 manage.py migrate
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying account.0001_initial... OK
  Applying account.0002_email_max_length... OK
.
.
.

こんな感じで出てマイグレートが完了します。

動作確認

ここまでできたらGunicornを起動して確認してみましょう。

cd /home/django/プロジェクトフォルダ
gunicorn config.wsgi:application --bind 127.0.0.1:8000 --daemon

ブラウザでVPSのIPアドレスにアクセスしてみましょう。

データベースが空っぽなのでアレですが、アプリが正常に動作しているはずです。

ドメインを設定

ドメインを取得

実際の運用でIPアドレスを使っているわけにもいかないのでドメインを取得し、レンタルしているVPSに紐づけます。

ドメインの取得方法は下記の記事をご参照ください。

お名前.comで独自ドメインを取得する方法

サービスはどこを使っても良いですが、一応この記事でもお名前.comでドメインを取得したていで進めていきます。

お名前.com側の設定

まずはお名前.com側でネームサーバーを変更します。

ネームサーバーの設定・変更方法については下記の記事のお名前.com側での作業をご参照ください。

ネームサーバーの設定・変更方法

今回は紐づける先がエックスサーバーではなくConohaVPSなので、ネームサーバーは次のようになります。

  • ns-a1.conoha.io
  • ns-a2.conoha.io
  • ns-a3.conoha.io

この変更は反映されるまで1日~3日程度かかりますので気長に待ちましょう。

※たいてい半日もあれば反映されている気がしますが、一応1日~3日程度かかるというていになっています。

ConohaVPS側の設定

ConohaVPS側でDNSの設定をします。

コントロールパネル左側のメニューバーから「DNS」を選択し、「+ドメイン」をクリック。

ドメイン名とIPアドレスを紐づけるためのAレコードを追加します。

ドメイン名とIPアドレスを紐づけるためのAレコードを追加

  • タイプ:A
  • 名称:@
  • TTL:3600
  • 値:IPアドレス

を入力して「保存」。

これでドメインとIPアドレスが紐づきます。

Django側の設定

settings.pyを編集してドメイン名でのアクセスを許可します。

ALLOWED_HOSTS = ['ドメイン']

nginxの設定

nginxの設定ファイルも編集して、ドメインでのアクセスを受け付けるようにします。

sudo vi /etc/nginx/conf.d/mysite.conf
server {
    listen  80;
    server_name ドメイン;

    location /static {
        alias /usr/share/nginx/html/static;
    }

    location /media {
        alias /usr/share/nginx/html/media;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        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;
    }
}

編集が完了したらnginxをリロードして変更を反映します。

sudo systemctl reload nginx

これでドメインでアクセスできるようになりました。

実際にブラウザから取得したドメインにアクセスしてみましょう。

HTTPS化

さて、これでデプロイ自体は完了したわけですが、これだと暗号化されていないHTTP通信で接続しているのでサイトのセキュリティ的に不安が残ります。

決済やユーザー登録をしないサイトであれば暗号化(HTTPS化)する必要はないのですが

  • Djangoで作るアプリはユーザー管理機能を使うケースが多い(というかDjangoはそれが便利なフレームワーク)
  • 今どきHTTPS化していないサイトはブラウザから警告が発される
  • Googleの検索アルゴリズムからも冷遇される

HTTPS化していないサイトはブラウザから警告が発される

よって実際問題として、実用サイトでHTTPS化しないという選択肢はありません。

ということでHTTPS化していきます。

Cerbotのインストールと実行

Cerbotというツールを使い、Let’s Encryptと呼ばれる認証局から無料でSSL認証書を発行し、Webサーバー側の設定まで自動やってもらいます。

まずはCerbotをインストールします。

sudo apt-get install certbot python3-certbot-nginx

いったんnginxを停止

sudo systemctl stop nginx

Certbot を実行

sudo certbot certonly --standalone -d ドメイン

いくつか質問されます。

Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel):

メールアドレス

You must agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(A)gree/(C)ancel:

規約に同意するかどうか

Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot?

メールアドレスを電子フロンティアと共有してもいいか(メールを受信したいかどうか)

ひととおり質問に答え終わると Congratulations! うんたらかんたら、と出て証明書とキーの保存場所が表示されます。

では改めて nginx を起動しましょう。

sudo systemctl start nginx

Nginxの設定変更

Nginxの設定ファイルを変更し、HTTPS通信ができるようにします。

sudo vi /etc/nginx/conf.d/mysite.conf
server {
    listen 80;
    listen [::]:80;
    server_name ドメイン;
    return 301 https://$host$request_uri;
}

server {
    listen  443 ssl;
    server_name ドメイン;

    ssl on;
    ssl_certificate         /etc/letsencrypt/live/ドメイン/fullchain.pem;
    ssl_certificate_key     /etc/letsencrypt/live/ドメイン/privkey.pem;

    location /static {
        alias /usr/share/nginx/html/static;
    }

    location /media {
        alias /usr/share/nginx/html/media;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        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;
    }
}

ファイアウォールのhttps用ポートを開放

Ubuntuで使われているファイアウォール、ufw (Uncomplicated Firewall)でhttps用ポートを開放します。

sudo ufw allow https

ちなみにufwのステータスは次のコマンドで確認できます。

ufw status

現在は

  • SSH接続用の22番ポート
  • HTTP接続用の80番ポート
  • HTTPS接続用の443番ポート

が空いているはずです。

確認できたらnginxをリロードして先ほどの設定変更を反映しましょう。

sudo systemctl reload nginx

ssl証明書の自動更新

Let’s Encrypt の SSL 証明書は期限が3ヶ月と短めです。

以前は cron を使って自動更新していたようですが、最新の certbot はなんと自動更新機能がついているので何もする必要はありません。

一応動作を確認しておきましょう。

sudo systemctl status certbot.timer
● certbot.timer - Run certbot twice daily
     Loaded: loaded (/lib/systemd/system/certbot.timer; enabled; vendor preset:>
     Active: active (waiting) since Fri 2023-03-10 14:24:13 JST; 39min ago
    Trigger: Sat 2023-03-11 00:44:22 JST; 9h left
   Triggers: ● certbot.service

このように active になっていればOKです。

この画面からはqキーで抜けることができます。

これですべての作業は完了です!お疲れさまでした!

あとは改めて Gunicorn を起動して、Djangoアプリの動作を確認してみましょう。

gunicorn config.wsgi:application --bind 127.0.0.1:8000 --daemon

無事、HTTPSでサイトに接続することができています!

無事、HTTPSでサイトに接続することができています!

万一動かない時は次の項目を確認してみましょう。

  • nginxは正常に動作しているか
  • Nginxの設定ファイルは間違っていないか(サイトのドメインや証明書のパスは間違っていないか)
  • Nginxをリロードしてみる
  • Gunicornは正常に動作しているか
  • 必要なポートは開放されているか

あと、SSH用のポートが22番のままなのはセキュリティ的によろしくないです。

一般的でないポートに変更しておきましょう。

このエントリーをはてなブックマークに追加

コメントを残す

頂いたコメントは一読した後表示させて頂いております。
反映まで数日かかる場合もございますがご了承下さい。