この記事は、Ubuntu22.04,Python3.10,Nginx,Gunicorn,PostgreSQL14.7を利用して、Django4.2.1プロジェクトの本番環境構築の方法を紹介します。
◆動作検証環境
・さくらVPSサーバー:メモリ 512M, ストレージ:SSD 25GB, CPU:1コア
・OS:Ubuntu 22.04 LTS amd64
・Python:3.10.6
・Django:4.2.1
・Nginx:1.18.0
・Gunicorn:20.1.0
・PostgrSQL:14.7
・psycopg3:3.1.9
Ubuntuの環境初期設定
Ubuntuの初期設定
まずはリモートサーバーにログインします。
1 2 3 | $ ssh -i ~/.ssh/id_rsa username@xxx.xxx.xxx.xxx |
日本語環境の設定
1 2 3 | $ sudo apt -y install language-pack-ja-base language-pack-ja ibus-mozc |
日本語への設定
1 2 3 | $ sudo localectl set-locale LANG=ja_JP.UTF-8 LANGUAGE="ja_JP:ja" |
変更後の確認
1 2 3 | $ sudo localectl |
↓のように表示されればOK
1 2 3 4 5 6 7 | System Locale: LANG=ja_JP.UTF-8 LANGUAGE=ja_JP:ja VC Keymap: n/a X11 Layout: jp,jp X11 Model: pc105 |
時刻設定の確認
1 2 3 | $ date |
以下のように表示される
1 2 3 | Sat Jun 19 21:18:14 JST 2021 |
タイムゾーンの変更
1 2 3 | $ sudo timedatectl set-timezone Asia/Tokyo |
1 2 3 | $ date |
Ubuntuのソフトウェアの更新
1 2 3 | $ sudo apt update |
Python3,pip,postgesql,nginx(周辺モジュール)のインストール
1 2 3 | $ sudo apt install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx |
libpq5のインストール
今回はPsycopg3系を利用するので、以下のモジュールもインストールします。
1 2 3 4 | <del><span class="n">sudo</span> <span class="n">apt</span> <span class="n">install</span> <span class="n">libpq5</span> </del> |
1 2 3 | $ sudo apt install python3-pip python3-dev default-libmysqlclient-dev build-essential nginx |
1 2 3 | $ sudo apt install mysql-server |
PostgreSQLの設定
postgresqlデータベースの作成
postgresqlのバージョン確認
1 2 3 | $ psql --version |
今回は→ psql (PostgreSQL) 14.7 (Ubuntu 14.7-0ubuntu0.22.04.1)
1 2 3 4 5 | PG::ConnectionBad (could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"? |
1 2 3 | pg_lsclusters |
1 2 3 | pg_ctlcluster 14 main start |
1 2 3 | sudo /etc/init.d/postgresql start |
postgresqlの初期化
1 2 3 | $ sudo -u postgres psql |
データベースの作成
1 2 3 | # CREATE DATABASE your_database; |
djangoから接続するユーザー、パスワードの設定
1 2 3 | # CREATE USER your_user_name WITH PASSWORD 'yourpassword'; |
1 2 3 | # ALTER ROLE your_user_name SET client_encoding TO 'utf8'; |
タイムゾーン設定
1 2 3 | # ALTER ROLE your_user_name SET timezone TO 'Asia/Tokyo'; |
ユーザーに権限つける
1 2 3 | # GRANT ALL PRIVILEGES ON DATABASE your_database TO your_user_name; |
1 2 3 | # \q |
postgresql起動確認
1 2 3 | $ ps aux |
下記のような表示を確認できればOK
1 2 3 4 5 6 7 8 9 | USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 1.2 168408 5960 ? Ss 10月21 0:32 /sbin/init root 2 0.0 0.0 0 0 ? S 10月21 0:00 [kthreadd] root 3 0.0 0.0 0 0 ? I< 10月21 0:00 [rcu_gp] ... ... ... |
postgresqlコンフィグファイルの設定
PostgreSQLのリモート接続設定
pg_hba.conf ファイルのディレクトリに移動1 2 3 | $ cd /etc/postgresql/14/main |
1 2 3 | $ sudo vim pg_hba.conf |
デフォルト
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # Database administrative login by Unix domain socket local all postgres peer # TYPE DATABASE USER ADDRESS METHOD # "local" is for Unix domain socket connections only local all all peer # IPv4 local connections: host all all 127.0.0.1/32 scram-sha-256 # IPv6 local connections: host all all ::1/128 scram-sha-256 # Allow replication connections from localhost, by a user with the # replication privilege. local replication all peer host replication all 127.0.0.1/32 scram-sha-256 host replication all ::1/128 scram-sha-256 |
下記にように編集します(97行目あたりに追加)。
*host all all 0.0.0.0/0 scram-sha-256 を追加
1 2 3 4 5 | local all all peer ↓変更 local all all trust |
編集後
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # Database administrative login by Unix domain socket local all postgres peer # TYPE DATABASE USER ADDRESS METHOD # "local" is for Unix domain socket connections only local all all trust # IPv4 local connections: host all all 127.0.0.1/32 scram-sha-256 host all all 0.0.0.0/0 scram-sha-256 # IPv6 local connections: host all all ::1/128 scram-sha-256 # Allow replication connections from localhost, by a user with the # replication privilege. local replication all peer host replication all 127.0.0.1/32 scram-sha-256 host replication all ::1/128 scram-sha-256 |
postgresql.conf の編集
1 2 3 | $ sudo vim postgresql.conf |
1 2 3 | # listen_addresses = ‘localhost’ => listen_addresses = ‘*’ |
PostgreSQL再起動
1 2 3 | $ sudo /etc/init.d/postgresql restart |
*参考)よく使うPostgreSQLのコマンド
1 2 3 4 5 6 7 8 9 10 | PostgreSQL起動 $ sudo /etc/init.d/postgresql start PostgreSQL停止 $ sudo /etc/init.d/postgresql stop PostgreSQL確認 $ sudo /etc/init.d/postgresql status |
1 2 3 | UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-4: ordinal not in range(256) |
1 2 3 | “UTF8” has no equivalent in encoding “LATIN1” |
まずは、作成したデータベースのEncodingを調べます
1 2 3 | $ sudo -u postgres psql |
1 2 3 | postgres=# \q |
以下のように表示されていると思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges ---------------+----------+----------+---------+-------+----------------------- your_database | postgres | LATIN1 | en_US | en_US | =Tc/postgres + | | | | | postgres=CTc/postgres+ | | | | | nakajima=CTc/postgres postgres | postgres | LATIN1 | en_US | en_US | template0 | postgres | LATIN1 | en_US | en_US | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | LATIN1 | en_US | en_US | =c/postgres + | | | | | postgres=CTc/postgres (4 rows) |
UTF-8ではなくLATIN1となるのは、UBUNTUのロケール設定をデフォルトのまま設定するとこのようになる場合があります。
UTF-8の設定にするために以下の対策を行います。
1 2 3 | $ sudo systemctl stop postgresql |
1 2 3 | $ sudo pg_dropcluster --stop 14 main |
1 2 3 4 5 | $ export LANGUAGE="en_US.UTF-8" $ export LANG="en_US.UTF-8" $ export LC_ALL="en_US.UTF-8" |
1 2 3 | sudo systemctl start postgresql |
1 2 3 | sudo pg_createcluster -e UTF8 --start 14 main |
以下のように表示されると設定完了です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | Creating new PostgreSQL cluster 14/main ... /usr/lib/postgresql/14/bin/initdb -D /var/lib/postgresql/14/main --auth-local peer --auth-host md5 --encoding UTF8 The files belonging to this database system will be owned by user "postgres". This user must also own the server process. The database cluster will be initialized with locale "en_US.UTF-8". The default text search configuration will be set to "english". Data page checksums are disabled. fixing permissions on existing directory /var/lib/postgresql/14/main ... ok creating subdirectories ... ok selecting dynamic shared memory implementation ... posix selecting default max_connections ... 100 selecting default shared_buffers ... 128MB selecting default time zone ... Asia/Tokyo creating configuration files ... ok running bootstrap script ... ok performing post-bootstrap initialization ... ok syncing data to disk ... ok Success. You can now start the database server using: pg_ctlcluster 14 main start Ver Cluster Port Status Owner Data directory Log file 12 main 5432 online postgres /var/lib/postgresql/12/main /var/log/postgresql/postgresql-12-main.log |
もう一度データベースの情報を確認します。
1 2 3 4 5 6 7 8 9 10 11 | List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -----------+----------+----------+-------------+-------------+----------------------- postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres + | | | | | postgres=CTc/postgres (3 rows) |
UTF-8に設定されていることが、確認できます。
既に作成したデータベースや、コンフィグファイルの設定はリセットされているので、もう一度作成します。
参考)Mysqlで設定する場合
バージョンの確認
1 2 3 | $ mysql --version |
mysql Ver 8.0.33-0ubuntu0.22.04.1 for Linux on x86_64 ((Ubuntu))
文字化け対策で/etc/mysql/my.cnf ファイルの編集
まず、time-zoneの設定に対応するため以下のコマンドを実行します。
1 2 3 | <del>$ sudo mysql -u root -Dmysql < ~/timezone.sql</del> |
以下のコードを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 | [mysqld] character-set-server=utf8 skip-character-set-client-handshake default-storage-engine=INNODB default-time-zone = 'Asia/Tokyo' [mysqldump] default-character-set=utf8 [mysql] default-character-set=utf8 |
編集後再起動
1 2 3 | $ sudo /etc/init.d/mysql restart |
Mysqlサーバーへログイン
1 2 3 | $ sudo mysql -u root -p |
データベース作成
1 2 3 | mysql > CREATE DATABASE your_database; |
ユーザー追加
1 2 3 | mysql > CREATE USER 'your_user_name'@'localhost' IDENTIFIED BY 'yourpassword'; |
追加したユーザーへの権限付与
1 2 3 | mysql > GRANT ALL on your_database.* to 'your_user_name'@'localhost'; |
設定の反映
1 2 3 | mysql > FLUSH PRIVILEGES; |
ログアウト
1 2 3 | mysql > \q |
再起動
1 2 3 | $ sudo /etc/init.d/mysql restart |
Virtualenvの仮想環境の構築
今回使用するOSのUbuntu0.20.04は、デフォルトでPython3.8.5がインストールされているため、自分でインストールする必要はありません。
仮想環境ファイルの作成
Pip3 のインストールとアップグレード
1 2 3 | $ sudo -H pip3 install --upgrade pip |
virtualenvのインストール
1 2 3 | $ sudo -H pip3 install virtualenv |
ホームディレクトリへ移動
1 2 3 | $ cd |
virtualenvのファイル作成(仮想環境ファイル名はvenvとしています)
1 2 3 | $ virtualenv venv |
仮想環境の有効化
1 2 3 | $ source venv/bin/activate |
仮想環境の有効時はターミナルなる表示が下記のようになります。
1 2 3 | (venv) username@xxx-xxx-xxxxx:~$ |
仮想環境の中にdjangoをインストール
今回はDjangoバージョン4.2.1を指定しております。
こちらは3.6の次のLTSのバージョンとなっています。
1 2 3 | (venv)$ pip install Django==4.2.1 |
仮想環境の中にpsycopg(pythonとpostgresqlのドライバとなるライブラリー)をインストール
1 2 3 | (venv)$ pip install psycopg==3.1.9 |
仮想環境の中にgunicornをインストール
1 2 3 | (venv) $ pip3 install gunicorn |
1 2 3 | (venv) $ pip3 install django gunicorn mysqlclient |
Djangoプロジェクトのデプロイ
本番環境の最低限の環境構築の準備ができましたので、ローカルで開発したDjangoプロジェクトをデプロイします。
この記事では、①GitHubを利用する方法、②PyCharm Professional、③VScodeを利用する方法を紹介します。
①GitHubを利用するデプロイ
gitをインストールします。
1 2 3 | sudo apt install git |
プロジェクトを設置したディレクトリへ移動してクローンします。
1 2 3 | $ git clone <https:xxxx@xxxxxx.xxxx.xxxx.xxxxxxx.> |
②PyCharm Professionalを利用するデプロイ
PyCharm Professionalを利用する方法は下記の方法を参考にしてください。
PyCharmでローカルで開発したDjangoプロジェクトを本番環境へデプロイする
③VScodeを利用するデプロイ
VScodeを利用する方法は下記の方法を参考にしてください。
VSCodeでDjangoプロジェクトをデプロイ【SFTP利用編】
動作確認用Djangoプロジェクトの設置
試験的にDjangoの動作の確認だけできれば良い場合は、ここで新規のプロジェクトを作成します。
1 2 3 | $ source venv/bin/activate |
1 2 3 | (Venv)$ django-admin startproject project_name . |
settings.pyの編集
settings.pyを編集します。
自分のリモートサーバーのホストを入力します。
1 2 3 | ALLOWED_HOSTS = ['xxx.xxx.xxx.xxx'] |
新規でプロジェクトを作成した場合は、さきほど行ったpostgresqlの設定に合わせて、データベースの設定も変更します。
1 2 3 4 5 6 7 8 | DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } |
上記の設定を下記の内容に変更します。
1 2 3 4 5 6 7 8 9 10 11 12 | DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'your_database', 'USER': 'your_user_name', 'PASSWORD': 'yourpassword', 'HOST': '', 'PORT': '', } } |
1 2 3 4 5 6 7 8 9 10 11 12 | DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'test_db', 'USER': 'user', 'PASSWORD': 'password', 'HOST': 'localhost', 'PORT': '', } } |
デプロイ後は、まずローカルからTextの形でエクスポートされたモジュールをインストールします。
1 2 3 | (venv) $ pip3 install -r module.txt |
ローカルからプロジェクトファイルをデプロイする際、migration関係のファイルを含めない設定にしているので、makemigrations , migtate を行います。
この段階でサーバーが立ち上がるか確認します。
まず、8000番のポートへのアクセスを許可します。
1 2 3 | sudo ufw allow 8000 |
次に以下のように0.0.0.0:8000 と指定して起動します。
1 2 3 | $ python3 manage.py runserver 0.0.0.0:8000 |
それぞれのリモートサーバーのIPアドレスの8000番ポートを指定してブラウザで確認します。
1 2 3 | xxx.xxx.xxx.xxx:8000/ |
サイトが確認できればOKです。
データベース内データのdump(エクスポート)とインポート
Postgresql
dump
1 2 3 | pg_dump -d your_db_name > sample.sql |
dump(テーブル単位)
1 2 3 | pg_dump -t your_table_name your_db_name > sample.sql |
インポート
1 2 3 | psql -d your_db_name < sample.sql |
mysql
dump
1 2 3 | mysqldump -u root -p your_db_name > sample.sql |
インポート
1 2 3 | sudo mysql -u root -p your_db-name < sample.sql |
Djangoコマンドを使用
以下のDjangoのコマンドを利用する事で、jsonファイルを介してデータの移動ができます。
dump
1 2 3 | python manage.py dumpdata > sample.json |
インポート
1 2 3 | python manage.py loaddata sample.json |
settings.py内のセキュリティーに関係する情報が、環境変数で管理していない場合は、対応させます。
今回は、django-environ を利用する方法を紹介します。
まずは、ライブラリのインストールです。
1 2 3 | (venv) $ pip3 install django-environ |
ベースディレクトリ(manage.pyがあるディレクトリ)に.env ファイルを作成し以下のように環境変数で管理したい情報を記入します。
1 2 3 4 5 6 7 | SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx DB_USER=your_user_name ... ... |
settings.pyを編集して、反映させます
1 2 3 4 5 6 7 8 9 10 11 | import environ env = environ.Env() env.read_env('.env') SECRET_KEY = env('SECRET_KEY') ... ... |
Gunicornの設定
Gunicornの起動と動作の確認
内蔵サーバーでのサイトの表示が確認できましたので、次にgnicornのアプリケーションサーバーを起動してサイトの表示を確認します。
gunicorn単体での起動確認
仮想環境を有効にして下記のコマンドを実行します。project.wsgi とする事で、projectアプリケーション内のwsgi.pyを参照させています。
それぞれのprojectアプリケーションの名前に変更してください。
projectアプリケーションを含むディレクトリ(manage.pyコマンドを実行する時のディレクトリ)に移動して下記のコマンドを実行します。
1 2 3 | (venv) $ gunicorn --bind 0.0.0.0:8000 project.wsgi |
このように表示されればOKです。
1 2 3 4 5 6 | [2020-10-25 17:03:08 +0900] [18716] [INFO] Starting gunicorn 20.0.4 [2020-10-25 17:03:08 +0900] [18716] [INFO] Listening at: http://0.0.0.0:8000 (18716) [2020-10-25 17:03:08 +0900] [18716] [INFO] Using worker: sync [2020-10-25 17:03:08 +0900] [18719] [INFO] Booting worker with pid: 18719 |
既に[control + c]で停止済みの場合は、一度サーバーを再起動します。
1 2 3 4 | [2021-06-10 22:27:01 +0900] [25754] [ERROR] Connection in use: ('0.0.0.0', 8000) [2021-06-10 22:27:01 +0900] [25754] [ERROR] Retrying in 1 second. |
内蔵サーバーの時のように以下の方法で、ブラウザにアクセスし表示を確かめます。
それぞれのリモートサーバーのIPアドレスの8000番ポートを指定してブラウザで確認します。
1 2 3 | xxx.xxx.xxx.xxx:8000/ |
確認できたら、control + c でgnicornを停止します。
仮想環境から抜けます。
1 2 3 | (venv)$ deactivate |
GunicornをOSの起動時に動作するように設定する
gunicorn単体の動作が確認できましたので、OSの起動時に自動的にgunicornが起動するように設定します。
gunicornのシステムファイルが含まれるディレクトリに移動します。
1 2 3 | $ cd /etc/systemd/system |
gunicornのサービスファイル作成
*ここではgunicorn.service というファイル名で作成します。
1 2 3 | $ sudo vim /etc/systemd/system/gunicorn.service |
作成したファイルを下記のように編集します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | [Unit] Description=gunicorn daemon After=network.target [Service] User=yourname Group=www-data WorkingDirectory=/home/yourname/project ExecStart=/home/yourname/venv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/yourname/project/project.sock project.wsgi:application [Install] WantedBy=multi-user.target |
編集後にファイルの動作を確認します。
1 2 3 | $ sudo systemctl start gunicorn |
ファイルが正常に動作するば、何も表示されずコマンドプロンプトが返ってきます。
エラーがある場合は表示されるので対応します。
1 2 3 | $ sudo systemctl enable gunicorn |
1 2 3 | Created symlink /etc/systemd/system/multi-user.target.wants/gunicorn.service → /etc/systemd/system/gunicorn.service. |
シンボリックリンクと、ソケットが表示されている場所、指定した場所に作成されているか確認します。
1 2 3 | $ sudo journalctl -u gunicorn |
一度シンボリックリンクを削除して、gunicorn.serviceを編集します。
1 2 3 | sudo rm -f /etc/systemd/system/multi-user.target.wants/gunicorn.service |
1 2 3 | sudo vim /etc/systemd/system/gunicorn.service |
次にソケットがあるディレクトリに移動してソケットも削除します。
1 2 3 | $ sudo rm -f project.sock |
ファイルを変更した後は再読み込みを行います。
1 2 3 | sudo systemctl daemon-reload |
gunicornをリスタートします
1 2 3 | sudo systemctl restart gunicorn |
その後再度、シンボリックリンクを貼り、指定のディレクトリにソケットができている事を確認し再度試します。
これでOSの起動時にgunicornが起動する設定ができました。
Nginxの設定
これからは、WEBサーバーNginxの設定を行います。
静的なファイルに関係する動作はNginxに担当させ、負荷のかかる動的な動作はNginxからgunicornを呼び出し対応させるます。
この設定によって、ユーザーのリクエストの種類によって無駄の内サーバー動作を行えるようになります。
Nginxのコンフィグファイルの編集
まず、Webサーバーのエントリーファイルがあるディレクトリへ移動します。
1 2 3 | $ cd /etc/nginx/sites-available |
次に今回のDjangoプロジェクトで使用するオリジナルのエントリーファイルを作成します。
1 2 3 | $ sudo vim project |
下記のように編集します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | server{ listen 80; server_name xxx.xxx.xxx.xxx; location =/fabicon.ico {access_log off; log_not_found off;} location /static/{ root /home/yourname/project; } location /{ include proxy_params; proxy_pass http://unix:/home/yourname/project/project.sock; } } |
1 2 3 | sudo ln -s /etc/nginx/sites-available/project /etc/nginx/sites-enabled/ |
1 2 3 | $ sudo nginx -t |
下記のように表示されればOKです。
*エラーの表示がある場合は対応します。
1 2 3 4 | nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful |
Nginxの起動とサイト表示確認
8000番ポートの無効化
1 2 3 | $ sudo ufw delete allow 8000 |
nginxへのアクセス許可
1 2 3 | $ sudo ufw allow 'Nginx Full' |
Nginxのリスタート
1 2 3 | $ sudo systemctl restart nginx |
gunicornの再起動
1 2 3 | $ sudo systemctl restart gunicorn |
ブラウザにアクセス(ポート番号の指定は無し)してプロジェクトの表示を確認します。
もう一度configファイルを中心に見直し内容を編集します。
1 2 3 | sudo vim /etc/nginx/sites-available/project |
編集後は、既に作成済みのシンボリックリンクを削除し、編集し直したもので再度作成します。
1 2 3 | sudo rm -f /etc/nginx/sites-enabled/project |
1 2 3 | sudo ln -s /etc/nginx/sites-available/project /etc/nginx/sites-enabled/ |
リスタートして表示を確認します。
1 2 3 | $ sudo systemctl restart nginx |
独自ドメイン・SSL化とリダイレクト設定
独自ドメインの設定
今までの設定で、IPアドレスの指定でサイトへアクセスできるようになりました。
ここからは独自ドメインの設定と、SSLとリダイレクトの設定を行います。
1 2 3 | ALLOWED_HOSTS = ['yoursite.com’] # 編集 |
Webサーバーのエントリーファイルがあるディレクトリへ移動し、編集します。
1 2 3 | $ cd /etc/nginx/sites-available |
1 2 3 | $ sudo vim project |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | server{ listen 80; server_name yoursite.com; location =/fabicon.ico {access_log off; log_not_found off;} location /static/{ root /home/yourname/project; } location /{ include proxy_params; proxy_pass http://unix:/home/yourname/project/project.sock; } } |
すでに設定しているsites-enabledのエントリーファイルを一旦削除します。
1 2 3 | sudo rm /etc/nginx/sites-enabled/project |
1 2 3 | sudo ln -s /etc/nginx/sites-available/project /etc/nginx/sites-enabled/ |
1 2 3 | $ sudo systemctl restart nginx |
gunicornの再起動
1 2 3 | $ sudo systemctl restart gunicorn |
SSL化とリダイレクト設定
今回はLet’s Encryptを利用してSSL化を行います。
letsencryptをインストール
1 2 3 | $ sudo apt-get install letsencrypt |
1 2 3 | $ sudo systemctl stop nginx |
1 2 3 | $ sudo letsencrypt certonly --standalone -d yoursite.com |
詳しい方法は下記の記事にて確認してください。
独自ドメインサイトのSSL化(HTTPS化)【Letsencrypt,Ubuntu,Nginx】
参考)レート制限がかかると、以下のエラーメッセージが出るので1週間待ってから行う。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Obtaining a new certificate An unexpected error occurred: There were too many requests of a given type :: Error creating new order :: too many certificates already issued for exact set of domains: yoursite.com: see https://letsencrypt.org/docs/rate-limits/ Please see the logfiles in /var/log/letsencrypt for more details. IMPORTANT NOTES: - Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal. |
Webサーバーのエントリーファイルがあるディレクトリへ移動し、編集します。
1 2 3 | $ cd /etc/nginx/sites-available |
1 2 3 | $ sudo vim project |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | # http wwwなしからのリダイレクト server { listen 80; listen [::]:80; server_name yoursite.com; return 301 https://$host$request_uri; } # http https wwwありからのリダイレクト server { listen 80; listen 443 ssl; server_name www.yoursite.com; ssl_certificate /etc/letsencrypt/live/yoursite.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yoursite.com/privkey.pem; return 301 https://yoursite.com$request_uri; } # リダイレクトを流される側の設定 server { listen 443 ssl default_server; server_name yoursite.com; ssl on; ssl_certificate /etc/letsencrypt/live/yoursite.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yoursite.com/privkey.pem; location =/fabicon.ico {access_log off; log_not_found off;} location /static/{ root /home/yourname/project; } location /{ include proxy_params; proxy_pass http://unix:/home/yourname/project/project.sock; } } |
1 2 3 | $ sudo service nginx start |
gunicornの再起動
1 2 3 | $ sudo systemctl restart gunicorn |
ブラウザでサイトの表示が行われるか、URL欄の表示がhttps対応になっているかを確認します。
letsencryptの証明書更新の自動化
letsencryptの証明書は3ヶ月ごとに更新する必要があります。
自動で更新を行うためにバッジ処理の設定を加えます。
詳しい方法は下記の記事にて確認してください。
独自ドメインサイトのSSL化(HTTPS化)【Letsencrypt,Ubuntu,Nginx】
本番環境での運用に向けて(static、mediaファイル表示の設定)
開発環境
例えばこのようにCSSフォルダを設置しても、Djangoは認識しません。
ですので、settings.pyに設定を加えます。
そうすることで、runserverするごとに設定したファルダから静的ファイルを読み込み、配信してくれます。
settings.py
1 2 3 4 5 | STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'static'), ) |
- 共通で利用するもの(settings_common.py)
- 本番環境用(settings.py)
- 開発環境用(settings_dev.py)
この3つに分割します。
まず、現在使用中のコードを共通用にコピーして、本番環境用は中身を削除します。
次に開発用を編集します。
1 2 3 4 5 6 7 | from .settings_common import * DEBUG = True EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' |
共通用のファイルをインポートしています
デバックを使用します
メール送信した際は、内容をコンソールに表示するようにします
開発サーバー起動時の読み込みファイルの設定
ローカルでサーバーを立ち上げる際は、settings_dev.pyを選択する必要があるので、pycharmのrunserverコマンドに開発用のファイルを読み込むようにします。
[runserver]→[edit configuration]を開き
Environment variablesの欄(PYTHONUNBUFFERED=1となっている箇所)に、以下の内容を追加します。
1 2 3 4 5 | Name:DJANGO_SETTINGS_MODULE Value:appname.settings_dev |
その他のエディター使用の際は、ローカル環境でサーバを立ち上げる際にコードを追加して対応します。
1 2 3 | $ python3 manage.py runserver --settings appname.settings_dev |
開発環境でのメディアファイルの設定
画像表示に対応するために、必要なライブラリをインストールします。
1 2 3 | (venv) $ pip3 install pillow |
開発環境では、プロジェクトディレクトリ直下にmediaディレクトリを作りその中に保存します。
以下のように編集します。
settings_dev.py
1 2 3 4 5 6 7 8 9 10 | from .settings_common import * import os DEBUG = True EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') |
*mediaフォルダは作成しなくても、初回の画像アップ時に作成されます。
以下のコードを編集します。
settings_common.py
1 2 3 | MEDIA_URL = '/media/' |
これで開発環境内で立ち上げブラウザで確認する際に、表示する画像は↑のURLに続くようになります。
上記のメディアファイルの表示に対応させるために、プロジェクトディレクトリのurls.pyに以下のコードを追加します。
1 2 3 4 5 6 7 8 9 | from django.conf.urls.static import static from . import settings_common, settings_dev ... ... urlpatterns += static(settings_common.MEDIA_URL, document_root=settings_dev.MEDIA_ROOT) |
これで、開発サーバーでメディアファイルを配信できるようになりました。
開発サーバーでのメディアファイル表示確認
これまでの設定を確認するために、画像をアップロードし、サーバー上でその画像を確認する最低限のアプリを追加して、動作を確認します。
プロジェクトディレクトリ直下で、uploadアプリを作成します。
1 2 3 | (venv)$ python3 manage.py startapp upload |
作成したuploadディレクトリ直下にtemplatesディレクトリを作成し、その中にupload.htmlを作成
他以下のように編集します。
upload.html upload/templates
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | {% block content %} <form action="{% url "upload" %}" method="post" enctype="multipart/form-data"> {% csrf_token %} <input type="file" name="image_file"> <input type="submit" value="submit" /> </form> {% if image_url %} <p>File uploaded at: <a href="{{ image_url }}">{{ image_url }}</a></p> {% endif %} {% endblock %} |
view.py upload/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from django.shortcuts import render from django.core.files.storage import FileSystemStorage def image_upload(request): if request.method == "POST" and request.FILES["image_file"]: image_file = request.FILES["image_file"] fs = FileSystemStorage() filename = fs.save(image_file.name, image_file) image_url = fs.url(filename) print(image_url) return render(request, "upload.html", { "image_url": image_url }) return render(request, "upload.html") |
urls.py /project
1 2 3 4 5 6 7 8 9 10 11 12 13 | from django.contrib import admin from django.urls import path from django.conf import settings from django.conf.urls.static import static from upload.views import image_upload urlpatterns = [ path("", image_upload, name="upload"), path("admin/", admin.site.urls), ] |
settings.py /project
1 2 3 4 5 6 | INSTALLED_APPS = [ … "upload", ] |
これで開発サーバーを立ち上げ、表示と動作を確認できればOKです。
本番環境用のメディアファイルの設定
環境開発同様の表示、動作を行えるように本番環境の設定を行います。
settings.py
1 2 3 4 5 6 7 8 9 10 | from .settings_common import * DEBUG = False ALLOWED_HOSTS = ['000.000.000.000','sample.com'] STATIC_ROOT = '/usr/share/nginx/html/static' MEDIA_ROOT = '/usr/share/nginx/html/media' |
本番環境の場合、STATIC_ROOTとMEDIA_ROOTは開発環境での、ベースディレクトリ下と指定していたものあたります。
静的ファイルを配信ディレクトリに設置する
開発環境ではdDjangoのプロジェクト内の画像をそのまま表示してましたが、本番環境は負担をへらすためnginxから、静的なファイルを表示するようにします。
リモートサーバーにSSH接続し、静的ファイルと、メディアファイルの作成と所有者の変更を行います。
1 2 3 | $ sudo mkdir -p /usr/share/nginx/html/static |
1 2 3 | $ sudo mkdir -p /usr/share/nginx/html/media |
1 2 3 | $ sudo chown username /usr/share/nginx/html/static |
1 2 3 | $ sudo chown username /usr/share/nginx/html/media |
nginxへのコンフィグファイルの編集
新たに作成したディレクトリに対応させるために、nginxのコンフィグファイルを編集します。
記入済みのstaticファイルのコードを削除
1 2 3 4 5 | location /static/{ root /home/yourname/yoursite; } |
削除した場所に以下の記入を追加
1 2 3 4 5 6 7 8 9 | location /static{ alias /usr/share/nginx/html/static; } location /media{ alias /usr/share/nginx/html/media; } |
リモートサーバー側にファイルを設置したので、Djangoアプリケーション内にある静的ファイルを、新たに作成したフォルダへ移します。
仮想環境に入り以下のコマンドを行います
1 2 3 | (venv) $ python3 manage.py collectstatic |
コマンド実行後に、nginx,guncornの再起動を行います。
1 2 3 | $ sudo systemctl restart nginx |
gunicornの再起動
1 2 3 | (venv) $ sudo systemctl restart gunicorn |
本番環境でもファイルのアップロード、表示の確認ができればOKです。
お疲れさまでした。
coconala にてPython,Djangoの開発、本番環境構築サービスを提供しています。
今回のブログで紹介している内容を試してみて、うまく動作しない等がある場合に利用を検討してみてください。
- ①依頼者様の本番環境サーバーの情報預かり、環境構築を行うサービス
Python,Djangoの本番環境構築します - ②ビデオチャットの画面共有にて、依頼者様のローカル、本番環境構築をリモートでサポートサービス
PythonDjango環境構築リモート援助します
この他にも、ココナラでは各種IT開発サポート、WEBデザイン、WEBマーケティングなど様々なサービスが提供されています。
以上、Ubuntu20.04,Python3.7,Nginx,Gunicorn,PostgreSQLを利用して、Djangoプロジェクトの本番環境構築の方法について紹介しました。