WSL2を使ってWindows11からDjangoをデプロイしよう

**WSL2を使ってWindows11からDjangoをデプロイしよう**

[前回の記事](https://asameshicode.com/ubuntu-windows11-wsl2/)では、windowsにWSL2（Windows Subsystem for Linux）をインストールする方法を紹介しました。

では今日はWSL2を使ってDjangoをデプロイする方法を説明していきます。[UbuntuサーバーからDjangoをデプロイする方法はこちらの記事](https://asameshicode.com/how-to-deploy-django-with-ubuntu/)を参考にしてください。

※この記事には課題が残っています。
**課題**
※WindowsからDjangoはデプロイできますが、Hyper-VでNATネットワークをUbuntuにアサインしているためにデフォルトでは、Windowsマシン以外からDjangoアプリにアクセスができません。詳しい対応策はMicrosoftの[WSLのGitHub Issue](https://github.com/microsoft/WSL/issues/4150#issuecomment-504209723)を見てください。
記事の最後で詳しく説明しています。


## **Ubuntuサーバーの起動**

では[前回の記事](https://asameshicode.com/ubuntu-windows11-wsl2/)でインストールしたUbuntuサーバーを起動します。

![alt_text](https://i0.wp.com/asameshicode.com/wp-content/uploads/2023/01/image-39.png?w=760&ssl=1 "image_tooltip")



## **Ubutnuサーバーの環境の確認**


※ﾋﾄｺﾄ
これから作業するにあたり、Linuxのコマンドに慣れていない人は簡単な早見表などを見ておくとよいです。

例えばCtl+Lで入力画面が一番上に来るのでキレイに見えます。

他に入力している途中でCtl+iを押すと推測したテキストが表示されます。長いファイル名の場合は最初の何文字か書いてCtrl+iで記入を終わられるのに便利です。

また、過去に実行したコマンドを見たい場合は上矢印で見ることができます。

----

UbuntuサーバーのIPアドレスを見てみます。


``` bash
ip addr
#結果
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
   inet 127.0.0.1/8 scope host lo
      valid_lft forever preferred_lft forever
   inet6 ::1/128 scope host
      valid_lft forever preferred_lft forever
2: bond0: <BROADCAST,MULTICAST,MASTER> mtu 1500 qdisc noop state DOWN group default qlen 1000
   link/ether 02:37:69:da:93:42 brd ff:ff:ff:ff:ff:ff
3: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
   link/ether 82:6e:ca:74:c1:c6 brd ff:ff:ff:ff:ff:ff
4: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
   link/ipip 0.0.0.0 brd 0.0.0.0
5: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
   link/sit 0.0.0.0 brd 0.0.0.0
6: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
   link/ether 00:15:5d:37:f0:07 brd ff:ff:ff:ff:ff:ff
   inet 172.18.173.157/20 brd 172.18.175.255 scope global eth0
      valid_lft forever preferred_lft forever
   inet6 fe80::215:5dff:fe37:f007/64 scope link
      valid_lft forever preferred_lft forever
```


ip addrのコマンドで分かるようにeth0のインターフェースに172.18.173.157のIPアドレスがあることが分かります。

WindowsのホストマシンのコマンドプロンプトからPingをかけてみました。


``` bash
#コマンドプロンプトから
ping 172.18.173.157
```


リスポンスがあったので、ここからデプロイできそうです。



![alt_text](https://i0.wp.com/asameshicode.com/wp-content/uploads/2023/01/image-40.png?w=514&ssl=1 "image_tooltip")


次にPythonが入っていることを確認します。


``` bash
python3 --version
#結果
Python 3.10.6
#注意
pythonを実行する際はpythonではなく、python3で入力します。
```


次にUbuntuソフトウェア、パッケージのアップデートをします。


``` bash
sudo apt update
```


Ubutnuユーザーをwww-dataグループに追加します。


``` bash
sudo adduser dan www-data
#danはUbuntuユーザー名
#結果
Adding user `dan' to group `www-data' ...
Adding user dan to group www-data
Done.
```


※これからの作業の注意点

Ubuntuユーザーを作成した際にsudoの権限がすでについています。rootに切り替えて作業せず、そのままsudo権限のあるユーザーのまま作業を行いましょう。理由はnginxやファイルの実行の際に権限が与えられていないとエラーが発生するからです。


## **Djangoデプロイに使うライブラリをUbuntuにインストール**

下記のコマンドでUbuntuサーバーにグローバルにインストールしていきます。


```
sudo apt install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx curl virtualenv

```



* python3-pip →Pythonのパッケージマネージャー
* python3-dev →スタティックライブラリ、デベロップメントツール
* libpq-dev →PostgreSQLで使います
* postgresql →データベースでPostgreSQLを使用する場合
* postgresql-contrib →データベースでPostgreSQLを使用する場合
* nginx →ウェブサーバー（Apacheよりもnginxをお勧めします）
* curl　→URLのテストツール
* virtualenv　→仮想環境の作成に使う（他のアプリのバージョンと干渉させないため）


## **PostgreSQLのデータベースを作成**

ではこちらの[参考Djangoのプロジェクト](https://github.com/TraitOtaku/JS-Hiroba-Backend)を使用してデプロイさせていくことにします。もしPostgreSQLを使ったことがない人は1時間くらいかけてデータベースのSQLコマンドを練習、理解してみてください。今後データベースのデータの修正やバックアップを取るためにコマンドラインを使っていくことになるので慣れておくとよいです。

postgresをインストールしたときに自動でpostgres というアドミン権限のユーザーが作成されます。

この権限を使って新しいデータベースとユーザーを作成します。

まずは、PostgreSQLのステータスを確認します。


``` bash
service postgresql status
#結果
14/main (port 5432): down
#ダウンの場合
#PostgreSQLを起動
sudo service postgresql start
#ステータスがonlineになっていればOK
```


PostgreSQLが起動できたらPostgresのユーザーに切り替えます。


``` bash
#Ubuntuのユーザーからpostgresに変更
sudo -u postgres psql
```


これでユーザーが切り替わりSQLの入力モードになったことが分かります。





![alt_text](https://i0.wp.com/asameshicode.com/wp-content/uploads/2023/01/image-41.png?w=630&ssl=1 "image_tooltip")


では、Djangoのsettings.pyに合わせたデータベースを作成していきます。

セミコロンを忘れずに！


``` sql
CREATE DATABASE asameshidb;　asameshidbはDB名
#結果
CREATE DATABASE
\l
                             List of databases
   Name    |  Owner   | Encoding | Collate |  Ctype  |   Access privileges
------------+----------+----------+---------+---------+-----------------------
asameshidb | postgres | UTF8     | C.UTF-8 | C.UTF-8 |
postgres   | postgres | UTF8     | C.UTF-8 | C.UTF-8 |
template0  | postgres | UTF8     | C.UTF-8 | C.UTF-8 | =c/postgres          +
           |          |          |         |         | postgres=CTc/postgres
template1  | postgres | UTF8     | C.UTF-8 | C.UTF-8 | =c/postgres          +
           |          |          |         |         | postgres=CTc/postgres
(4 rows)
```


\lのコマンドでDBの一覧が表示されます。

これでpostgresユーザーがオーナーのデータベースが出来ました。


## **PostgreSQLのコンフィグレーション**

もしデータベースのオーナーをpostgres以外に設定したい場合は新しいPosgreSQLのユーザーを作成して所有権を移動させてください。


``` bash
CREATE USER djangouser WITH PASSWORD 'django1234';
#結果
CREATE ROLE
#passwordはもっと複雑なものにしてください。
```


ではpostgresの接続をスムースにするためにコネクションパラメーターを変えます。

まずはエンコーディングをutf-8に変えます。


``` bash
ALTER ROLE djangouser SET default_transaction_isolation TO 'read committed';
#結果
ALTER ROLE
```


Postgresのタイムゾーンを日本時間に変えます。

Djangoのタイムゾーンがデフォルト（初期設定）でUTCにセットさせているのでそれを変更していない人はSettnigs.pyから変更しておきましょう。


``` bash
ALTER ROLE djangouser SET timezone TO 'Asia/Tokyo';
#結果
ALTER ROLE
#タイムゾーンの一覧を確認したい人は下記のコマンド
SELECT * FROM pg_timezone_names;
```


次に、作成したユーザーにdb（データベース）のアドミン権限をつけます。


``` bash
GRANT ALL PRIVILEGES ON DATABASE asameshidb TO djangouser;
#結果
GRANT
```


postgresは一旦完了なのでquitと入力してでpostgresから抜け出しましょう。

もしくはCtl＋Zでも抜けられます。


## **Django用に仮想環境を作成**

pythonではいくつか仮想環境のライブラリがありますが今回はvirtualenvを使用します。

仮想環境を使ったことがない人は詳しく理解しておいた方が良いですね。

簡単に説明すると同じサーバーで違うバージョンのライブラリを使いたいとき（例えばDjangoの3.0と4.0)に仮想環境をアクティベートして同じマシンでも同時に使用できる様になります。

また、複数人で仕事をするときもバージョンを統一してするために使います。

**Pipの準備**

pipはpythonパッケージマネージャーでpythonのライブラリをインストールする際に使用しますね。

-HのフラグはsudoのコマンドでユーザーのhomeディレクトリではなくrootのHOMEディレクトリにインストールするように指示します。

まずはpipを最新のものにします。


``` bash
sudo -H pip3 install --upgrade pip
```


virtualenvはすでにインストールしているのでこれを使って仮想環境を作成します。（似たものでvenvがあるのでそれでもOKです）

まずは、Djangoのプロジェクトを置く場所を決めましょう。apacheを使ってきた人は/var/wwwのディレクトリに慣れているかもしれません。もちろんそれでもOKです。

今回はNginxと、特定のユーザーを使ってデプロイするので/home/user (※userはUbuntuのユーザー名）にDjangoのプロジェクトを置くようにしましょう。

では、ユーザーのディレクトリに移動します。


``` bash
cd /home/asameshi
#みなさんの場合は自分のユーザー名の場所
cd /home
ls
#lsで存在するフォルダーが見れるのでそれで
Ctl +　i　で推測入力することも可能です。
pwd
#現在のファイルパスが表示されます。
```



## **Djangoプロジェクトの作成**

では、自分で作成したDjangoのプロジェクトを/home/userに置きます。

もしWindowsのファイルエクスプローラーでファイルをドラッグ＆ドロップしたい場合は下記のファイルパスを参考にしてください。

\wsl.localhost\Ubuntu\home\ユーザー名


![alt_text](https://i0.wp.com/asameshicode.com/wp-content/uploads/2023/01/image-42.png?resize=768%2C467&ssl=1 "image_tooltip")


ファイルエクスプローラーを開くとLinuxのディレクトリがあるのでそこからアクセスも可能です。

一番のおすすめのやり方はGitとGitHubを使った方法です。

その場合は下記のコマンドを参考にしてください。


```bash
#Gitがインストールされているか確認
git --version
#結果
git version 2.34.1
#正しいパスにいることを確認
pwd
#GitHubリポからコードをクローンする
git clone git@github.com:TraitOtaku/JS-Hiroba-Backend.git
```


ここで、SSHキーがGitHubに登録されていないとセキュリティのエラーでリポのクローンができないので、[こちらの記事](https://asameshicode.com/how-to-push-repo-from-ubuntu/)を参考にしてSSHキーをGitHubに登録しましょう。コマンドだけ記載しておきます。


```bash
cd ~/.ssh
ssh-keygen -t rsa
```


下記にいくつか質問されるのですべてエンターで飛ばしていきます。もし合言葉を設定したい場合は入力することも可能です。

SSHキーだけでもセキュリティが強化されるので不要だとは思いますが。


![alt_text](https://i0.wp.com/asameshicode.com/wp-content/uploads/2023/01/image-43.png?resize=768%2C476&ssl=1 "image_tooltip")


次にcatコマンドでパブリックキーを閲覧します。


```bash
cat id_rsa.pub
#表示されたキーをハイライトして右クリックすることで自動でコピーされます。
```


では[記事](https://asameshicode.com/how-to-push-repo-from-ubuntu/)に従い、SSHキーを登録できたところで再度Git cloneのコマンドを実行します。


```bash
cd /home/dan
git clone git@github.com:TraitOtaku/JS-Hiroba-Backend.git
#結果
dan@asameshi:~$ git clone git@github.com:TraitOtaku/JS-Hiroba-Backend.git
Cloning into 'JS-Hiroba-Backend'...
remote: Enumerating objects: 267, done.
remote: Counting objects: 100% (267/267), done.
remote: Compressing objects: 100% (195/195), done.
remote: Total 267 (delta 79), reused 257 (delta 69), pack-reused 0
Receiving objects: 100% (267/267), 1.21 MiB | 5.22 MiB/s, done.
Resolving deltas: 100% (79/79), done.
```


これでリポジトリのクローンができました。

Windowsのファイルエクスプローラーを見ると確かにリポがクローンされていることが確認できました。


![alt_text](https://i0.wp.com/asameshicode.com/wp-content/uploads/2023/01/image-44.png?resize=768%2C550&ssl=1 "image_tooltip")


もし手動でファイルを置きたい場合はここにおいてください。


## **仮想環境をアクティベート**

下のコマンドでvirtualenvで仮想環境を作成します。envの所はディレクトリ名なので自分で好きなものを決めてください。


```bash
cd Djangoのプロジェクトディレクトリ
virtualenv env
#virtualenvのライブラリがない場合
sudo apt install python3-virtualenv
ls
#結果
command  env  js_hiroba  manage.py  memo.txt  requirements.txt  static
```


では、/env/binフォルダにあるactivateを実行して仮想環境を起動します。


```bash
source env/bin/activate
#envが付きました！
(env) dan@asameshi:~/JS-Hiroba-Backend$
```


lsでDjangoのプロジェクトのルートディレクトリを参照します。

Pythonのプログラムを作業するにあたりrequirements.txtというファイルを作成することが慣習になります。このファイルがPythonのプロジェクトで使用するライブラリの一覧になります。

ではこのテキストファイルを使ってDjangoプロジェクトに必要なライブラリをインストールしていきます。


```bash
pip install -r requirements.txt
#結果
Defaulting to user installation because normal site-packages is not writeable
Collecting asgiref==3.5.2
 Downloading asgiref-3.5.2-py3-none-any.whl (22 kB)
Collecting Django==4.1.4
 Downloading Django-4.1.4-py3-none-any.whl (8.1 MB)
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8.1/8.1 MB 5.3 MB/s eta 0:00:00
Collecting django-cors-headers==3.13.0
 Downloading django_cors_headers-3.13.0-py3-none-any.whl (13 kB)
Collecting djangorestframework==3.14.0
 Downloading djangorestframework-3.14.0-py3-none-any.whl (1.1 MB)
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.1/1.1 MB 5.3 MB/s eta 0:00:00
Collecting psycopg2-binary==2.9.5
 Downloading psycopg2_binary-2.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.0 MB)
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.0/3.0 MB 5.9 MB/s eta 0:00:00
Collecting pytz==2022.6
 Downloading pytz-2022.6-py2.py3-none-any.whl (498 kB)
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 498.1/498.1 kB 5.3 MB/s eta 0:00:00
Collecting sqlparse==0.4.3
 Downloading sqlparse-0.4.3-py3-none-any.whl (42 kB)
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 42.8/42.8 kB 6.6 MB/s eta 0:00:00
Installing collected packages: pytz, sqlparse, psycopg2-binary, asgiref, Django, djangorestframework, django-cors-headers
 WARNING: The script sqlformat is installed in '/home/dan/.local/bin' which is not on PATH.
 Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
 WARNING: The script django-admin is installed in '/home/dan/.local/bin' which is not on PATH.
 Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed Django-4.1.4 asgiref-3.5.2 django-cors-headers-3.13.0 djangorestframework-3.14.0 psycopg2-binary-2.9.5 pytz-2022.6 sqlparse-0.4.3
```


もしrequirements.txtがない場合は必要なライブラリを手動でインストールしましょう。


## **Gunicornのインストール**

次にデプロイで使用するGunicornをインストールします。すでにインストールされている場合はその旨を言われるので確認しておきましょう。[Gunicornの説明はこちらの記事](https://asameshicode.com/what-is-gunicorn/)をどうぞ。


```bash
pip install gunicorn
#すでにインストールされている場合
Requirement already satisfied: asgiref<4,>=3.5.2 in ./env/lib/python3.10/site-packages (from django) (3.5.2)
Requirement already satisfied: sqlparse>=0.2.2 in ./env/lib/python3.10/site-packages (from django) (0.4.3)
Requirement already satisfied: setuptools>=3.0 in ./env/lib/python3.10/site-packages (from gunicorn) (59.6.0)
Installing collected packages: gunicorn
Successfully installed gunicorn-20.1.0
#requirements.txtを更新する場合
pip freeze > requirements.txt
```



## **settings.pyのコンフィグレーション**

では、Djangoが正しく起動できるために、settings.pyのコンフィグレーションを確認します。

今回はコマンドラインのテキストエディタのnanoを使ってUbuntuサーバーに上げたファイルをいじりますが、オリジナルを編集してアップロードしなおしてもOKです。


```bash
cd js_hiroba/
#もしくは
cd djangoプロジェクトフォルダ
ls
sudo nano settings.py
```


下記のラインが正しく記載されているか確認しましょう。


```python
ALLOWED_HOSTS = ['127.0.0.1', '172.18.173.157']
   DATABASES = {
       'default': {
           'ENGINE': 'django.db.backends.postgresql_psycopg2',
           'NAME': 'asameshidb',
           'USER': 'djangouser',
           'PASSWORD': 'django1234',
           'HOST': '127.0.0.1',
           # 'PORT': '5432',
       }
   }
```


ALLOWED_HOSTS = ['*'] で全てのIpを許可しますが、セキュリティ上、良くないのでこれはやめましょう。


## **Staticファイルの扱い**

同じくsettings.pyです。

下記のようにosモジュールをインポートしてStaticファイル（CSS,JS,画像ファイル）等の保管場所を指定してあげます。


```python
import os
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
```



## **データベースのマイグレーション**

ではmanage.pyがあるディレクトリから下記のコマンドで接続したDBにDjangoのモデルで作成したテーブルの枠組みをmigration（マイグレーション：移動）します。


```bash
python3 manage.py makemigrations
python3 manage.py migrate
#DBテーブルが作成されたことが表示されます。
```



## **スーパーユーザーの作成**

次にDjangoのアドミンパネルに入るためのスーパーユーザを作成します。


```bash
python3 manage.py createsuperuser
```



## **collectstaticの実行**

ではmanage.pyから下記のコマンドを実行して、Staticファイルをデプロイ用に一か所にまとめます。


```bash
python3 manage.py collectstatic
#yesで実行
```



## **ファイヤーウォールの設定**

では、このDjangoプロジェクトをテストで公開するために下記のコマンドでサーバーのポートを開けます。


```bash
sudo ufw allow 8000
#結果
Rules updated
Rules updated (v6)
```



## **Djangoのテストサーバーでテスト**

では下記のコマンドでDjangoにおまけでついてきたウェブサーバーで実際にpublicのネットワークから見れるか確認しましょう。

ちなみに自宅のLAN環境の場合はポートフォワーディングをして外からのアクセスを許可しないといけません。

ではWindowsのブラウザからDjangoのアプリにアクセスしてみます。

http://172.18.173.157:8000/admin

Ipはip addrで出たIPを記載してください。:8000はポート番号になります。

![alt_text](https://i0.wp.com/asameshicode.com/wp-content/uploads/2023/01/image-45.png?w=587&ssl=1 "image_tooltip")


これで、windowsからUbuntuでホスティングされているDjangoにアクセスすることができました。

しかし実際のデプロイではpython manage.py runserverで起動されるデベロップメント用のテストサーバーは使用しません。


## **Gunicornを使ってテスト**

では、今度はgunicornを使って同じようにDjangoアプリをデプロイできるか試してみましょう。

※このproject.wsgiのprojectはDjangoのアプリ名です。settings.pyが入っているディレクトリ名ですね。


```
gunicorn --bind 0.0.0.0:8000 js_hiroba.wsgi
※必要に応じてパスを移動（pwdで確認）
gunicorn --bind 0.0.0.0:8000 Djangoのプロジェクト名.wsgi
[2023-01-24 14:43:41 -0500] [3720] [INFO] Starting gunicorn 20.1.0
[2023-01-24 14:43:41 -0500] [3720] [INFO] Listening at: http://0.0.0.0:8000 (3720)
[2023-01-24 14:43:41 -0500] [3720] [INFO] Using worker: sync
[2023-01-24 14:43:41 -0500] [3721] [INFO] Booting worker with pid: 3721
```


では同じようにWindowsから同じようにブラウザにアクセスします。

http://172.18.173.157:8000/admin/

GunicornでDjangoアプリがデプロイのテストができました。


![alt_text](https://i0.wp.com/asameshicode.com/wp-content/uploads/2023/01/image-46.png?w=451&ssl=1 "image_tooltip")


スタイルが抜けている部分は無視しておいて大丈夫です。

では同じようにCtrl +CでGunicornを止めておきます。


## **Systemdソケットとサービスファイルの作成**

ではここからgunicorn様にsystemd socket(ソケット)とサービスファイルを作成します。

さっき、gunicornが動くことが分かったのですが、よりコントロールのある設定をしていきます。

下記のコマンドでソケットファイルを作成します。


```bash
sudo nano /etc/systemd/system/gunicorn.socket
```


中身はこのようになります。


```bash
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target
```


次に、systemdサービスファイルを作成します。


```bash
sudo nano /etc/systemd/system/gunicorn.service
```


中はこんな感じです。

Nanoの使い方が分からない人は調べておきましょう。Ctrl+Oで上書きします。

UserはUbuntuのユーザー名になります。


```bash
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
User=dan
Group=www-data
WorkingDirectory=/home/dan/JS-Hiroba-Backend
ExecStart=/home/dan/JS-Hiroba-Backend/env/bin/gunicorn \
         --access-logfile - \
         --workers 3 \
         --bind unix:/run/gunicorn.sock \
         js_hiroba.wsgi:application
[Install]
WantedBy=multi-user.target

```



* User=Ubuntuのユーザー名
* Group=www-data（これからUbuntuのユーザーをwww-dataに追加します。）
* WorkingDirectory　/home/Ubuntuユーザー/Djangoプロジェクト
* ExecStart=/home/dan/Djangoプロジェクト/env/bin/gunicorn
* その下で、Djangoプロジェクト.wsgi:application

次に下のコマンドでGunicornソケットを実行します。これで自動でソケットファイルが作成されます。


```bash
sudo systemctl start gunicorn.socket
#結果
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
```


ここで、systemdが起動されていないというエラーが出ました。下記にLinuxの重要なSystemdtosystemctlについて簡単に説明します。

`systemd` は init systemで、起動時に実行されるアプリケーションのことです。systemdはLinuxの多くのディストリビューターで使われる新しいスタンダードとなるシステムマネージャー（管理システム）になります。Linuxのアドミン作業でsystemdを使っていくことになるので知っておいて損はありません。`systemd` は比較的新しいシステムなので、Linuxディストロによってはインストールされていないこともあります。また、今回のWSL2ではデフォルトでインストールされていないようです。

では起動時にsystemdが使えるようにUbuntuのコンフィグをいじります。


```bash
sudo nano /etc/wsl.conf
#下記の行を追加してセーブします。
[boot]
systemd=true
```


ではUbuntuサーバーを再起動するために、**Windowsのコマンドライン**から下記のコマンドを実行します。


```bash
wsl --shutdown
#これでUbuntuのコマンドラインインターフェースが落ちます。
```


では再度WSL2のUbuntuを起動しなおしましょう。

再度、Gunicornのソケットファイルを作成します。


```bash
sudo systemctl start gunicorn.socket
```


これでエラーが出なければOKです。



![alt_text](https://i0.wp.com/asameshicode.com/wp-content/uploads/2023/01/image-47.png?w=471&ssl=1 "image_tooltip")


gunicorn.socketをアクティブにします。


```bash
sudo systemctl enable gunicorn.socket
#結果
Created symlink /etc/systemd/system/sockets.target.wants/gunicorn.socket → /etc/systemd/system/gunicorn.socket.
```


では下記のコマンドでプロセスのステータスを確認しましょう。


```bash
sudo systemctl status gunicorn.socket
#結果
● gunicorn.socket - gunicorn socket
    Loaded: loaded (/etc/systemd/system/gunicorn.socket; enabled; vendor preset: enabled)
    Active: active (listening) since Tue 2023-01-24 15:34:40 EST; 1min 4s ago
  Triggers: ● gunicorn.service
    Listen: /run/gunicorn.sock (Stream)
    CGroup: /system.slice/gunicorn.socket
Jan 24 15:34:40 asameshi systemd[1]: Listening on gunicorn socket.
```


次に、/runディレクトリ直下にgunicorn.sockファイルがあるか確認します。


```bash
file /run/gunicorn.sock
#結果
/run/gunicorn.sock: socket
```


※もしここで、systemctl statusのコマンドでエラーが出るか、gunicorn.sockファイルが見つからないメッセージが出た場合はgunicornソケットが作成されていないことが原因になるかと思います。下記のコマンドでgunicornソケットのログを出しましょう。


```bash
sudo journalctl -u gunicorn.socket
```


次のステップに進む前に下記のファイルに問題が無いか確認してください。

/etc/systemd/system/gunicorn.socket


## **ソケットアクティベーションのテスト**

Gunicorn.scoketユニットをスタートしただけだとgunicorn.serviceはアクティブになりません。それはソケットが接続を受けていないからです。

下記のコマンドでステータスをチェックしましょう。


```bash
sudo systemctl status gunicorn
#結果
○ gunicorn.service - gunicorn daemon
    Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled)
    Active: inactive (dead)
TriggeredBy: ● gunicorn.socket
```


gunicorn.service; disabledになっているのでGunicornを起動します。


```bash
sudo systemctl start gunicorn
sudo systemctl status gunicorn
#結果
● gunicorn.service - gunicorn daemon
    Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled)
    Active: active (running) since Tue 2023-01-24 15:43:52 EST; 29s ago
TriggeredBy: ● gunicorn.socket
  Main PID: 611 (gunicorn)
     Tasks: 4 (limit: 19139)
    Memory: 120.5M
    CGroup: /system.slice/gunicorn.service
            ├─611 /home/dan/JS-Hiroba-Backend/env/bin/python /home/dan/JS-Hiroba-Backend/env/bin/gunicorn --access-log>
            ├─612 /home/dan/JS-Hiroba-Backend/env/bin/python /home/dan/JS-Hiroba-Backend/env/bin/gunicorn --access-log>
            ├─613 /home/dan/JS-Hiroba-Backend/env/bin/python /home/dan/JS-Hiroba-Backend/env/bin/gunicorn --access-log>
            └─614 /home/dan/JS-Hiroba-Backend/env/bin/python /home/dan/JS-Hiroba-Backend/env/bin/gunicorn --access-log>
Jan 24 15:43:52 asameshi systemd[1]: Started gunicorn daemon.
Jan 24 15:43:52 asameshi gunicorn[611]: [2023-01-24 15:43:52 -0500] [611] [INFO] Starting gunicorn 20.1.0
Jan 24 15:43:52 asameshi gunicorn[611]: [2023-01-24 15:43:52 -0500] [611] [INFO] Listening at: unix:/run/gunicorn.sock >
Jan 24 15:43:52 asameshi gunicorn[611]: [2023-01-24 15:43:52 -0500] [611] [INFO] Using worker: sync
Jan 24 15:43:52 asameshi gunicorn[612]: [2023-01-24 15:43:52 -0500] [612] [INFO] Booting worker with pid: 612
Jan 24 15:43:52 asameshi gunicorn[613]: [2023-01-24 15:43:52 -0500] [613] [INFO] Booting worker with pid: 613
Jan 24 15:43:52 asameshi gunicorn[614]: [2023-01-24 15:43:52 -0500] [614] [INFO] Booting worker with pid: 614
Jan 24 15:43:53 asameshi gunicorn[613]:  - - [24/Jan/2023:20:43:53 +0000] "GET / HTTP/1.1" 400 143 "-" "curl/7.81.0"
```


ソケットのアクティベーションのメカニズムをテストするには、curlコマンドを使ってソケットに接続シグナルを送ります。


```bash
curl --unix-socket /run/gunicorn.sock localhost
#結果
<!DOCTYPE html>
<html lang="en">
<head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 <meta name="robots" content="NONE,NOARCHIVE">
 <title>DisallowedHost
         at /</title>
 <style type="text/css">
   html * { padding:0; margin:0; }
   body * { padding:10px 20px; }
   body * * { padding:0; }
   body { font:small sans-serif; background-color:#fff; color:#000; }
   body>div { border-bottom:1px solid #ddd; }
   h1 { font-weight:normal; }
   h2 { margin-bottom:.8em; }
   h3 { margin:1em 0 .5em 0; }
-------
```


もし400エラーが返ってきた場合はsetting.pyのDEBUGがFalseになっていることが原因の一つになる可能性があります。テストのためにDEBUG = Trueにして問題がなければFalseに戻すようにしておきましょう。

では、Gunicornのステータスをもう一度確認してみましょう。


```bash
sudo systemctl status gunicorn
#修正したら下記のコマンド
sudo systemctl daemon-reload
#で、gunicornのプロセスもリスタートしましょう。
sudo systemctl restart gunicorn
```


では、次に進む前にここまでで問題ないことを確認しましょう。


## **NginxのGunicornにパスするプロキシを設定する**

では、gunicornも設定ができたところで、次にプロセスにnginxのトラフィックを設定してきます。

nginxはウェブサーバーでフロントエンドのアプリケーションをデプロイする際にも使うので是非慣れておきたいですね。

まずは、Nginxのsites-availableディレクトリに新しいサーバーブロックを作成します。

ファイル作成前に理解しておきたい部分を説明します。



* サーバーブロックとは各ウェブサイトのコンフィグをファイルごとに分けているものを指します。
* sites-availableはサイト（Djangoアプリなど）のサーバーブロックを保管するディレクトリになります。
* /etc/nginxにsites-enableというディレクトリがあります。ここに実際に公開したいサイトをシンボリックリンクでリンクしておきまsす。これはWindowsのショートカットのようなイメージになります。
* なので、nginxのサーバーブロックを編集するする際にはいつもsites-available内のファイルを編集することになります。

先に学習の為にnginxのデフォルトのコンフィグを見てみましょう。


```bash
cd /etc/nginx
ls
sudo nano nginx.conf
#この部分を見てください。
http {
       include /etc/nginx/conf.d/*.conf;
       include /etc/nginx/sites-enabled/*;
}
```


このnginx.confがnginxが最初に参照するコンフィグになります。

ここで分かるように/etc/nginx/sites-enabled/*のすべてのファイルが読み込まれるようになります。

では、これが理解できたところで、/etc/nginx/sites-availableにサーバーブロックを作成してsites-enabledにリンクさせましょう。


```bash
sudo nano /etc/nginx/sites-available/django-api
#django-apiの部分は自分のサイト名にするのが一般的
```


下記にベーシックなサーバーブロックのコンフィグ例を記載します。


```nginx
server {
   listen 80;
   server_name 172.18.173.157;
   location = /favicon.ico { access_log off; log_not_found off; }
   location /static/ {
       root /home/dan/JS-Hiroba-Backend;
   }
   location / {
       include proxy_params;
       proxy_pass http://unix:/run/gunicorn.sock;
   }
}

```



* listen 基本は80番ポートになります。もし81番ポートを使いたい場合は81を記載します。その場合ドメインの後にポートを記載してDjangoアプリにアクセスすることになります。例:172.18.173.157:81、asameshicode.com:81など
* server_nameはユーザーがURLに打ち込むドメイン名です。　パブリックIPからアクセスさせるにはIPアドレスを記載します。ドメインがある場合はドメイン名（asameshicode.com www.asameshicode.com）を記載します。
* location /static/ にstaticファイルのファイルパスを指定します。

もしドメインを購入して、SSL（HTTPS）から公開したい場合は下記の様になります。

※この場合はSSLの取得と、DNSでドメインの設定が必要になります。先に80ポートからIPアドレスで公開できるか試しておきましょう。[Let’sEncryptでSSLを無料で取得する方法はこの記事](https://asameshicode.com/lets-encrypt-certbot/)を参照してください。


```nginx
server {
   listen 80;
   listen [::]:80;
   server_name asameshi-api.cloud www.asameshi-api.cloud;
   return 301 https://asameshi-api.cloud$request_uri;
}
server {
   listen 443 ssl;
   server_name asameshi-api.cloud www.asameshi-api.cloud;
   ssl_certificate /etc/letsencrypt/live/asameshi-api.cloud/fullchain.pem;
   ssl_certificate_key /etc/letsencrypt/live/asameshi-api.cloud/privkey.pem;
   location = /favicon.ico { access_log off; log_not_found off; }
   location /static/ {
       root /home/dan/JS-Hiroba-Backend;
   }
   location / {
       include proxy_params;
       proxy_pass http://unix:/run/js-hiroba-backend.sock;
   }
}
```


では、サーバーブロックのファイルができたところでシンボリックリンクでsites-enabledディレクトリ内にリンクしてあげます。


```bash
sudo ln -s /etc/nginx/sites-available/django-api /etc/nginx/sites-enabled
#django-apiは自分のサーバーブロックのファイル名に変更しておくこと
```


では、nginxのコンフィグレーションをテストしてみましょう。


```bash
sudo nginx -t
#結果
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
```


okが返ってきたら大丈夫です。

ここでエラーがでなければ、再度nginxをリスタートします。


```bash
sudo systemctl restart nginx
```


では、最初に開けた8000番のポートはデベロップメント用なので閉じてあげます。


```bash
sudo ufw delete allow 8000
#結果
sudo ufw status
#結果
Status: inactive
```


もしufw statusのコマンドでファイヤーウォールがinactiveの場合はアクティベートしてあげます。


```bash
sudo ufw enable
```


それから、通常のアクセスは80番と443番のポートなので　HTTPとHTTPSのポートを下記のように許可します。


```bash
sudo ufw allow 'Nginx Full'
#結果
Rule added
Rule added (v6)
```


必要に応じてサービスを再起動します。


```bash
sudo systemctl restart nginx
sudo systemctl restart gunicorn
```


これでDjangoのデプロイは一応できました！


![alt_text](https://i0.wp.com/asameshicode.com/wp-content/uploads/2023/01/image-48.png?w=519&ssl=1 "image_tooltip")


ここで大きな問題があることに気が付きました。

課題①**UbuntuをホストしているWindowsからはDjangoアプリにアクセスできるが、他のネットワークデバイスからはアクセスできない。**

課題②**Ubuntuサーバーを起動する度にIPアドレスが変わる。**

最初は、固定IPにすればよいのではと思いましたがこの問題はGitHubでも大きなトピックになっているようでした。

[https://github.com/microsoft/WSL/issues/4150](https://github.com/microsoft/WSL/issues/4150)

理由のうちの一つとしてWSL2のネットワークコンフィグレーションはWindowsのHyper-Vで行っていることとと、NATネットワークを使用していることが原因です。

UbuntuのコマンドラインでこのようにデフォルトゲートウェイのIPを見つけました。


```
ip r | grep default
#結果
default via 172.18.160.1 dev eth0 proto kernel
```


ではwindowsの方でネットワークの詳細を確認しました。

![alt_text](https://i0.wp.com/asameshicode.com/wp-content/uploads/2023/01/image-49.png?w=568&ssl=1 "image_tooltip")


やはりHyper-Vのバーチャルネットワークアダプターを使用していることが分かりました。

この課題に関しては別途、記事にしようと思います。


## **結論**

WindowsからUbuntuなどのLinuxディストロを使ってデプロイするには、バーチャルマシンのVMWareやVirtualBoxの方がネットワークコンフィグレーションが簡単であることが分かりました。VirtualBoxではネットワークアダプターの設定がUI上で変更でき、Bridgeアダプターに変更できるのでとても簡単です。もちろん、VirtualBoxの方が使用するRAMが多くなりますが、設定が楽なのは確かです。