本稿はAWS EC2環境にて以下構成でdjango、nginx、uwsgiによる開発環境を構築する際の私的メモです。
構成
名称 | バージョン | 用途 | その他 |
---|---|---|---|
Amazon Linux | 2 | OS | |
nginx | 1.20.0 | Webサーバ | |
uwsgi | 2.0.20 | APサーバ | |
pyenv | 2.3.3 | Pythonの実行環境管理ツール | |
python | 3.8.0 | プログラミング言語 | |
pip | 22.2.2 | pythonライブラリパッケージ管理ツール | python3.8.0付属 |
venv | ー | 仮想環境ツール | python3.8.0付属 |
Mysql | 8.0.30 | DB |
実行環境全体像(デプロイ)
browser <-> nginx <-> unix socket <-> uwsgi <-> django
Pyenv
pyenvをインストール、環境変数の設定をする
sudo su
cd /usr/local/
git clone https://github.com/yyuu/pyenv.git ./pyenv
mkdir -p ./pyenv/versions ./pyenv/shims
cd /usr/local/pyenv/plugins/
git clone https://github.com/yyuu/pyenv-virtualenv.git
echo 'export PYENV_ROOT="/usr/local/pyenv"' | sudo tee -a /etc/profile.d/pyenv.sh
echo 'export PATH="${PYENV_ROOT}/shims:${PYENV_ROOT}/bin:${PATH}"' | sudo tee -a /etc/profile.d/pyenv.sh
source /etc/profile.d/pyenv.sh
cd ~/
cp /etc/sudoers /etc/sudoers.org
PATH_LINE=$(sed -n '/Defaults secure_path/=' /etc/sudoers)
sed -i -e "s/Defaults secure_path/#Defaults secure_path/g" /etc/sudoers
sed -i -e "${PATH_LINE}a Defaults env_keep += \"PYENV_ROOT\"" /etc/sudoers
sed -i -e "${PATH_LINE}a Defaults env_keep += \"PATH\"" /etc/sudoers
Python
pythonバージョン3.8.0をpyenvからインストール、設定する
pyenv install -v 3.8.0
pyenv global 3.8.0
ln -s /lib/python2.7/site-packages/amazon_linux_extras /usr/local/pyenv/versions/3.8.0/lib/python3.8/site-packages/
nginx
nginxをインストールする
amazon-linux-extras enable nginx1
amazon-linux-extras install -y nginx1
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.org
# virtualhost用ディレクトリ
mkdir /etc/nginx/sites-available
mkdir /etc/nginx/sites-enabled
設定ファイルを編集する
vim /etc/nginx/nginx.conf
includeを追記
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
再起動、自動起動設定
systemctl stop nginx
systemctl enable nginx
systemctl start nginx
Mysql
mysqlバージョン8をインストール、初期設定する
# MySQL GPGキーの有効期限切れ対応、インストール時にエラーが起きなければ必要ないです
# rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
yum-config-manager --disable mysql57-community
# mariadb削除
yum -y remove mariadb-*
rm -rf /var/lib/mysql/
yum localinstall https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm -y
yum -y install --enablerepo=mysql80-community mysql-community-server
yum -y install --enablerepo=mysql80-community mysql-community-devel
cp /etc/my.cnf /etc/my.cnf.org
echo 'character-set-server=utf8' | sudo tee -a /etc/my.cnf
echo 'default_password_lifetime=0' | sudo tee -a /etc/my.cnf
systemctl stop mysqld
systemctl enable mysqld
systemctl start mysqld
初期設定
mysql_secure_installation
初期パスワード入力 /var/log/mysqld.logから抽出
Securing the MySQL server deployment.
Enter password for user root:
新しいパスワードの入力
The existing password for the user account root has expired. Please set a new password.
New password: ******
Re-enter new password: ******
パスワード検証プラグイン
インストール済みなのでここでのパスワード入力は不要
The 'validate_password' plugin is installed on the server.
The subsequent steps will run with the existing configuration
of the plugin.
Using existing password for root.
Estimated strength of the password: 100
Change the password for root ? ((Press y|Y for Yes, any other key for No) : n
匿名ユーザの削除
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.
Remove anonymous users? (Press y|Y for Yes, any other key for No) : y
Success.
リモートからの root ユーザでのログイン禁止
Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.
Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y
Success.
test データベースの削除
By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.
Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y
- Dropping test database...
Success.
すぐに権限テーブルをリロードして変更を有効にするか
Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.
Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y
Success.
mysql にrootユーザでログインする
mysql -u root -p
パスワードバリデーション設定無効化
UNINSTALL COMPONENT 'file://component_validate_password';
データベースを作成「django_db」
MariaDB [(none)]> CREATE DATABASE django_db CHARACTER SET utf8;
Query OK, 1 row affected (0.00 sec)
ユーザー作成、権限設定
CREATE USER 'writer'@'%' identified by '******';
CREATE USER 'writer'@'localhost' identified by '******';
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,ALTER,INDEX,REFERENCES ON *.* TO 'writer'@'%';
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,ALTER,INDEX,REFERENCES ON *.* TO 'writer'@'localhost';
# migration時に権限エラーとなったので追加
GRANT ALL PRIVILEGES ON first.* TO 'writer'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
uwsgi
uwsgiをインストールする
yes | pip install --upgrade pip
yes | pip install wheel
yes | pip install uwsgi
ln -s /usr/local/pyenv/shims/uwsgi /usr/bin/uwsgi
ドキュメントルートディレクトリ作成
mkdir -m 755 /home/web
Django
venvで仮想環境化する
cd /home/web
mkdir test && cd test
# venvの仮想環境作成
python -m venv appvenv
# 仮想環境を有効化
source appvenv/bin/activate
# djangoインストール
# pipを更新
(appvenv) pip install --upgrade pip
# 仮想環境にDjangoをインストール
(appvenv) pip install django
# 仮想環境にuWSGIをインストール
(appvenv) pip install uwsgi
# 仮想環境にmysqlclientをインストール
(appvenv) pip install mysqlclient
# django プロジェクト作成
(appvenv) django-admin startproject test_pj
# django アプリ作成
(appvenv) cd test_pj
(appvenv) django-admin startapp test_apps
(appvenv) mkdir static templates
(appvenv) mkdir templates/test_apps
Djangoの設定ファイルを編集する
vim /home/web/test/test_pj/test_pj/settings.py
変更、追記を行う
import os
ALLOWED_HOSTS = ['IPアドレスまたはドメイン']
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_db',
'USER': 'writer',
'PASSWORD': '******',
'HOST': 'localhost',
'PORT': '3306',
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
}
}
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'
USE_I18N = True
USE_L10N = True
USE_TZ = False
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
Djangoのマイグレーション等を行う
# マイグレーションを行う
(appvenv) python manage.py makemigrations
(appvenv) python manage.py migrate
管理ユーザ作成
(appvenv) python manage.py createsuperuser
ユーザー名 (leave blank to use 'root'):admin
メールアドレス: admin@sample.com
Password: ******
Password (again): ******
Superuser created successfully.
静的ファイルを下記コマンドで集める
(venvname) python manage.py collectstatic
uwsgiの設定
socketファイルとpidファイルを格納するディレクトリを作成、所有者や権限を変更する
# ディレクトリ作成
mkdir -p /var/run/uwsgi
# 所有者変更
chown nginx:nginx /var/run/uwsgi
# 権限変更
chmod +w /var/run/uwsgi
appvenv配下にuwsgiのための変数を定義するファイルuwsgi_paramsを作成する。
# 移動
cd /home/web/test/appvenv
# ファイル作成
vim uwsgi_params
下記を記載、保存
uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;
uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param REQUEST_SCHEME $scheme;
uwsgi_param HTTPS $https if_not_empty;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;
同じくappvenv配下にuwsgi.iniファイルを作成する
# ファイル作成
vim uwsgi.ini
下記を記載、保存
[uwsgi]
uid = nginx
gid = nginx
base-htdocs = /home/web/test
project-name = test_pj
# 作成したDjangoアプリのルートを指定する
chdir = %(base-htdocs)/%(project-name)
# loadするwsgiモジュールを指定
module = %(project-name).wsgi
# 仮想環境の場所を指定する
home = %(base-htdocs)/appvenv
master = true
processes = 2
threads = 1
# socketとpidファイルの作成場所を指定する
socket = /var/run/uwsgi/%(project-name).sock
pidfile = /var/run/uwsgi/master.pid
chmod-socket = 666
vacuum = true
thunder-lock = true
max-requests = 6000
max-requests-delta = 300
# クライアント送信元IPアドレスをログに出力するか
log-x-forwarded-for = true
# ログ
logto = /var/log/uwsgi/%(project-name).log
deamonize = /var/log/uwsgi/uwsgi-@(exec://date +%Y-%m-%d).log
log-reopen = true
# 開発用リロード設定 ファイル監視、反映のためN秒毎にuwsgiをリロードする
py-autoreload = 1
emperor mode
uwsgiで複数アプリケーションを起動できる仕組み、同一サーバで複数人が開発をする事を想定して使用する
uwsgiの自動起動設定
# ファイル作成
vim /etc/systemd/system/uwsgi.service
下記を記載、保存
# uwsgi.service
[Unit]
Description=uWSGI
After=syslog.target
[Service]
ExecStartPre=-/bin/mkdir -p /var/log/uwsgi
ExecStartPre=-/bin/chown -R nginx:nginx /var/log/uwsgi
ExecStartPre=-/bin/mkdir -p /var/run/uwsgi
ExecStartPre=-/bin/chown -R nginx:nginx /var/run/uwsgi
ExecStart=/usr/local/pyenv/shims/uwsgi --ini /etc/uwsgi/emperor.ini
Restart=always
Restart=on-failure
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all
[Install]
WantedBy=multi-user.target
シンボリックリンク
mkdir -p /etc/uwsgi/vassals
# シンボリックリンクを設定
ln -s /home/web/test/appvenv/uwsgi.ini /etc/uwsgi/vassals/test.ini
emperor mode設定
vim /etc/uwsgi/emperor.ini
下記を記載、保存
[uwsgi]
emperor = /etc/uwsgi/vassals
uid = nginx
gid = nginx
logto = /var/log/uwsgi/uwsgi.log
touch-logreopen = /var/log/uwsgi/touch-logreopen
master = true
vacuum = true
ignore-sigpipe = true
ignore-write-errors = true
disable-write-exception = true
emperor modeになっているか確認
# 設定を読み込み
systemctl daemon-reload
# 再起動、自動起動をONに
systemctl stop uwsgi
systemctl enable uwsgi
systemctl start uwsgi
# ステータスを確認
systemctl status uwsgi
# ステータスが以下になっていればOK
Status: "The Emperor is governing 1 vassals"
nginxの設定
同一サーバで複数アプリケーションを運用することを想定しているので、バーチャルホストの設定を行う
/etc/nginx/sites-available
配下に設定ファイルを作成する。
vim /etc/nginx/sites-available/test
下記を記載、保存
# Djangoの設定
upstream test {
# uwsgi.iniで設定したソケットファイルの場所を指定する。
server unix:///var/run/uwsgi/test_pj.sock;
}
# サーバの設定
server {
# ポート番号
listen 80;
# virtual hostやIPを指定
server_name "ドメイン指定";
charset utf-8;
# Djangoの静的ファイルの設定
location /static {
# staticディレクトリが存在する場所を指定する。開発用なのでrootで指定
root /home/web/test/test_pj;
}
location / {
uwsgi_pass test;
# uwsgi_paramsの場所を指定する
include /home/web/test/appvenv/uwsgi_params;
}
}
上記で作成した設定ファイルのシンボリックリンクを/etc/nginx/sites-enabled
に貼る。
# シンボリックリンクを設定
ln -s /etc/nginx/sites-available/test /etc/nginx/sites-enabled/test
再起動
systemctl stop nginx
systemctl start nginx
ブラウザでアクセス
django初期ページが表示されたのを確認