ヒストグラムの階級数を決める方法論

データ分析業務ははっきり言って泥臭い。
分析の設計を行い、可視化を行ってから使えるデータかどうか判断できる。
そもそもそれはデータ分析前の話なのだが。

今回は、可視化の中でもデータの傾向を把握するのに役立つヒストグラム、その階級数を決める方法論を確認したい。
そこには思わぬ落とし穴があった。

1. きっかけ

筆者はコンサル(自社)やデータ分析受託会社、事業会社への研修を行うことが度々ある。
統計学をはじめ、科学は一つ一つの積み重ねで結果を出す。
そのうち、1ステップでも間違いがあれば結論が覆ることがある。

初学者はよく間違いを犯す。私もそうだった。

~その昔~
上長「決定木で要因分析した後、分かれたノードごとに数値を確認しておいて。」

ワイ「平均値と標準偏差が一致することを確認しました!問題ないです!」
上長「おっ早いね。分布はどうだった?」
ワイ(あ、分布は見てなかったわ・・)
ワイ「データはあるので今可視化しますね~」

ワイ「なんやこれ・・・全然違うやんけ」
上長「せやな」(やり直して来いよー)

ここまではっきり出ることは珍しいが、よくありがちなミスである。
要因分析をしたところで、ユーザー層が全く違う人たちを取ってくることはままある。
ユーザー層が似通っている根拠づけとして、分布を確認することは必要だろう。

データ分析の前段階で良く行うのは、平均値や中央値、標準偏差など代表値を確認することである。
ただし、今回のように当たり前に使われている代表値が意味をなさないことがある。

ちなみに、上記の平均値と分散は、どちらも10、4.5あたりである。
(実験コード(1)は後に記載している。)
可視化しない場合はほぼ変わらないと判断されてもおかしくはないだろう。
今回可視化したことによって、判断が変わることだろう。

2. ビン数決定どうしよう…

そういった背景もあり、基本的に私は必ず分布を確認することにしている。
ただ、分布を確認する場合、どうしても越えなければならない壁がある。

階級数設定(ビン付け)が経験則になることである。

それに対して、最近統計学入門(基礎統計学Ⅰ;赤本)を読み返していたところ、可視化のうち、ヒストグラムに関する記載があった。

P.22

このように、ヒストグラムを描くことによって、現象の基礎にある本質が発見されることがあり、単に理解の手助けとなるだけではないことが分かる。

同

度数分布表やヒストグラムを作成するときに注意すべき点は、階級数の問題と階級幅の問題である。
(略)
このように、階級をどのように取るかを決める統一的ルールはない。

うーん確かになあ。
例題として挙げるなら、以下のような分布があったらどうするかという話が一般的だろうか。

まずはそのままビン数は10。

正規分布かな・・・?170という数字に意味があるのかな。

次にもう少し細かくしてみる。k(ビン数)=100だ!

なんだろう・・・細かすぎてよくわからない。

ここで正解を出しておこう。
これは、30代の日本人男女の身長(cm)の分布を合わせたものである。

データは国民健康・栄養調査 身長・体重の平均値及び標準偏差 – 年齢階級、身長・体重別、人数、平均値、標準偏差 – 男性・女性、1歳以上〔体重は妊婦除外〕 を利用した。

簡単な多峰性を持つ正規分布だということは答えを見たらわかるが、ヒストグラムを描写しているときはイマイチわからなかったのではないか。
この正解の図を簡単に出せるとありがたいのだが。

赤本によると、スタージェスの公式というものがあるらしい。

k ≒ 1+log2(n)
*k=階級数の目安
*n=サンプルサイズ

ふむ、使ってみよう。今回は10になるのか。これって最初に確認したような・・・

やっぱりわからねえええええええ。。。。。。

答えが分かっているから何となくそれっぽく見えるが、前情報がないと判断できないだろう。
前情報が分からないから判断は難しいのである。

よし!それなら総当たりや!

for i in np.arange(10, 100):
    print("i=%s" % i)
    plt.hist(y, bins=i)
    plt.show()

1つずつ見たけど、なんもわからん・・・という人が多いのではないか。
それっぽく見えるけど、決定的な証拠として採用できるものがない。

作成したy1, y2のデータは、コード(2)の通りである。

y1 = np.random.normal(loc=171.2, scale=5.5, size=257)
y2 = np.random.normal(loc=158.6, scale=6.0, size=282)

「これならわかりそうなもんだけどなあ・・・」
私も思った。でもわからないのだ。

このように、分布を確認したほうが良いが、したところで何かが分かるとは限らないことに注意が必要だ。
ヒストグラムの階級数を決める方法論は・・・今のところなさそうだ。

今回のように多峰性があり、かつ分布が2つのみであることが事前に分かっているのであれば何らかの方法は取れるかもしれない。

しかし、ビン付けの総当たりをしてみたが、有効そうな数値は存在しなかった。
そのため、どのような数値を計算式で求めたところで意味がないと判断した。
*この判断も経験則であるが、ヒトのイメージでの判断能力は意外と高い。画像認識も然りだ。

実験コード

(1)

import numpy as np
import matplotlib.pyplot as plt
n = 10000

# 一様分布用関数
def randint(a, b, n):
    return (b - a) * np.random.rand(n) + a

# 正規分布
y1 = np.random.normal(loc=10.0, scale=4.5, size=n)
y1 = np.where(y1 < 0, np.nan, y1)
y1 = y1[~np.isnan(y1)]

# 一様分布
y2 = randint(2, 18, n) 
y2 = np.where(y2 < 0, 0, y2)
y2 = y2[~np.isnan(y2)]

# 可視化
plt.hist(y1, bins=100, alpha=0.5, label='A')
plt.hist(y2, bins=100, alpha=0.5, label='B')
plt.title('User Segments')
plt.legend()
plt.show()

# 代表値計算
print("A:", np.mean(y1), np.std(y1))
print("B:", np.mean(y2), np.std(y2))

(2)

y1 = np.random.normal(loc=171.2, scale=5.5, size=257)
y2 = np.random.normal(loc=158.6, scale=6.0, size=282)

y = np.append(y1, y2)

# 問題提起
plt.hist(y)
plt.show()

# ビン100
plt.hist(y, bins=100)
plt.show()

# 正解
plt.hist(y1, alpha=0.5)
plt.hist(y2, alpha=0.5)
plt.show()

# スタージェスの公式
def calc_sta(n):
    return int(1 + np.log2(n))

plt.hist(y, bins=calc_sta(len(y)))
plt.show()
print(calc_sta(len(y)))

# 総当たり
for i in np.arange(10, 100):
    print("i=%s" % i)
    plt.hist(y, bins=i)
    plt.show()

参考文献

[Meisyo] Viewは不要!SQL処理高速化方法

今回の問題は、対戦成績をデータ分析用に選手対選手で個別に保存していたことから始まります。

選手個人の総合成績をView処理で出力しまいした。
ただ・・・インデックス等がないのでめっちゃ計算時間が掛かるー!

ユーザーを少なく見積もって100ユーザーでも、1ユーザー最低10選手=1000選手持っています。
最大組み合わせ数は、1000選手×999選手=ほぼ100万・・・多すぎる(^^;

そういったものをSQLでSUMすればどうなるか。
そして、試合ごとに全選手を更新する。

もちろん重かった。
悲しかったです。

というわけで、対応策は下記の通りにしました。
・Viewではなく、総合成績の中間テーブルを作るようにしました。
・更新対象を狭め、自分と対戦相手の選手のみとしました。

改良前

個別成績テーブルスキーマ:
選手ID, 対戦選手ID, 試合数…

↓ 試合ごとにSQLでSUM(アクティブなユーザーの全選手)

総合成績Viewスキーマ:
選手ID, 試合数…

↓

各種データ呼び出し

改良後

個別成績テーブルスキーマ:
選手ID, 対戦選手ID, 試合数…

↓ 試合ごとに自分と対戦相手の選手の成績だけ、SQLでSUM

総合成績テーブルスキーマ:
選手ID, 試合数…

↓

各種データ呼び出し

結果

試合の待ち時間5~10秒(またはエラー)が、2秒以内に収まるようになりました。
SQLをテキトーに設定していたのですが、やっぱりちゃんと考えて書かないとダメですね。
いい教訓になりました。

Work It! 初期版Webアプリリリース

ソーシャルタイムトラッキングツールアプリWork It!(https://work-it.biz/)をリリースしました。

まずは、今何ができるのかをお伝えし、将来的な予定(つまり開発予定)となぜ開発しようと思ったのかを書きます。

今何ができるのか

2021年6月3日現在のアプリ機能は以下の4つです。

  1. ユーザー登録(利用に必須)
  2. タスク作成・編集・削除
  3. タスク別タイムトラッキング
  4. タイムトラッキング簡易統計情報表示

かなりシンプルで最低限の内容になっています。
使ってもらいたい人達がいるので、その説明のためにも実物が欲しかったわけです。

とりあえずは、下記の4つ内容を達成できるようにしています。

  1. したいことを思いったった時に、保存できる
  2. 忘れないようにするために、系統的にリスト化しておく
  3. タイムトラッキングと進捗率を保存する
  4. ログを簡単にでも見れるようにする

ログイン後のトップページは以下のようになっています。

これだと、とりあえずは仕事用メモアプリとして一応使えるかなレベルでしかないです。
一応使えるかなレベルだと継続的に使われないので機能の追加を予定しています。

将来何ができるようになるのか

  1. タスク管理
  2. よりタスク管理しやすいようにメモ機能、実績確認のための統計情報を表示。

  3. ルーム
  4. 誰かと一緒に作業しよう。独りはツラい。

  5. ユーザータイムライン
  6. 知り合った人達にしていることを共有して、やりたいことを一緒に進めよう。

  7. グループ
  8. グループで具体的にタスクを進めよう。

詳しくは下記パワーポイントファイルをご覧ください。
20210603_WorkIt

P.1

P2.

P.3

P.4

P.5

P.6

P.7

P.8

P.9

P.10

さいごに

まずはリリースできてよかったです。
少しずつですが機能を開発していきます~(^^v)
今後ともよろしくお願いいたします。

(VPSでつくる) Let’s EncryptでVPS上のWebサイトをSSL(HTTPS)接続にしよう

連載第十五回目です。
いや~この連載、長かったですね。まとめに1か月近くかかりました。

今回は、これまで作ってきたVPS環境のWebサイトをHTTPS接続に切り替えます。
HTTPS接続に切り替えるために使う機能は、非常に簡単なのでLet’s Encryptにします。
HTTPS接続には独自ドメインが必要になりますので、そちらも併せて説明します。

この記事は、VPSで作るPythonでのWebアプリ運用環境の連載記事です。
その他については上記ページをお読みください。

作業予定

下記の通り、作業を行います。

  1. 独自ドメイン取得
  2. 独自ドメイン反映
  3. SSH接続設定
  4. Let’s EncryptでWebサイトの設定を行う

独自ドメイン取得

簡単な手順で、最後の手順であるドメイン反映が行えるため、さくらのドメインで取得しました。別のサイトで取得していただいてもかまいませんが、ドメイン転入(さくらのドメイン)への申請が必要です。

転入がホントに面倒だった…orz

取得の具体的な方法については、さくらのドメインをご覧ください。

独自ドメイン反映

独自ドメインの変更の反映には少し時間が掛かるため、先に設定を行っておきます。

独自ドメインの設定(さくらのVPS設定マニュアル)の3.VPS側のネームサーバー設定を実施してください。

SSH接続設定

ファイアウォールを起動

さくらVPSのデフォルトでは、ファイアウォールがONになっていません。
VPSにログインし、まずはONにしておきます。

systemctl start firewalld.service
systemctl enable firewalld.service

自動起動設定もしておきましょう。

firewall-cmd --state

そうすると、httpアクセスも遮断されるため、以前の記事でデプロイしたアプリにアクセスできなくなります。
この間にVPSへのログインを切断するとログインできなくなるので注意してください。

パケットフィルタの停止

まず初めに、さくらのVPSコントロールパネルで、パケットフィルタを停止させておきます。

※こちらは必須ではありませんが、SSHのポート番号が22で固定されることが困る場合は実行必須です。

ファイアウォールの利用可能機能設定

とりあえず、HTTP接続とFTP接続、SSH接続は接続可能にしておきます。

sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service=ftp --permanent
sudo firewall-cmd --add-service=ssh --permanent
sudo firewall-cmd --reload

TeraTermで公開鍵を作って反映する

Tera Termで公開鍵と秘密鍵を作成して、安全にSSH接続を行う方法(エンジニア足立のコーディング日記さんより)を参照ください。

作成したid_rsa.pubをアップロードしてます。

       
cd ~            
mkdir .ssh
chmod 700 .ssh
mv id_rsa.pub .ssh/authorized_keys
chmod 600 .ssh/authorized_keys

※さくらVPSのOSインストール時の機能として、id_rsa.pubを登録することもできます。

いったんログアウトして、今度は公開鍵認証でログインします。
パスフレーズはVPSサーバーのユーザーではなく、公開鍵を作った時のパスワードを入力してください。

セキュリティのための設定

rootユーザーは強すぎる権限を持つため、VPSへのログインを別ユーザーで行います。
そのため、新規ユーザーを先に作成します。
加えて、平文パスワードでのログイン認証も不可能にしましょう。

ユーザーの作成とsudo設定

rootユーザーの代わりのユーザー(例:sakura)を作成します。

useradd sakura

ユーザー(sakura)のパスワードを設定します。

passwd sakura

ユーザー(sakura)にsudo権限を与えます。

usermod -G wheel sakura
設定ファイルの変更

SSH設定ファイル(/etc/ssh/sshd_config)を変更します。

PasswordAuthentication no

※今回はポート番号は変えません。変えたい場合は、こちらの記事を参照ください。

変更後、下記コマンドを実行します。

sudo systemctl restart sshd
sudo firewall-cmd --reload

最後に、firewallで有効にされている機能を確認します。
http、ssh、ftpがあることを確認してください。

firewall-cmd --list-services --zone=public --permanent

確認のため、ユーザーを切り替える場合は下記コマンドを入力します。

su sakura

rootでログインしなおし、今回作成したユーザーに切り替えてください。

Let’s EncryptでWebサイトの設定を行う

Let’s Encryptのクライアントcertbotをインストールし、反映する

今回はwork-it.bizという独自ドメインを使います。環境に合わせて変更してください。

まずはepelと、epelを利用したcertbotのインストールをします。

sudo yum install -y epel-release
sudo yum install -y certbot

続いて、証明書の発行を行います。
メールアドレスの入力と確認を求められます。

sudo systemctl stop nginx
sudo certbot certonly --standalone -d work-it.biz
sudo systemctl start nginx

※certbotは80番ポートを使うので、nginxを止めておく必要があります。もちろんファイアウォールも止めておかないとエラーが出ます(出ました)。

最後に設定ファイル(/etc/nginx/conf.d/work-it.biz.conf)を下記の例に沿って変更します。

server {
       listen 80;
       listen [::]:80;
       server_name work-it.biz;
       return 301 https://$host$request_uri;
}

server {
       listen  443 ssl;
       server_name     work-it.biz;
       #ssl on;
       ssl_certificate         /etc/letsencrypt/live/work-it.biz/fullchain.pem;
       ssl_certificate_key     /etc/letsencrypt/live/work-it.biz/privkey.pem;
}

Nginxを再起動します。

sudo systemctl restart nginx

HTTPSの起動

ファイアウォールにHTTPSを登録し、リロードします。

sudo firewall-cmd --add-service=https --permanent
sudo firewall-cmd --reload

最後に、cron設定ファイルを作っておき、自動更新設定を掛けておきます。

sudo crontab -e

下記を正しく設定してください。

0 12 5 * * certbot renew --pre-hook "systemctl stop nginx" --post-hook "systemctl start nginx"

※この設定では、毎月5日12時に更新がかかる設定となります。

最終確認

http://work-it.bizと、https://work-it.bizどちらもにアクセスできることを確認してください。

httpsへアクセスした場合、下記のようにCentOS7の初期表示が見えます。

赤枠の部分に鍵マークがついていることが確認できると思います。

おつかれさまでした~。

おわりに

今回は、WebサイトにHTTPS接続ができるように設定しました。
意外と単純に設定ができるので驚きました(@@

通常の運用だと、この後HTTPの接続をできなくするなどの設定を行います。
HTTPを開いておく必要は全くないので。
これである程度のセキュリティ設定は完了しました!

この記事は、VPSで作るPythonでのWebアプリ運用環境の連載記事です。
次回以降は上記記事からご覧ください。

(VPSでつくる) セキュリティ設定

連載第十四回目です。

セキュリティ設定について何もわからん状態なので色々と漁っていました。
PythonやFlaskなどの個別のモノに対してのセキュリティ設定の書籍は中々多くないので、Linuxなどの基礎的なセキュリティ設定について学習する方がいいと思われます。

その学習には下記のようにシステムの構成図を書いて、どこがセキュリティを設定しきれていないか確認しながら進むといいでしょう。

抜け道で言うと、プロに聞くのが最短ですね。

この記事は、VPSで作るPythonでのWebアプリ運用環境の連載記事です。
その他については上記ページをお読みください。

すべての基本

バージョンアップしよう。
基本的に、脆弱性はバージョンアップすると減る。

CentOS7のセキュリティ設定

参考記事:接続時のセキュリティの設定(CentOS 7)(さくらVPS設定マニュアル)

1. さくらVPSのデフォルトではファイアウォールが起動されていないことがある。

ファイアウォールの起動コマンドは下記の通り。

systemctl start firewalld

さくらVPS独特のパケットフィルタという厄介な設定もあるので注意。

2. ファイアウォール中にサービスの利用を許可するコマンドを使わないと、自作のサービスが動かない

ファイアウォールの許可を追加するコマンドは以下の通り。

firewall-cmd --permanent --zone=public --add-service=許可するサービス名

許可を追加しても、ファイアウォールをリロードしないと設定は反映されません。

参考記事:サーバ作成直後に設定しておくべき初期セキュリティ設定(さくらのVPS)

本来の参考記事はさくらVPSでDjangoアプリを公開する手順の備忘録(note:夕月悠里さん)ですが、公式がベースになっているので記載。

  1. ROOTユーザーは使わない
  2. SSH接続用の公開鍵暗号方式を使う
  3. HTTPS(SSL)使おうぜ
  4. HTTPSに必要な独自ドメインは無料で取れるサービスもあるし、HTTPSでないと安全でないサイトと表示されるのでやりましょう。
    → 記事参照:Let’s EncryptでVPS上のWebサイトをSSL(HTTPS)接続にしよう

あくまで基本やけど、個人開発で全部をカバーできている所は多くない気がする。

Nginxのセキュリティ設定

表示

1. レスポンスにNginxのバージョンを表示させない。

Nginx設定ファイル(/etc/nginx/conf.d/default.conf)に下記を追加。

http {
    server_tokens off;
}

バージョン情報=脆弱性情報ですからねえ・・・。

FTPのセキュリティ設定

ファイル送信にはSFTPかSCPを使おう。

Pythonのセキュリティ設定

Python2はやめてPython3を使おう。
かつ、メジャーバージョンでもできるだけ新しいバージョンを使おう。

そのためには、Nginx Unitさんは早く、公式でPython3.6.8以外の対応をできるようにすべき。Dockerでどうにかなるらしい(未確認)が面倒。
GunicornやuWSGIは、バージョンを気にしなくてOKなのが楽。ただしWindows上では試験的に使えないのは面倒。WSL2等で特別に設定すればできるが面倒。

Flaskのセキュリティ設定

参考記事:Flaskのセキュリティ対策(simon’s noteさん)

特に注意すべきは下記3点。1番が一番抜けやすい気がする。

  1. 自分で変数を埋め込んだHTMLを用意する場合にはescapeを使う
  2. コンテンツセキュリティポリシー(CSP)
  3. X-Content-Type-Options

Flaskバージョンアップ

Flask2が出たのでそちらを使った方がいいかもしれない。

Flaskのセキュリティ設定に関するバグ(?)

1. データベースとの通信に使うapp.SECRET_KEYの乱数生成文字列の設定に要注意

CentOS7+Python3だとデフォルトはascii。
asciiで対応できない文字列(例:日本語等)を入れると、エラーは表示されないが、ログイン時のクッキー操作等に異常が出る。

記事13で行った、文字コードのデフォルト設定をUTF-8にすると解決する。

phpMyAdminのセキュリティ設定

最低限、アクセス可能IPを制限する必要がある。
ディレクトリ名をphpMyAdminにしない。

おわりに

色々調べてみましたが、セキュリティ設定は難しい。。
不足している観点があればURLだけでもコメントいただけると幸いです。

この記事は、VPSで作るPythonでのWebアプリ運用環境の連載記事です。
次回以降は上記記事からご覧ください。

(VPSでつくる) Socket通信を使ったモダンなチャットアプリをFlaskで作ろう

連載第十三回目です。

今回は、チャットアプリを作っていきたいと思います。
チャットの想定としては、会員制、socket通信で滑らかにチャットできる、データベースにログを残すにしましょう。

ただのチャットとは言え、使いやすさも考えて構築を行います。
そのため、HTML、JavaScript(jQuery含む)、CSSなどでの記載も行います。
ただし、理解が簡単になるよう、コメントを多めに書いています。

この記事は、VPSで作るPythonでのWebアプリ運用環境の連載記事です。
その他については上記ページをお読みください。

作業予定

まず、テストアプリプログラムファイルのダウンロードが必要です。
Github(https://github.com/R2002/flask_chat)
テストアプリフォルダ(app/flask_chat)は、VPS上の/usr/share/nginx/app/flask_chatにアップロードします。

作業予定としては以下を想定しています。
・Gunicorn+eventletの設定
・CentOS7日本語対応
・チャットアプリのsystemd上でのサービス化
・Nginxの設定
・公開(デプロイ)

socket通信には、Gunicornやeventletなどのサービスが必要になります。Webサーバー兼リバースプロキシのNginxだけでは対応できません。
そのため、いろいろと設定が必要になります。

続いて、どのような思考でそれぞれのプログラムが書かれているのか確認します。

構成


このアプリは、チャットアプリです。
滑らかなチャットを行うためにsocket通信を使います。

socket通信の担い手はWSGIサーバーであるGunicorn、その一機能のeventletです。
前回のアプリまで使っていたNginx Unitは、eventletに関する資料がなかったので使いませんでした。

ファイル構成


ファイルごとに関係を示します。

前回と比べconfig.pyなどが増えましたが、設計思考は同じです。
viewsとmodelsをディレクトリ化したのは、機能の増加を何度か行い記載量が増えた際に、コーディングの状況が一人開発ですら分かり辛くなるからです。例えば、app.pyにviewsの記載をべた書きしていると、複数人での開発は困難になります。

ディレクトリを分けることによって、機能の一時停止判断や、バージョンアップ・ダウンの切り替え作業が非常に簡単になります。

なお、Flaskアプリの起動にはrun.pyを利用しています。
すべてのファイルは、run.pyから見た絶対的または相対的な記述が必要です。
例えば、importやfromで指定するディレクトリはどこか、パスはどう記載しなければ動かないか等です。

Gunicorn+eventletの設定

flask-socketioの公式を参考にします。

まずは、仮想環境(/usr/share/nginx/venv/flask_chat)を作り、その環境上でgunicornなどをインストールします。
gunicorn以外は、テストアプリに含まれるrequirements.txtをご利用ください。

pip install gunicorn==20.1.0

※バージョンは変更して問題ありません。

最後に、アプリフォルダ(/usr/share/nginx/app/flask_chat)に移動して、gunicornでflask_chatを起動します。

gunicorn -k eventlet -w 1 run:application

ちなみに、Windows上ではgunicornは動きませんのでご注意ください。

CentOS7、Windowsどちらでも動く下記コマンドは優秀ですね!

python run.py

何度かテスト立ち上げをしていると、ポートはもう使われているというエラーが出ます。
その場合はポートを開けるために、プロセスを停止させる必要があります。

プロセスの検索は下記コマンドを利用します。

ps ax

pythonのプロセスを探して、PIDを指定します。

kill -9 [該当のPID]

CentOS7日本語対応

CentOS7はそのままの設定だと言語が英語になっています。
チャットでは日本語を使うのですが、チャット内容に日本語を含む場合エラーが発生します。
エラーが起こらないよう、言語設定を変更していきます。

まずは、環境変数(LANG)を確認します。
LANG=C(英語)となっていると思います。

env

設定ファイルも確認しておきましょう。

less  /etc/locale.conf

次に、使える言語を確認します。
ja_JP.utf8があるか確認してください。

locale -a

最後に、下記コマンドで設定を書き換えます。

localectl set-locale LANG=ja_JP.utf8

これで日本語入力ができるようになりました。

失敗例

下記ファイル群を書き換えても意味がありません。
~/.bash_profile
~/.bashrc
~/.profile

下記コマンドもシェル上だけで有効で、systemd上のサービスにすると日本語にエラーが出ます。

export LANG=ja_JP.utf8

チャットアプリのsystemd上でのサービス化

それでは、デプロイのために色々と設定を行っていきましょう。

Gunicorn

gunicorn.conf.pyを下記の通りに作成します。

workers = 1
worker_class = 'eventlet'
bind = 'unix:/run/flask_chat.socket'

上記のファイルは、以下のようにコマンド上で利用します。

gunicorn run:application --config gunicorn.conf.py

worker_classは、eventletかgeventを指定します。
bindは、どこのポートまたはソケットで立ち上げるかを設定します。今回はソケットを使います。
workerについては、CPU1個あたりworkerを2~4個用意するのがいいようです。1個だとたまにチャットのメッセージが消えます。

CPU数を出力するには下記コードをpythonインタプリンタ上で使用してください。

import multiprocessing
print(multiprocessing.cpu_count())

serviceおよびsocketの準備

flask_chat.serviceとflask_chat.socketを用意します。
※settings_envフォルダに入っているのでアップロードしていただいてもかまいません。

flask_chat.serviceの内容は下記の通りです。

[Unit]
Description=flask_chat daemon
Requires=flask_chat.socket
After=network.target

[Service]
User=root
Group=root
RuntimeDirectory=gunicorn
WorkingDirectory=/usr/share/nginx/app/flask_chat/
ExecStart=/usr/share/nginx/venv/flask_chat/bin/gunicorn --config /usr/share/nginx/app/flask_chat/gunicorn.conf.py run:application
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
KillMode=mixed
PrivateTmp=true
Restart=always

[Install]
WantedBy=multi-user.target

注意すべき点は、ExecStartを仮想環境上のgunicornに指定することです。
venvを直接指定しなくても、勝手に良い感じに読み込みをしてくれます。

flask_chat.socketの内容は下記の通りです。

[Unit]
Description=flask_chat socket

[Socket]
ListenStream=/run/flask_chat.socket

[Install]
WantedBy=sockets.target

2つのファイルをアップロードして、下記コマンドで指定位置にコピーします。

cp flask_chat.service /etc/systemd/system/flask_chat.service
cp flask_chat.socket /etc/systemd/system/flask_chat.socket

サービス起動

下記コマンドでサービスを自動開始設定・開始します。

systemctl enable flask_chat.socket
systemctl start flask_chat.socket

※socketを起動すると、自動的にflask_chat.serviceが起動するのでコマンドは不要です。

最後に、動作確認を行います。

curl --unix-socket /run/flask_chat.socket localhost

エラーが出ずに、HTMLが返ってくれば設定は完了です。

Nginxの設定

Nginx Unit設定ファイル(/usr/share/nginx/conf.json)を下記の通りに変更します。
使わないので空にしましょう。

{
    "listeners": {
    },

    "applications": {
    }
}

設定を反映します。

sudo curl -X PUT --data-binary @/usr/share/nginx/conf.json --unix-socket /var/run/unit/control.sock http://localhost/config
systemctl restart unit

Nginx設定ファイル(/etc/nginx/conf.d/default.conf)のlocationを変更します。

location / {
    proxy_set_header Host $host;
    proxy_pass http://unix:/run/flask_chat.socket;
}

再起動させましょう。

systemctl restart nginx

公開(デプロイ)

上記の手続きが問題なければアプリが起動すると思います。
おつかれさまでした。

あとは、前回と同様にデータベース(flask_chat)を用意しておく必要がありますが、今回は説明を割愛します。

問題がなければ、下記のように別ブラウザおよび別IPからで滑らかなチャットを行えます。

socket通信で問題となる、ブラウザ上では通信確立が上手くできたかわからないについても、通信が確立されるまではチャットを表示しないようにしています。

おわりに

今回は、socket通信を使った滑らかなチャットが可能なアプリをデプロイまで持っていきました。

次回以降は、これまで全く考えられていなかったセキュリティ設定等を行っていきます。
アプリをデプロイしても、頻繁に落ちたり、個人情報が取られたり・・・可能性は十分あり得ます。
そのため、HTTPS(SSL)接続などの設定も行います。

この記事は、VPSで作るPythonでのWebアプリ運用環境の連載記事です。
次回以降は上記記事からご覧ください。

(VPSでつくる) Python(Flask)でMariaDB(MySQL)へ接続できるアプリをもっと読みやすく改良してみよう

連載第十二回目です。

前回の記事で、Python3.6.8+FlaskでMariaDBに接続・データベースを編集するアプリを動作させる設定を行い、動作確認しました。

今回は、機能は前回と全く同じアプリを、もっと簡潔に読みやすく記述する方法を説明します。
コーディングの解説のみで、アプリの動作確認等は行いません。

この記事は、VPSで作るPythonでのWebアプリ運用環境の連載記事です。
その他については上記ページをお読みください。

作業予定

まず、テストアプリプログラムファイルのダウンロードが必要です。
Github(https://github.com/R2002/flask_db_blueprint)

続いて、どのような思考でそれぞれのプログラムが書かれているのか確認します。

構成

このアプリは、データベース(MariaDB)を変更するアプリです。

HTTP接続でWebサーバ(Nginx)にアクセスし、APサーバ(Nginx Unit)を介してPythonアプリをvenvで起動しています。
Nginx UnitでのPythonのバージョンは導入が簡単なので3.6.8を選択しました。
phpMyAdminはWebサーバ(Nginx)上のPHP-FPMで動かしています。

このように図解することで、どんなアクセスに対し、それぞれの機能が対応しているかを分かりやすくしています。

ファイル構成

ファイルごとに関係を示します。
viewsとmodelsをディレクトリ化したのは、機能の増加を何度か行い記載量が増えた際に、コーディングの状況が一人開発ですら分かり辛くなるからです。例えば、app.pyにviewsの記載をべた書きしていると、複数人での開発は困難になります。

ディレクトリを分けることによって、機能の一時停止判断や、バージョンアップ・ダウンの切り替え作業が非常に簡単になります。

なお、Flaskアプリの起動にはrun.pyを利用しています。
すべてのファイルは、run.pyから見た絶対的または相対的な記述が必要です。
例えば、importやfromで指定するディレクトリはどこか、パスはどう記載しなければ動かないか等です。

ディレクトリ構成

前回に比べて、ディレクトリは増えましたが機能は変わっていないので、理解はそこまで難しくないと思います。

/usr/share/nginx 
 ┗ app アプリ用ディレクトリ
 | ┗ flask_db_blueprint テストアプリ用ディレクトリ
 |   ┗ models データベースモデル設定用ファイル(旧:models.py)
 |   ┗ templates HTML設定用テンプレートファイル
 |   ┗ views ビュー用ファイル(旧:app.py内に記載)
 |   ┗ app.py アプリ本体
 |   ┗ config.py 設定ファイル
 |   ┗ database.py データベース用関数ファイル
 |   ┗ run.py 起動ファイル
 ┗ venv 仮想環境用ディレクトリ
   ┗ flask_db テストアプリ用環境(前回アプリとインストール内容は同じ)

コード解説

それではflask_db_blueprintのディレクトリ内にあるファイルを一つずつ、コードを解説していきます。

run.py

オンラインではNginx UnitからWebアプリを起動するため、ローカルではflaskでローカルサーバーを起動するためのファイルです。

from app import app as application

if __name__ == '__main__':
    application.run()

Nginx Unitのデフォルトでは、application.run()が必要です。
そのため、app.pyを呼び出して、appをapplicationにエイリアスを変更してからrun()を行っています。
※conf.jsonの個別のapplicationのcallback属性でエイリアス(application)の変更が可能です。

app.py

run.pyから呼び出されるファイルです。
アプリ設定(Flask、設定、DB)の基本的な流れが書かれています。

from flask import Flask
import config, views
from database import init_database

# create_app
def create_app():
    # Flask定義
    app = Flask(__name__)
    # 設定反映
    app.config.update(config.cf)
    # DB設定
    init_database(app)
    return app

# app
app = create_app()

# Blueprint
# データベース参照(view): views/index.py
app.register_blueprint(views.index.app)

# 一行追加(insert), 一行変更(update), 一行削除(delete): views/database.py
app.register_blueprint(views.database.app)

create_appでアプリ設定をした後に別で表示用にBlueprintを定義することで、
・アプリとして起動したい場合は、ファイル全体を呼び出す。
・アプリのDB初期設定を行いたい場合は、app.pyのcreate_appのみを呼び出す。
という使い方が可能になります。

config.py

アプリの設定を全て統括するファイルです。
今回は追加していないですが、画像・JavaScript・CSSなどの静的ファイルのディレクトリ設定(絶対パス・相対パス問わない)などを設定すると良いかと思います。

import os

#--------------------------------------#
# 設定ファイル
#--------------------------------------#
cf = {} # 削除しないでください

# Flaskのデバッグ表示を有りにする
cf['DEBUG'] = 1

# DB設定
cf['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://{user}:{password}@{host}/{db_name}?charset=utf8'.format(**{
    'user': os.getenv('DB_USER', 'root'),
    'password': os.getenv('DB_PASSWORD', ''),
    'host': os.getenv('DB_HOST', 'localhost'),
    'db_name': 'flask_db_blueprint',
})

# TRACK_MODIFICATIONSを無効にしておく
cf['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

database.py

DBの読み込み設定を行っています。
今回はflask_SQLAlchemy(DB接続方法)とflask_migrate(DB更新方法)を規定しています。
その他には、init_database()などの関数を定義しておくことで、DBロジックの変更に対して、このファイルの書き換え行うだけで対応が可能になります。

from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

# DB規定
db = SQLAlchemy()

# db初期設定
def init_database(app):
    db.init_app(app)
    Migrate(app, db)

# 追加または更新
def db_insert(data):
    db.session.add(data)
    db.session.commit()

# 削除
def db_delete(data):
    db.session.delete(data)
    db.session.commit()

おわりに

今回はflaskアプリの中身について解説しました。
どう動いているのか、なぜこのような記載方法になっているのかを知ることで、このアプリではない他アプリをどう作るべきか考えるのに役立てれば幸いです。

その他にも下記のようなページが参考になります。
・【Flask】ディレクトリ構成を考える

次回は、このアプリを元に、Socket通信を用いた軽量チャットアプリを作成します。
Webアプリ(Flask)+Socket通信はまとまった解説がなく、かなり理解に時間が取られてしまったので、後の方はもっと楽してほしいなーと思っています。

この記事は、VPSで作るPythonでのWebアプリ運用環境の連載記事です。
次は、13. Socket通信を使ったモダンなチャットアプリをFlaskで作ろうです。

(VPSでつくる) PythonでMariaDB(MySQL)へ接続できるアプリを触ってみよう

連載第十一回目です。

Python3.6.8+FlaskでMariaDBに接続・データベースを編集するアプリを動作させる設定を行い、動作確認します。

この記事は、VPSで作るPythonでのWebアプリ運用環境の連載記事です。
その他については上記ページをお読みください。

作業予定

作業予定としては、下記のアプリを作っていきます。
まず動かしてみて、その後でFlaskの各関数が何をしているか解説していきます。

ディレクトリ構成

/usr/share/nginx 
 ┗ app アプリ用ディレクトリ
 | ┗ flask_db テストアプリ用ディレクトリ
 |   ┗ app.py アプリ本体
 |   ┗ config.py 設定ファイル
 |   ┗ database.py データベース用関数ファイル
 |   ┗ models.py データベースモデル設定ファイル
 |   ┗ run.py 起動ファイル
 ┗ venv 仮想環境用ディレクトリ
   ┗ flask_db テストアプリ用環境

機能

・データベース参照(/)
・1行追加(/insert)
・1行変更(/update)
・1行削除(/delete)

作業内容

まず、テストアプリプログラムファイルのダウンロードが必要です。
Github(https://github.com/R2002/flask_database_test)
アップロードして使用しますので、適宜内容を見てご利用ください。

まずは、ディレクトリを移動します。

cd /usr/share/nginx

次に、アプリ用ディレクトリを作ります。

mkdir app/flask_db

仮想環境を作り、その仮想環境に入ります。

python3 -m venv venv/flask_db
source venv/flask_db/bin/activate

pipをアップグレードしておきます。

pip install --upgrade pip

ダウンロードしたファイルの中にあるrequirements.txtアップロードし、テストアプリに必要なPythonモジュールを下記コマンドでインストールします。仮想環境上でインストールするようにしてください。

pip install -r requirements.txt

ファイルをアップロードできない場合は、パーミッション変更を下記の通り行ってみてください。

chmod 0777 /usr/share/nginx

requirements.txtファイルの内容は以下の通りです。

flask==1.1.2
flask-sqlalchemy==2.5.0
SQLalchemy==1.3.23
pymysql==1.0.2
Flask-Migrate==2.7.0

簡易アプリ(main.py)作成し、複数アプリを同時並行でNginx Unitでデプロイできることを確認します。
まずは、アプリ用ディレクトリに移動します。

cd app/flask_db
[python]

続いて、<strong>main.py</strong>を作成します。
[python]
from flask import Flask

application = Flask(__name__)

@application.route('/')
def index():
    print('test')
    return "Hello Flask"

if __name__ == '__main__':
    application.run()

/usr/share/nginx/conf.jsonを編集し、flask_testに加え新たなアプリ(flask_db)を起動できるようにします。

{
    "listeners": {
        "*:8081": {
            "application": "flask_test"
        },
        "*:8082": {
            "application": "flask_db"
        },
    },

    "applications": {
        "flask_test": {
            "type": "python 3.6.8",
            "path": "/usr/share/nginx/app/flask_test/",
            "home": "/usr/share/nginx/venv/flask_test/",
            "module": "main"
        },
        "flask_db": {
            "type": "python 3.6.8",
            "path": "/usr/share/nginx/app/flask_db/",
            "home": "/usr/share/nginx/venv/flask_db/",
            "module": "main"
        },
    }
}

Nginx Unitの設定を更新します。

sudo curl -X PUT --data-binary @/usr/share/nginx/conf.json --unix-socket /var/run/unit/control.sock http://localhost/config

Nginxの設定ファイル(/etc/nginx/conf.d/default.conf)に下記を追記します。

    location /flask_db/ {
        proxy_pass http://127.0.0.1:8082/;
    }

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

systemctl restart nginx
systemctl restart unit

下記のURLでアクセスできるようになります。
http://XXX.XXX.XXX.XXX/sample/
→ 前回のテストアプリ
http://XXX.XXX.XXX.XXX/flask_db/
→ 同じようなテスト用アプリ

今後は、flask_dbを改良していきます。

それでは、ファイルアップロードのためのパーミッション変更を行います。

cd /usr/share/nginx
chmod 0777 app/flask_db

flask_db内にファイルをアップロードします。

conf.jsonを編集し、applicationsのflask_db、moduleをmainからrunにしてください。

{
    "listeners": {
       # 略
    },

    "applications": {
        "flask_test": {
           # 略
        },
        "flask_db": {
            # run
            "module": "run" # ここだけ変更
        },
    }
}

Nginx Unitの設定を更新します。

sudo curl -X PUT --data-binary @/usr/share/nginx/conf.json --unix-socket /var/run/unit/control.sock http://localhost/config

phpMyAdminで、新しいデータベースflask_dbを作っておきます。照会順序はutf8_general_ciで問題ありません。
http://XXX.XXX.XXX.XXX/phpMyAdmin/

最後に、アプリ設定ファイル(app/flask_db/config.py)を編集し、phpMyAdminで設定したユーザーのパスワードを記載します。

再起動をしておきましょう。

systemctl restart nginx
systemctl restart unit

ここまでで設定は終わりです!
おつかれさまでした。

あとは実際にアプリを触っていきます。

まず、データベースをcreateします。
そのためにflask_db仮想環境に入っておき、ディレクトリを/usr/share/nginx/app/flask_dbに移動します。

続いて、pythonコマンドでPythonインタプリンタを起動し、下記コマンドを入力します。

from app import create_app
from database import db
db.create_all(app=create_app())

データベースの内容(testテーブル)ができたことを確認してください!

続いて、データベースのMigrate(差分保存)初期設定を行っておきます。
Pythonインタプリンタから出て、下記コマンドを実行します。

set FLASK_APP=run.py
flask db init

※Migrateについての詳細は、Flask-migrateをご覧ください。

それではWebサイトにアクセスします。
まずはトップページ(/flask_db/)を確認します。

まだデータが入っていないため、テーブルは空です。
※このトップページはphpMyAdmin(flask_dbのtestテーブル内)と同じ表示になります。

では、データを入れていきましょう。
データ追加は、/insert/<入れたい値>にアクセスしてください。
テストでは100, 200, 300, 400, 5000の5つの数値をそれぞれ入力しました。

トップページ(/flask_db/)を確認すると、下記のようにデータベースに行が追加されました。

続いて、特定のidの値(data)を更新していきます。
更新は、/update/<id>/<変更したい値>にアクセスしてください。
テストでは/update/3/0, /update/4/100にアクセスしました。

トップページ(/flask_db/)を確認すると、下記のようにデータベースのid3および4の値が変更されました。

最後に、特定のidを削除します。
削除は、/delete/<id>にアクセスしてください。
テストでは/delete/3にアクセスしました。

トップページ(/flask_db/)を確認すると、下記のようにデータベースのid3が削除されました。

これにてテストアプリのテスト起動は終了しました。

締めに、アプリの解説を行います。
アプリの構造は以下の通りです。
HTTP接続からNginx、NginxからNginx Unit、Nginx Unit上でvenvを使ってアプリを起動し、MariaDBにアクセスする方法を取っています。

ファイルの内容については以下の通りです。
app.pyがアプリ本体です。conf.jsonに指定したrun.pyは起動用のアプリであって本体ではありません。

このような構成にすることで、ファイルごとに役割分担を明確にしています。かつ、Nginx Unit以外のAPサーバー(例:uWSGI)などでも動かせるような構成となっています。

おわりに

PythonでMariaDB(MySQL)へ接続できるアプリを触ってみようということで、今回いろいろと設定を行いました。
このアプリをWebサーバー上で起動できれば、その他の応用アプリも起動が可能になります。

ただ、当アプリはapp.pyにルーティングや表示のコードが記載されているため、このまま記載を続けるとapp.pyのコード量が肥大化します。
次回はファイルごとに役割分担を明確にしたFlaskアプリを作成するために、Flaskの機能であるBlueprintをこのアプリに導入していきます。

この記事は、VPSで作るPythonでのWebアプリ運用環境の連載記事です。
次は、12. Python(Flask)でMariaDB(MySQL)へ接続できるアプリをもっと読みやすく改良してみようです。

(VPSでつくる) WinSCPでFTP接続

連載第十回目です。

これまではVPSサーバーに対し、viエディタで色々なファイルを編集してきました。
ただ、今後はFlaskアプリなど、かなり作り込んだサービスの導入テストを行いますので、一ファイルずつviエディタで書き込んでると日が暮れます。

そのため、FTP通信を使って、VPSサーバーにファイルを転送してしまいましょう。

この記事は、VPSで作るPythonでのWebアプリ運用環境の連載記事です。
その他については上記ページをお読みください。

1. ユーザーの作成

FTPユーザー(ftp-user)を作ります。他の名前でも構いません。
パスワードも設定しておきましょう。

useradd ftp-user
passwd ftp-user

あとは、ユーザーが操作できる最上位のディレクトリのパーミッションを0777に設定しておきます。

chmod 777 /usr/share/nginx

2. FTPのインストール

FTPパッケージのインストールを行います。

yum -y install vsftpd

3. FTPの設定

FTPの設定ファイル(/etc/vsftpd/vsftpd.conf)を2通り変更します。
(1)内容の追記

# userlist_fileで指定指定したユーザを接続可能にする
userlist_enable=YES

# アクセスファイル(/etc/hosts.allow, /etc/hosts.deny)をアクセス制御に利用しない
tcp_wrappers=NO

# ドットから始まるファイルを含めた一覧を返す
force_dot_files=YES

# ファイル(またはディレクトリ)のタイムスタンプの表示をローカルタイムで表示する
use_localtime=YES

# ユーザー毎の設定ファイルの場所を指定する。
user_config_dir=/etc/vsftpd/user_conf

# chroot設定で許可する
allow_writeable_chroot=YES

# chroot設定で許可するを設定すると、下記エラーが防止できます。
OOPS: vsftpd: refusing to run with writable root inside chroot()

(2)コメントアウトから有効にする

# ルート設定有効ユーザー
chroot_local_user=NO
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd/chroot_list

意外と追記内容(赤枠)が多いですが、問題ありません。

ルート設定ユーザーリストファイル(/etc/vsftpd/chroot_list)を下記の通りにしてください。

ftp-user

※改行で新規ユーザーを追加可能です。

ユーザー設定用ディレクトリとファイルを作ります。

mkdir /etc/vsftpd/user_conf
vi /etc/vsftpd/user_conf/ftp-user

ユーザー設定用ファイル(/etc/vsftpd/user_conf/ftp-user)を下記の通りにしてください。

local_root=/usr/share/nginx

※コピペすると先頭数文字が切れる場合があるので注意ください。

いつもの通りサービスのスタートと再起動可能設定を行います。

systemctl enable vsftpd
systemctl start vsftpd

4. FTPのテスト

仕様ソフトはWinSCPを例にしていますが、他ソフトでも構いません。

下記の通り設定します。
IPアドレスは環境に応じて変更してください。

パッシブモードOFFだと20番接続、パッシブモードONだと21番接続にします。

※もし接続できて、ディレクトリが表示されない場合はONにしてください。

接続すると下記のような表示となります。
上位のディレクトリに移動する(赤枠)をクリックしても、設定したディレクトリより上には行けないことを確認できます。

上位のディレクトリに行けない設定にするのには、セキュリティの観点から言って正解です。
FTPユーザーはファイルを送受信するだけの役割であり、サーバーの中身は見る必要はありません。

おつかれさまでした。

おわりに

今回でFTPでのファイル送受信が可能となり、前回行ったデータベースと合わせて、本格的なアプリを構築する準備ができました。
次回は、Pythonの軽量なフレームワークFlaskで本格的なアプリを構築していきます!

ちなみに、FTPは平文でファイルをやり取りするためセキュリティ面に脆弱性があります。
よりセキュリティを高めるなら、SFTPなどを利用することをお勧めします。

この記事は、VPSで作るPythonでのWebアプリ運用環境の連載記事です。
次は、11. PythonでMariaDB(MySQL)へ接続できるアプリを触ってみようです。

(VPSでつくる) phpMyAdminインストール

連載第九回目です。

GUI上でMariaDB(MySQL)を触れるようにするために、phpMyAdminをインストールしましょう。

この記事は、VPSで作るPythonでのWebアプリ運用環境の連載記事です。
その他については上記ページをお読みください。

1. phpMyAdminインストール

前回の記事で指定したremiレポジトリを使っていきます。

yum -y --enablerepo=remi-php71 install phpMyAdmin

※もしPHPのバージョンを変更された場合は、php71を編集してください。

環境設定保存用のデータベースを作成しておきます。

vi /usr/share/phpMyAdmin/sql/create_tables.sql

コードを下記から、

-- (activate this statement if necessary)
-- GRANT SELECT, INSERT, DELETE, UPDATE, ALTER ON `phpmyadmin`.* TO
--    'pma'@localhost;

下記の通り変更します。

-- (activate this statement if necessary)
GRANT SELECT, INSERT, DELETE, UPDATE, ALTER ON `phpmyadmin`.* TO
  'root'@localhost;

※今回はrootユーザーをすでに作成しているので、このようにしています。

MariaDBにログインして、クエリを実行します。

mysql -u root -p
source /usr/share/phpMyAdmin/sql/create_tables.sql

権限関係のメモリリフレッシュを行います。

FLUSH PRIVILEGES;

Control+ZコマンドでMariaDBから抜けることができます。

2. Nginxの環境設定

PHP-FPMとNginxを接続するために、TCPとUnix Socketの2通りの方法があります。(参考ページ)
今回はUnix Socketを利用します。

まずは、PHP-FPMファイルの設定(/etc/php-fpm.d/www.conf)を変更します。

listen = /var/run/php-fpm/php-fpm.sock
listen.owner = nginx
listen.group = nginx
listen.mode = 0666

変更イメージは以下の通りです。

PHPの設定ファイル(/etc/php.ini)を変更します。

session.save_path = "/var/lib/php/session"

このセッションにNginxがアクセスできるようにしておきます。

sudo chown -R root.nginx /var/lib/php/session

最後に、Nginxの設定を変更します。
環境設定ファイル(/etc/nginx/conf.d/default.conf)を2点編集します。
(1)server{}内のlocation ~ \.php$内を変更します。

    location ~ \.php$ {
                fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
    }

(2)server{}内にlocation /phpMyAdminを追記します。

    location /phpMyAdmin {
        alias /usr/share/phpMyAdmin/;
        try_files $uri $uri/ /index.php;

        location ~ ^/phpMyAdmin/(.+\.php)$ {
            alias /usr/share/phpMyAdmin;
            fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
            fastcgi_param SCRIPT_FILENAME /usr/share/phpMyAdmin/$1;
            include fastcgi_params;
            fastcgi_intercept_errors on;
        }
    }

location ~ ^/phpMyAdmin/(.+\.php)$内にallow XXX.XXX.XXX.XXX(IP); deny all;をこの中に追記すると、指定IP以外のアクセスを拒否することができます。

変更イメージとしては以下の通りです。

sudo systemctl restart php-fpm
sudo systemctl reload nginx

3. 動作確認

下記のように表示されればOKです。

rootユーザーでのログインが可能かどうか確認ください。

設定を変更した場合は、php-fpm.sockを削除して、php-fpmなどを再起動します。

rm -f /var/run/php-fpm/php-fpm.sock

おわりに

phpMyAdminがインストールできました。
これにてデータベースの導入は完了です!

次は、FTPでファイルを送受信できるようにします。
これまではviエディタで色々と記載していましたが、この方法だと限界があるので変更します。

この記事は、VPSで作るPythonでのWebアプリ運用環境の連載記事です。
次は、10. WinSCPでFTP接続です。