ConoHaVPSにDjangoアプリケーションを本格的にデプロイしてみましょう。いったんアプリケーションイメージを構築してから、Djangoでよく使われるNginx、Gunicornといった構成で実装します。
目次
- ConoHa VPSでサーバーを構築する
- VPSにSSH接続
- Ubuntuのユーザー管理
- Nginxのインストールと設定
- Djangoアプリのデプロイと設定
- Gunicornのインストールと起動
- MySQL(MariaDB)の設定
- ドメインを設定
- HTTPS化
ConoHa VPSでサーバーを構築する
Conoha VPSに登録し、コントロールパネルからDjangoのアプリケーションイメージを選択します。
今回はローカルからサーバーにSSH接続するので下にスクロールしてオプションのSSH KEYからキーの新規作成。
「+追加」を押すと画像のようなポップアップがでるので秘密鍵を「ダウンロード」します。
このキーはVPSへの接続に使用するので大切に保管しましょう。
SSH Key の項目を「キーを選択」、パブリックキーを選択できていることを確認して、VPSサーバーを追加(契約)します。
VPSにSSH接続
ではダウンロードした秘密鍵を使ってVPSにSSH接続してみましょう。
ツールはTeraTermを使います。
これはConohaVPSに公式記事があるのでそちらを参照。
※一般ユーザー用のフォルダの所有者はその一般ユーザーにしておくこと。
これで記載されているURLにいくとDjangoの初期画面が確認できます。
Ubuntuのユーザー管理
初期設定
VPSに接続できたらまずはUbuntuのアップデートを実行します。
sudo apt-get update sudo apt-get upgrade
結構時間がかかります。
一般ユーザーを作成
アップデートが完了したら一般ユーザーを作成しましょう。
sudo adduser 任意のユーザー名
実行するとそのままこのユーザーのパスワードを聞かれるので設定します。
管理者権限付与
作成したユーザーに管理者権限付与を付与します。
gpasswd -a ユーザー名 sudo
これでこのユーザーで sudo コマンドが実行できるようになりました。
一般ユーザー用のSSHキーの生成と設置
これはConohaVPSに公式記事があるのでそちらを参照。
ルートユーザーでのログインを禁止
ConohaVPSの公式記事を参照。
Nginxのインストールと設定
nginxをインストール
sudo apt-get install -y nginx
sudo systemctl stop apache2 sudo systemctl disable apache2
sudo systemctl start nginx sudo systemctl enable nginx
sudo vi /etc/nginx/conf.d/mysite.conf
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 'パスワード';
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側での作業をご参照ください。
今回は紐づける先がエックスサーバーではなくConohaVPSなので、ネームサーバーは次のようになります。
- ns-a1.conoha.io
- ns-a2.conoha.io
- ns-a3.conoha.io
この変更は反映されるまで1日~3日程度かかりますので気長に待ちましょう。
※たいてい半日もあれば反映されている気がしますが、一応1日~3日程度かかるというていになっています。
ConohaVPS側の設定
ConohaVPS側でDNSの設定をします。
コントロールパネル左側のメニューバーから「DNS」を選択し、「+ドメイン」をクリック。
ドメイン名と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化していきます。
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でサイトに接続することができています!
万一動かない時は次の項目を確認してみましょう。
- nginxは正常に動作しているか
- Nginxの設定ファイルは間違っていないか(サイトのドメインや証明書のパスは間違っていないか)
- Nginxをリロードしてみる
- Gunicornは正常に動作しているか
- 必要なポートは開放されているか
あと、SSH用のポートが22番のままなのはセキュリティ的によろしくないです。
一般的でないポートに変更しておきましょう。