Win上でビルドした.NET Core Webアプリを、CentOS7で実行するまでの最短環境構築 （開発デプロイ編）

# なにする
[CentOS事前準備編](https://qiita.com/miyapei/items/8a6caaf4f8121e4f0830)（Linux側の準備）の続きで
こちらでは
「開発環境の準備～デプロイ、Linux上で実行するまで」
の部分の流れを超ざっくり追います。

# はじめに
（事前準備編でサーバの用意ができている状態から、）
開発環境となるVSCodeを用意してデモプロジェクトを発行、
それをビルドしてLinuxに持っていき起動します。
それをApacheのリバースプロキシでアクセス可能にするまでの開発デプロイ編です。
（前回がインフラチームの作業だとすれば、こちらは開発者が担当する部分かな）

# 開発デプロイ編 はじめます！

## ローカル開発環境を作る
環境はWindows(10)です。

- ローカルでビルドするために .NET Core SDK をインストール
    - https://www.microsoft.com/net/download
- VSCodeを用意します
    - https://code.visualstudio.com/Download

\# Portable版(.zip)もあるでよ。私はこれ。

これだけです。

### デモプロジェクトを用意してビルド(publish)する
\# 予め用意されているテンプレというかデモプロジェクトがありますので、
　それを取得してビルド（publish）して持っていきます。

作業用フォルダを作っておき、VSCodeを立ち上げて開きます。
その状態で、ターミナルで以下のコマンドを打ち、プロジェクトを展開します
（ターミナルはメニューかCtrl+@で開きます）

```
> dotnet new webapp -o RazorPagesMovie
```
これでフォルダにファイルができあがります。
ライブラリがないよ、とかのポップアップが出たら「Yes」で勝手に入ります。

### とりあえずローカルで動かす
.csprojのある場所に移動して、runすると動きます

```
> cd RazorPagesMovie
> dotnet run
```

エラーなどが出なければ http://localhost:5000/ でLISTENしてるよって出るので、アクセス。
正常にデモサイトが見れたらOKです。

なお、ポート番号を変更する場合や、Linux上で動作させる場合にhttpsを使用しない場合
下記ファイル、下記の箇所のapplicationUrlの部分も書き換えます。
（localhostはそのままでも変えても大丈夫。今回は下記で行きます）

```json:\Properties\launchSettings.json
    "RazorPagesMovie": {
      "commandName": "Project",
      "launchBrowser": true,
      "applicationUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
```

**ポート番号を変える場合**
ポート番号を変える場合は、上記のapplicationUrlだけ変えても
CentOS展開時に反映されなかったため、以下も追記します。

```c#:\Program.cs
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .UseUrls("http://localhost:5001") // ここを追記
            ;
```


### ちなみに補足、解説
これをpublishして持っていけば動くんですが…

.NET Webは上記のように、
ポート番号に対して独自のWebサーバ（Kestrel:ケストレル）が起動します。
\# なので、1プロジェクトごとにポート番号が要ります。
　（ちなみにこのポート番号はApacheに経由してもらうため、ファイアウォールの設定は不要）

Linux側ではこれをApacheのリバースプロキシで経由して見せるわけですが、
素直に転送するとドキュメントルート直下で動くようなイメージになります。

サブドメインなどを切れる場合などは問題ありませんが、
もしそうでない場合で
例えばディレクトリごとにプロジェクトを起動したい、という場合などは
あらかじめプロジェクト内のパスも、それを想定したパスにしておく
\# ドキュメントルート直下にならないので。
といった対応が必要です。

そんな場合のナレッジも兼ねて、
私もそう詳しくないのですが、あらかじめあるディレクトリ以下にする方法を載せておきます。

```c#:\Startup.cs
            app.UsePathBase("/path/to/project_directory"); // ※ app.UseStaticFiles();に影響します
            app.UseStaticFiles();
```

※ app.UseStaticFiles() より前に記載すると、静的ファイル参照時の起点も同じディレクトリからになります。
　 app.UseStaticFiles() より後に書けばパスの指定がかからないため、Kestrelのドキュメントルート起点になります。

このように、パスとKestrel側の（プロジェクト側の）ポート番号が異なっていれば
Apacheへのアクセスは80番のみ（1つのポートのみ）でも
それぞれのパスに対応したプロジェクトにアクセスさせることができます。

### それではpublishします
外部のサーバに合わせたRID（ランタイム識別子）を指定することで、その環境用にビルドできます。
RIDのカタログは[こちら](https://docs.microsoft.com/ja-jp/dotnet/core/rid-catalog)

```
> dotnet publish --runtime centos.7-x64
```

※ ちなみにbuildコマンドもありますが
　 ASP.NETとかだとbuildすれば他の環境でも動きましたが
　 .NET Coreでは自環境で動く最低限しかファイルが用意されないので
　 buildしたものを持って行っても動きません。

\bin\Debug\netcoreapp2.1\centos.7-x64\publish にファイルができます。
できたdll達をsambaで持っていくことでサーバへの展開は完了です。
（持っていくときは単純に公開するパスに合わせて配置の想定です）


## Linuxで起動

### まずは手動で動かしてみる
Windowsでrunした時と同じように、とりあえず起動確認だけしておきます。
Linuxにログインして、先ほど展開したフォルダまで移動し、dotnetコマンドでメインのdllを実行します。

```bash
dotnet ./RazorPagesMovie.dll
```
runしたときと似たようなのが出て、待機状態になります。
この状態では外部からアクセスできないので、
エラーが出なければとりあえずOKです。

### サービスとして登録する
都度手動起動して走りっぱなしにしておくわけにもいかないので、
サービスとして登録して起動します。

```bash
vi /etc/systemd/system/(ファイル名は適当でOK).service
```

ファイルの内容はこんな感じで、最低限必要なのはパスの部分の調整です

```text:（さっきの）.service
[Unit]
Description=Example .NET Web API App running on CentOS 7

[Service]
WorkingDirectory=/home/apache/vhost/path/to/project_directory
ExecStart=/usr/bin/dotnet /home/apache/vhost/path/to/project_directory/RazorPagesMovie.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
SyslogIdentifier=dotnet-example
User=apache
Environment=ASPNETCORE_ENVIRONMENT=Production

[Install]
WantedBy=multi-user.target
```

こうして作ったファイルをサービスとして登録します。

```bash
### 自動起動有効化
systemctl enable (さっきの).service

### 起動
systemctl start (さっきの).service

### 確認
systemctl status (さっきの).service
```

### Apacheでリバースプロキシを設定する
最後に、外部からのApacheへのアクセスをKestrelに転送するため
リバースプロキシを設定します。

```bash
vi /etc/httpd/conf.d/vhost.conf
```

```text:/etc/httpd/conf.d/vhost.conf
<VirtualHost *:*>
        RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}e
</VirtualHost>

<VirtualHost *:80>
        ServerName 192.168.0.123
        DocumentRoot /home/apache/vhost
        <Directory "/home/apache/vhost">
                Require all granted
        </Directory>

        ProxyPreserveHost On

        # 以下を環境に合わせて追記。トレイリングスラッシュは無し。
        ProxyPass /path/to/project_directory http://localhost:5000/path/to/project_directory
        ProxyPassReverse /path/to/project_directory http://localhost:5000/path/to/project_directory
</VirtualHost>
```

重要なのはProxy…の部分で、他のは前回設定した内容とかです。
今回はApacheで受けたパスを5000番ポートにそのまま流す形です。

```bash
### 確認して
apachectl configtest
### 反映します
systemctl restart httpd
```

これでアクセスしてみて見ることができれば、とりあえずは公開完了！になります。

お疲れさまでした！！