Ubuntu18.04 + pyenv + pipenv + Django + Apache2 なデプロイ その2

#MySQL5.7のインストールと設定
以下のコマンドから実行する．

```
ttimes@xxx-xxx-xxxxxx:~$ sudo apt install python-dev python3-dev libmysqlclient-dev default-libmysqlclient-dev mysql-server
ttimes@xxx-xxx-xxxxxx:~$ sudo mysql_secure_installation
```
セキュアインスタレーションを実行すると，パスワードのセキュリティレベルを設定し，パスワードを設定することになります．
普段からパスワード生成器を利用されている方は`2`にするといいと思います．
その後，①匿名ユーザを禁止するか　②リモートからのrootログインを禁止するか　③テストデータベースを削除しておくか　④ここまでの設定をすぐに反映するか　を聞いてきます，基本的に全て`Yes`でいいと思っています．

次はデータベース`ttimesdb`とユーザー`ttimes`に対する権限付与です．成功すれば，変更を反映するためにリロードしましょう．

```
ttimes@xxx-xxx-xxxxx:~/app$ sudo mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 5.7.36-0ubuntu0.18.04.1 (Ubuntu)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>  CREATE DATABASE ttimesdb CHARACTER SET utf8mb4;
Query OK, 1 row affected (0.00 sec)
mysql> CREATE DATABASE ttimesdb CHARACTER SET utf8mb4;
Query OK, 1 row affected (0.00 sec)
mysql> CREATE USER 'ttimes'@'localhost' IDENTIFIED BY '~~~~~~~~~~';
Query OK, 0 rows affected (0.00 sec)
mysql> GRANT ALL PRIVILEGES ON * . * TO 'ttimes'@'localhost';
Query OK, 0 rows affected (0.00 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.02 sec)
mysql> exit
Bye
```
これでデータベースが完成しました．あとはDjangoの設定ファイルに内容を書き込んで，Djangoから触れるようにMySQL用のモジュールを入れるだけです．また，`CREATE USER`で作成したユーザーにDjangoからログインするので，その際のパスワードは必ず控えておきましょう．

#`mysqlclient`のインストールに失敗する
`python3 -m pipenv install mysqlclient` が失敗します．`適切なバージョンが見つかりません`みたいな意味わからんエラーとともに．これがめちゃくちゃめんどくさかった．
環境ごとに，ディストリビューションごとに違うと思うので一概には言えませんが，僕は`bash_profile`に下記を追記して助かりました．これが本質的な解決になってるのかは知りません．

```
ttimes@xxx-xxx-xxxxx:~$ sudo nano ~/.bash_profile
```

```
# set env in order to install mysqlclient
export PATH="/usr/local/opt/openssl@1.1/bin:$PATH"
export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib"
export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include"
```
変えたら読み込むクセをつける

```
ttimes@xxx-xxx-xxxxx:~$ source ~/.bash_profile
```
#`migrate`に失敗するようなら以下を試してみる．
他のライブラリをインストールする．こんなにいっぱいいるのか．

```
(TTimes) ttimes@xxx-xxx-xxxxx:~/app/TTimes$ pipenv install mysql-connector-python django-mysql
```

#`migrate`できたら
※ [ここ](https://medium.com/@kjmczk/django-multiple-settings-2a4c15c7c7b0)を参考に`settings.py`を`production.py`と`local.py`に分けてます．

```production.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'ttimesdb',
        'USER': 'ttimes',
        'PASSWORD': '**********',
        'HOST': 'localhost',
        'PORT': '3306',
    }
}
```



#マイグレーション
またエラーした．マイグレーションでグダっていたので，データベース`ttimesdb`を削除した上で，再度作成．

```bash
ttimes@xxx-xxx-xxxxx:~$ mysql -u ttimes -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 18
Server version: 5.7.36-0ubuntu0.18.04.1 (Ubuntu)
```

こんな感じで削除して，こんな感じで再度作成する．

```mysql
mysql> use ttimesdb
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+-------------------------------------------+
| Tables_in_ttimesdb                        |
+-------------------------------------------+
| TTimes_attendancemodel                    |
| TTimes_childcompanymodel                  |
| TTimes_childcompanymodel_groups           |
| TTimes_childcompanymodel_user_permissions |
| TTimes_parentcompanymodel                 |
| TTimes_staffmodel                         |
| auth_group                                |
| auth_group_permissions                    |
| auth_permission                           |
| django_content_type                       |
| django_migrations                         |
+-------------------------------------------+
11 rows in set (0.00 sec)

mysql> drop database ttimesdb;
Query OK, 11 rows affected (0.02 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)
mysql> CREATE DATABASE ttimesdb CHARACTER SET utf8mb4;
Query OK, 1 row affected (0.00 sec)
mysql> exit;
Bye
```

#`makemigrate`に失敗する
もうここまで来たら驚かない．失敗するのであるから，対応するというわけである．
実はローカルで作業してきた段階から．二つのPCを行き来しながら開発していたせいか，マイグレーションファイルの整合性が取れなくなっており，ロールバックできない状態と化していた．
ということで，まだ何一つデータベースに登録されていない僕に何も怖いものは一つもない，ガンガン`migrations`ファイルを物理消去していくのみ．
`~/app/TTimes/.venv/lib/python3.8/site-packages/django/contrib`の中の`admin`, `auth`, `sessions`, `sites`の中にも`migrations`ディレクトリがあるので，マイグレーションファイルを消してしまっていい．ただし`__init__.py`は消さずに残しておくこと．

そして晴れて成功するのである．

```
(TTimes) ttimes@xxx-xxx-xxxxx:~/app/TTimes$ python3 manage.py makemigrations
Migrations for 'TTimes':
  TTimes/migrations/0001_initial.py
    - Create model ParentCompanyModel
    - Create model ChildCompanyModel
    - Create model StaffModel
    - Create model AttendanceModel
(TTimes) ttimes@xxx-xxx-xxxxx:~/app/TTimes$ python3 manage.py migrate
Operations to perform:
  Apply all migrations: TTimes, admin, auth, contenttypes, sessions
Running migrations:
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying sessions.0001_initial... OK
(TTimes) xxx-xxx-xxxxx:~/app/TTimes$ python3 manage.py createsuperuser
会社名: admin
Email: xxxx@yyy.com
Password: 
Password (again): 
Superuser created successfully.
```



#Apache2のインストールと設定

```
ttimes@xxx-xxx-xxxxx:~$ sudo apt install -y apache2 apache2-dev libapache2-mod-wsgi-py3
```
##`mod_wsgi`のインストールと設定
きちんと仮想環境に対してインストールすること．その後，`django.conf`設定のための情報収集を行う．

```
ttimes@xxx-xxx-xxxxx:~/app/TTimes$ python3 -m pipenv shell
(TTimes) ttimes@xxx-xxx-xxxxx:~/app/TTimes$ pipenv install mod_wsgi
(TTimes) ttimes@xxx-xxx-xxxxx:~/app/TTimes$ mod_wsgi-express module-config
LoadModule wsgi_module "/home/ttimes/app/TTimes/.venv/lib/python3.8/site-packages/mod_wsgi/server/mod_wsgi-py38.cpython-38-x86_64-linux-gnu.so"
WSGIPythonHome "/home/ttimes/app/TTimes/.venv"
```
で，ここまできたら一度アクセスしてみましょう．DNSの向きさえ設定できていれば，Apache2のデフォルト画面が表示されるはずです．
ここで表示されなかったらファイアウォールやポート開放が完了していないことが多いです．

##ポート周りの確認
Apacheはport80を使います．

```
ttimes@xxx-xxx-xxxxx:~/app/TTimes$ sudo lsof -i:80
COMMAND  PID     USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
apache2 5268     root    3u  IPv4 177716      0t0  TCP *:http (LISTEN)
apache2 5270 www-data    3u  IPv4 177716      0t0  TCP *:http (LISTEN)
apache2 5271 www-data    3u  IPv4 177716      0t0  TCP *:http (LISTEN)
```
動いてるっぽいですね．
次に，ファイアウォール等が80番portでの外部アクセスを拒否していないかを確認します．

```
ttimes@xxx-xxx-xxxxx:~/app/TTimes$ nmap localhost

Starting Nmap 7.60 ( https://nmap.org ) at 2021-11-05 18:18 JST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.0000020s latency).
Other addresses for localhost (not scanned): ::1
Not shown: 998 closed ports
PORT     STATE SERVICE
80/tcp   open  http
3306/tcp open  mysql

Nmap done: 1 IP address (1 host up) scanned in 1.67 seconds
```
これもOKです．
あとは，`iptables`なるライブラリが動いていることが原因である場合もあるので，[ここ](https://www.icoro.com/201201276505)も参考にしてみてください．
SSHでVPSサーバーに接続する際のポートをその1で変更している場合は，リンク先サイトの30000の部分の書き換えが必要なので，注意してください”

**まあ，僕は上のどれを試してもうまくいかなかったんですけどね．**
原因はさくらVPSのパケットフィルタとかいう~~クソ~~機能でした．冗談抜きで3時間くらい無駄にしました．[ここ](https://megu-tech.hatenablog.com/entry/2019/07/26/101018)を参考にport80と443を許可して解決しました．

#mod-wsgiの設定
ここが正直一番難しいしややこしい．正直分かってない．まずは

- TTimesディレクトリ(manage.pyのところ)のパス
- wsgi.pyまでのパス
- staticフォルダがあればそこまでのパス(collectstaticで生成されたパス)

あたりが大事になるので，確認しておきましょう．そしてそいつらをもとに，Apacheでwsgiする（？）ための設定ファイルを作成します．


```
ttimes@xxx-xxx-xxxxx:~/app/TTimes$ sudo nano /etc/apache2/sites-available/django.conf
```

```django.conf
LoadModule wsgi_module /home/ttimes/app/TTimes/.venv/lib/python3.9/site-packages/mod_wsgi/server/mod_wsgi-py39.cpython-39-x86_64-linux-gnu.so
WSGIPythonHome /home/ttimes/app/TTimes/.venv
WSGIPythonPath /home/ttimes/app/TTimes:/home/ttimes/app/TTimes/.venv/lib/python3.9/site-packages
WSGIDaemonProcess /home/ttimes/app/TTimes python-home=/home/ttimes/app/TTimes/.venv python-path=/home/ttimes/app/TTimes/.venv/lib/python3.9/site-packages
WSGIScriptAlias / /home/ttimes/app/TTimes/config/wsgi.py

<VirtualHost *:80>
  <Directory /home/ttimes/app/TTimes/config>
    <Files wsgi.py>
      Require all granted
    </Files>
  </Directory>

  Alias /static/ /home/ttimes/app/TTimes/static/
  <Directory /home/ttimes/app/TTimes/static>
    Require all granted
  </Directory>
</VirtualHost>
```



:::note
雛形としてはこんな感じ．VirtualHostの設定は今後`https`化するときに設定することになるので，今のうちにこうしておいてもいいでしょう．
いらない！という場合は，VirtualHostの開始タグと終了タグを削除して，WSGIDaemonProcess，WSGIDaemonProcessインテンドを一段下げればいいです．
※Qiitaの注釈の仕様で<>で囲った部分が見えなくなるようです．開始タグの直後に半角スペースを入れているので，コピペの際は注意してください

LoadModule wsgi_module 【仮想環境内で`mod_wsgi-express module-config`で出たLoadModule wsgi_moduleの内容】

WSGIPythonHome 【仮想環境内でmod_wsgi-express module-configで出たWSGIPythonHomeの内容】
WSGIPythonPath 【TTimesまでのパス(manage.pyがあるところ)】:【仮想環境のsite-packagesまでのパス】

< VirtualHost *:80 >
  WSGIDaemonProcess 【settings.pyが入っているのディレクトリの名前】 python-home=【仮想環境までのパス】 python-path=【仮想環境のsite-packagesまでのパス】
  WSGIScriptAlias / 【wsgi.pyまでのパス(wsgi.py含む)】

  < Directory 【wsgi.pyまでのパス(wsgi.py含まない】】>
    < Files wsgi.py>
      Require all granted
    < /Files>
  < /Directory>

  Alias /static/ 【collectstaticで生成されたstaticフォルダ(manage.pyと同階層のstatic)までのパス】
  < Directory 【collectstaticで生成されたstaticフォルダ(manage.pyと同階層のstatic)までのパス】>
    Require all granted
  < /Directory>
< /VirtualHost>

:::
設定を保存できたら次のコマンドで変更を反映します．

```
ttimes@xxx-xxx-xxxxxx:~$ sudo a2dissite 000-default
Site 000-default disabled.
To activate the new configuration, you need to run:
  systemctl reload apache2
ttimes@xxx-xxx-xxxxxx:~$ sudo a2ensite django
Enabling site django.
To activate the new configuration, you need to run:
  systemctl reload apache2
ttimes@xxx-xxx-xxxxxx:~$ sudo systemctl restart apache2
ttimes@xxx-xxx-xxxxxx:~$ sudo systemctl enable apache2
Synchronizing state of apache2.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable apache2
```

2dissiteは **a** pache **2** の **dis** eble **site** で，無効化の意味，
2ensiteは **a** pache **2** の **en** able **site** で，有効化の意味じゃないか，という記事をどこかで読んで覚えられました．





これで終わりなのだろうか？


### [その０](https://qiita.com/_branch_/items/e9c22d9e51ed3ed8d0bb) リモートの本番環境にSSHでアクセスする
### [その１](https://qiita.com/_branch_/items/633055f69503aec96156) pythonの環境を整える（pyenv, pipenv）
###[その２](https://qiita.com/_branch_/items/7c225cbc277d53b71f0e) のこり