【Raspberry Pi】Apache+WSGI+Python Flaskを使ってhttpsでWebアプリケーションを公開する

# 概要
Raspberry PiでPythonのFlaskフレームワークを用いたWebアプリを公開する。
その際、WSGIを用いてApacheと連携させることでSSLにも対応させる。

# はじめに
この記事は、Raspberry Piの初期設定、ドメインの取得、Apache2の導入、ポート開放、SSL証明書の取得等が済んでいる前提の記事です。
お済みでない方は、先にそちらの設定を行うことを推奨します。

- [raspberry piでお手軽自家サーバー webサーバー編 - Qiita](https://qiita.com/picker/items/0466c55f9a03ebb0bd90)
- [ラズパイwebサーバをhttpsに対応させた - Qiita](https://qiita.com/HO_Pollyanna/items/aee45b25e2318d39157b)

# 使用環境
- Raspbian 10.7
- Apache 2.4.38
- Python 3.7.3
- Flask 1.0.2

## 環境構築
次のコマンドでmod_wsgiをインストールします。
Pythonのバージョンが2以下の方はインストールするものが違うので注意してください。

```console
$ sudo apt-get install libapache2-mod-wsgi-py3
```
Pythonのバージョンが2以下の場合

```console
$ sudo apt-get install libapache2-mod-wsgi
```
PythonにFlaskフレームワークがインストールされていない方はインストールします。

```console
$ sudo pip3 install Flask
```

# Flaskアプリケーションの用意
## ファイル構成
Flaskアプリケーションのファイル構成は以下のようにしました。

```
└ var/
  └ www/
    └ flask/
      ├ app.py
      ├ app.wsgi
      └ templates/
        └ test.html
```

## サンプルの作成

```python:app.py
#!/usr/bin/ python3
# -*- coding: utf-8 -*-

# Flaskフレームワークのインポート
from flask import Flask
# テンプレートエンジンのインポート
from flask import render_template

# Flaskインスタンスの作成
app = Flask(__name__)

# ルーティング
@app.route('/')
def index():
    return render_template('test.html')

# アプリ起動時の実行内容
if __name__ == '__main__':
    app.run()
```

```python:app.wsgi
#!/usr/bin/ python3
# -*- coding:utf-8 -*-

import sys

# パスの指定
sys.path.insert(0, '/var/www/flask')
from app import app
application = app
```

```html:test.html
<html>
  <body>
    <h1>Hello Flask!</h1>
  </body>
</html>
```

## サンプルの動作確認
コマンドを入力してアプリが正常に動くか確認します

```
$ python3 /var/www/flask/app.py
```
最後に`Running on http://127.0.0.1:<ポート番号>/ (Press CTRL+C to quit)`と出れば成功です。
そのまま別のターミナルを開き、以下のコマンドを入力して正常にhtmlが取得できるか確認します。

```
$ curl localhost:<ポート番号>
```
test.htmlの内容が取得できれば成功です。CTRL+Cを押して一度アプリを終了します。

# Apache2の設定
/etc/apache2/sites-available/に次のファイルを作成します。
root権限で行ってください。

```config:flask_wsgi.conf
# コードの簡単化のためIfModuleは使わない

# http通信をhttps通信にリダイレクトする
<VirtualHost *:80>
	RewriteEngine On
	RewriteCond %{HTTPS} off
	RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,END]
</VirtualHost>

# https通信の設定
<VirtualHost *:443>
	ServerName <サーバの名前>
	ServerAdmin <管理者のメールアドレス>

	DocumentRoot /var/www/flask

	WSGIDaemonProcess app user=<ユーザー名> group=<ユーザーグループ> threads=5
	WSGIScriptAlias / /var/www/flask/app.wsgi

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

	SSLEngine on

	SSLCertificateFile <SSL証明書 fullchain.pemのパス>
	SSLCertificateKeyFile <SSL証明書 prevkey.pemのパス>

	<FilesMatch "\.(cgi|shtml|phtml|php)$">
		SSLOptions +StdEnvVars
	</FilesMatch>
	<Directory /usr/lib/cgi-bin>
		SSLOptions +StdEnvVars
	</Directory>

	<Directory /var/www/flask/>
		WSGIProcessGroup app
		WSGIApplicationGroup %{GLOBAL}
		WSGIScriptReloading On

		Require all granted
		Options FollowSymLinks
		AllowOverride All
	</Directory>
</VirtualHost>
```
次に、以下のコマンドを入力してコンフィグを有効にします。

```console
$ sudo a2ensite flask_wsgi
```
/etc/apache2/sites-enabledを確認して他のコンフィグファイル(000-default.conf等)が有効になっていないか確認します。サーバー名が明確に分かれていない場合、競合する可能性があるので以下のコマンドで無効にします。

```console
$ sudo a2dissite <他のコンフィグファイル>
```
以上ができたら、Apacheを再起動します。

```console
$ sudo service apache2 restart
```
エラーなく再起動できたら、ブラウザを開き確認します。
test.htmlの内容がブラウザで正常に取得出来たら成功です。お疲れ様でした。
# 参考
- [Apache上でFlaskを動かすまで（Apache2+wsgi+Flask）](http://www.wanna-continue.com/entry/apache2%2Bwsgi%2Bflask)