Nginx + Daphne を使って django-channel を AWS EC2 上で公開する
以前,「django-channels を使った websocket を用いたチャットアプリの作成」という記事を書きましたが,EC2 上にデプロイしたいという相談を受けたのでチャレンジしてみます。
なお,サービス公開のことを考えればスケールアウトやスケールアップを考えた方が良いですが,
今回はシンプルにただただ見られるようにするところをゴールとします。
EIP や RDS も使用しない,最安最小構成です。
環境
- AWS EC2
- OS: Amazon Linux 2 (Kernel 5.10)
- インスタンスタイプ: t2.micro (無料利用枠の対象)
セキュリティグループの編集からポート 80 にアクセスできるように事前に設定してください。
Nginx のインストール
$ sudo amazon-linux-extras install -y nginx1
$ sudo systemctl enable nginx.service
$ sudo systemctl start nginx.service
$ sudo systemctl status nginx.service
● nginx.service - The nginx HTTP and reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled)
Active: active (running) since 日 2022-02-06 08:43:38 UTC; 6s ago
Process: 3499 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
Process: 3494 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
Process: 3493 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
Main PID: 3501 (nginx)
CGroup: /system.slice/nginx.service
├─3501 nginx: master process /usr/sbin/nginx
└─3502 nginx: worker process
「Active: active (running)」となればOKです。
ウェブブラウザから IP アドレスに直接アクセスすると下の画面になるかと思います!
「Active: active (running)」だけどアクセスできないときは…
セキュリティグループの設定を見直してポート 80 にアクセスできるようにしてください。
RDBMS のインストール
今回は mariadb を使用します:
$ sudo amazon-linux-extras install -y mariadb10.5
$ sudo systemctl enable mariadb.service
$ sudo systemctl start mariadb.service
$ sudo systemctl status mariadb.service
● mariadb.service - MariaDB 10.5 database server
Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled; vendor preset: disabled)
Active: active (running) since 月 2022-02-07 14:09:40 UTC; 3s ago
Docs: man:mariadbd(8)
https://mariadb.com/kb/en/library/systemd/
Process: 8542 ExecStartPost=/usr/libexec/mariadb-check-upgrade (code=exited, status=0/SUCCESS)
Process: 8381 ExecStartPre=/usr/libexec/mariadb-prepare-db-dir %n (code=exited, status=0/SUCCESS)
Process: 8357 ExecStartPre=/usr/libexec/mariadb-check-socket (code=exited, status=0/SUCCESS)
Main PID: 8490 (mariadbd)
Status: "Taking your SQL requests now..."
CGroup: /system.slice/mariadb.service
└─8490 /usr/libexec/mariadbd --basedir=/usr
こちらも「Active: active (running)」となればOKです。
Redis のインストール
$ sudo amazon-linux-extras install -y redis6
$ sudo systemctl enable redis.service
$ sudo systemctl start redis.service
$ sudo systemctl status redis.service
● redis.service - Redis persistent key-value database
Loaded: loaded (/usr/lib/systemd/system/redis.service; enabled; vendor preset: disabled)
Drop-In: /etc/systemd/system/redis.service.d
└─limit.conf
Active: active (running) since 日 2022-02-06 11:35:52 UTC; 7s ago
Main PID: 5172 (redis-server)
Status: "Ready to accept connections"
CGroup: /system.slice/redis.service
└─5172 /usr/bin/redis-server 127.0.0.1:6379
こちらも「Active: active (running)」となればOKです。
mariadb のセットアップ
まずはセキュリティ設定から:
$ sudo mysql_secure_installation
Enter current password for root (enter for none):
Switch to unix_socket authentication [Y/n] Y
Change the root password? [Y/n] Y
New password:
Re-enter new password:
Remove anonymous users? [Y/n] Y
Disallow root login remotely? [Y/n] Y
Remove test database and access to it? [Y/n] Y
Reload privilege tables now? [Y/n] Y
設定したパスワードで接続できることを確認します:
$ mysql -u root -e 'status' -p
Enter password:
Enter password:
--------------
mysql Ver 15.1 Distrib 10.5.10-MariaDB, for Linux (x86_64) using EditLine wrapper
Connection id: 15
Current database:
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server: MariaDB
Server version: 10.5.10-MariaDB MariaDB Server
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: latin1
Db characterset: latin1
Client characterset: utf8
Conn. characterset: utf8
UNIX socket: /var/lib/mysql/mysql.sock
Uptime: 7 min 29 sec
Threads: 1 Questions: 24 Slow queries: 0 Opens: 20 Open tables: 13 Queries per second avg: 0.053
--------------
…さてここで「latin1」が気になるので設定します:
#
# This group is read both both by the client and the server
# use it for options that affect everything
#
[client-server]
+[client]
+default-character-set=utf8mb4
+
+[mysql]
+default-character-set=utf8mb4
+
#
# This group is read by the server
#
[mysqld]
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
+character-set-client-handshake=FALSE
+character-set-server=utf8mb4
+collation-server=utf8mb4_unicode_ci
#
# include all files from the config directory
#
!includedir /etc/my.cnf.d
編集したら,反映のため mariadb を再起動します:
$ sudo systemctl restart mariadb.service
$ mysql -u root -e 'status' -p
Enter password:
--------------
mysql Ver 15.1 Distrib 10.5.10-MariaDB, for Linux (x86_64) using EditLine wrapper
Connection id: 3
Current database:
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server: MariaDB
Server version: 10.5.10-MariaDB MariaDB Server
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: utf8mb4
Db characterset: utf8mb4
Client characterset: utf8mb4
Conn. characterset: utf8mb4
UNIX socket: /var/lib/mysql/mysql.sock
Uptime: 7 sec
Threads: 1 Questions: 4 Slow queries: 0 Opens: 17 Open tables: 10 Queries per second avg: 0.571
--------------
$ mysql -u root -e "SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';" -p
Enter password:
+--------------------------+--------------------+
| Variable_name | Value |
+--------------------------+--------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| collation_connection | utf8mb4_unicode_ci |
| collation_database | utf8mb4_unicode_ci |
| collation_server | utf8mb4_unicode_ci |
+--------------------------+--------------------+
とても良さげです!
次にアプリケーションで使用するユーザとデータベースを作成します:
$ mysql -u root -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 5
Server version: 10.5.10-MariaDB MariaDB Server
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)]>
> create database chat;
Query OK, 1 row affected (0.000 sec)
> grant all on chat.* to chat@'%' IDENTIFIED BY 'password';
Query OK, 0 rows affected (0.001 sec)
> flush privileges;
Query OK, 0 rows affected (0.000 sec)
作成したユーザで作成したデータベースにアクセスできればOKです:
$ mysql -u chat chat -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 8
Server version: 10.5.10-MariaDB MariaDB Server
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 [chat]>
Python のインストール
$ sudo amazon-linux-extras install -y python3.8
$ python3.8 -V
Python 3.8.5
👍
django アプリケーションのセットアップ
↑のソースコードをそのまま使用します。
ソースコードは↓です:
リポジトリをクローン
$ sudo yum install -y git patch
$ cd /opt/
$ sudo git clone https://github.com/yk-lab/django-websocket-chat-demo-app.git
$ sudo chown -R ec2-user:ec2-user django-websocket-chat-demo-app/
$ ls django-websocket-chat-demo-app/
Dockerfile.dev Pipfile Pipfile.lock README.md accounts chat config docker-compose.yml manage.py sample.env scripts templates
ファイル群が確認できればOKです。
pipenv・依存モジュールのインストール
$ sudo pip3.8 install pipenv
$ cd /opt/django-websocket-chat-demo-app/
$ pipenv install --deploy --system
$ python3.8 -m django
Type 'python -m django help <subcommand>' for help on a specific subcommand.
Available subcommands:
[django]
check
compilemessages
createcachetable
dbshell
diffsettings
dumpdata
flush
inspectdb
loaddata
makemessages
makemigrations
migrate
runserver
sendtestemail
shell
showmigrations
sqlflush
sqlmigrate
sqlsequencereset
squashmigrations
startapp
startproject
test
testserver
Note that only Django core commands are listed as settings are not properly configured (error: Requested setting INSTALLED_APPS, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.).
「python3.8 -m django
」で上のような出力が得られればOKです。
続いて DB に接続できるように依存ライブラリをインストールします:
$ sudo yum install -y gcc python38-devel
$ pip3.8 install mysqlclient
アプリケーションのセットアップ
$ cd /opt/django-websocket-chat-demo-app/
$ mv sample.env .env
https://djecrety.ir/ なりで SECRET_KEY
を作成します:
-SECRET_KEY=CHANGE_ME
+SECRET_KEY='b5ha%-yy1j1q7#k49c8cbza(io-z7t@$scyesm3(78ix92i2ei'
-DEBUG=true
+DEBUG=false
下記ファイルをダウンロードしてパッチを適用します:
$ wget https://gist.githubusercontent.com/yk-lab/247ed4134c37ad5e6788dc77df548dbd/raw/settings.py.patch -P ~
$ cd /opt/django-websocket-chat-demo-app/config
$ patch settings.py < ~/settings.py.patch
patching file settings.py
patch unexpectedly ends in middle of line
Hunk #4 succeeded at 148 with fuzz 1.
ALLOWED_HOSTS
と CHANNEL_LAYERS
が書き変わって STATIC_ROOT
と STATICFILES_DIRS
が追加されればOKです。
下記コマンドでエラーが出なければOKです(ワーニングは一旦無視してください):
$ cd /opt/django-websocket-chat-demo-app
$ set -a; source .env; set +a; python3.8 ./manage.py check --deploy
System check identified some issues:
WARNINGS:
?: (security.W004) You have not set a value for the SECURE_HSTS_SECONDS setting. If your entire site is served only over SSL, you may want to consider setting a value and enabling HTTP Strict Transport Security. Be sure to read the documentation first; enabling HSTS carelessly can cause serious, irreversible problems.
?: (security.W008) Your SECURE_SSL_REDIRECT setting is not set to True. Unless your site should be available over both SSL and non-SSL connections, you may want to either set this setting True or configure a load balancer or reverse-proxy server to redirect all connections to HTTPS.
?: (security.W012) SESSION_COOKIE_SECURE is not set to True. Using a secure-only session cookie makes it more difficult for network traffic sniffers to hijack user sessions.
?: (security.W016) You have 'django.middleware.csrf.CsrfViewMiddleware' in your MIDDLEWARE, but you have not set CSRF_COOKIE_SECURE to True. Using a secure-only CSRF cookie makes it more difficult for network traffic sniffers to steal the CSRF token.
System check identified 4 issues (0 silenced).
起動時にエラーとなるため,下記をダウンロードしパッチをあてます:
$ wget https://gist.githubusercontent.com/yk-lab/247ed4134c37ad5e6788dc77df548dbd/raw/asgi.py.patch -P ~
$ cd /opt/django-websocket-chat-demo-app/config
$ patch asgi.py < ~/asgi.py.patch
patching file asgi.py
起動後の画面アクセスでバグるので,下記をダウンロードしパッチをあてます:
$ wget https://gist.githubusercontent.com/yk-lab/247ed4134c37ad5e6788dc77df548dbd/raw/room.html.patch -P ~
$ cd /opt/django-websocket-chat-demo-app
$ patch templates/chat/room.html < ~/room.html.patch
patching file templates/chat/room.html
patch unexpectedly ends in middle of line
Hunk #1 succeeded at 63 with fuzz 1.
動作確認:
$ cd /opt/django-websocket-chat-demo-app
$ set -a; source .env; set +a; daphne config.asgi:application
2022-02-07 08:15:16,279 INFO Starting server at tcp:port=8000:interface=127.0.0.1
2022-02-07 08:15:16,280 INFO HTTP/2 support not enabled (install the http2 and tls Twisted extras)
2022-02-07 08:15:16,280 INFO Configuring endpoint tcp:port=8000:interface=127.0.0.1
2022-02-07 08:15:16,281 INFO Listening on TCP address 127.0.0.1:8000
特にエラーなく「Listening on TCP address 127.0.0.1:8000」と表示されればOKです。
Ctrl + C
で終了してください。
Nginx のセットアップ
daphne.sock
へプロキシするように下記設定ファイルを作成します:
upstream channels-backend {
server localhost:8000;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
location /static/ {
alias /opt/django-websocket-chat-demo-app/static;
}
# https://qiita.com/YuukiMiyoshi/items/d56d99be7fb8f69a751b
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_set_header X-Frame-Options SAMEORIGIN;
location / {
proxy_pass http://channels-backend;
}
}
反映のため,Nginx を再起動:
$ sudo systemctl restart nginx.service
実行・確認
static 配下に js, css ファイルを作成,DBのマイグレートをします:
$ cd /opt/django-websocket-chat-demo-app
$ mkdir static
$ python3.8 manage.py collectstatic
$ python3.8 manage.py migrate
あとは createsuperuser
でスーパユーザの作成をします:
$ cd /opt/django-websocket-chat-demo-app
$ python3.8 manage.py createsuperuser
メールアドレス: yetanother.yk@example.com
Password:
Password (again):
このパスワードは一般的すぎます。
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
最後に下記を実行:
$ cd /opt/django-websocket-chat-demo-app
$ set -a; source .env; set +a; daphne config.asgi:application
ウェブブラウザから「http://IPアドレス」でアクセスすれば,下記画面が表示されるはずです!
🎉
先ほど作成したスーパユーザでログインします:
別のブラウザからもアクセスしてチャットしてみます:
リアルタイムチャット成功です!
ちなみに、RDS,ECS を使って動くところまでやっているのでそちらも需要があればそのうち記事にします。
参考
- Amazon Linux 2にExtrasレポジトリからNginxをインストールする | DevelopersIO
- AmazonLinux2でPython3環境構築 - Qiita
- Linuxエンジニアらしいパッチのつくりかた - Qiita
- patchファイルの作り方 - Qiita
- Amazon Linux 2でサーバ作成 (Apache2.4+PHP7.2+MariaDB) - Qiita
- [SQL]MariaDBで絵文字保存 – Fatware
- mariadbのcollationをutf8mb4 に対応させる | ++頭道++
- mysqlデータベース作成と権限の付与 - Qiita
- .env ( dotenv ) ファイルの定義をシェルの環境変数として export するコマンドの例 ( set -a; source .env; set +a; ) #Linux #Shell - Qiita
- Deploying — Channels 3.0.3 documentation
- NginxのリバースプロキシでWebソケットを通す際の設定 - Qiita
Discussion