「サーバーを起動する」ってなんじゃ

# はじめに

一つ前の記事（[CGIってなんじゃ](https://qiita.com/vagary/items/a90652cad440fdee21e8)）に関連する話ではありますが、以前までの私はWebサーバーの仕組みに疎かったこともあり、

<br>

**「ローカル環境でLaravelやNode.jsのサーバーを起動して実行すること」**

と、

**「実際のWebサーバーやアプリケーションサーバーでプログラムを実行すること」**

<br>

の違いがあまり理解できていませんでした。

（「サーバーの中で ```npm run start``` とか ```php artisan serve``` しなきゃいけないの？」「けどWebサーバーにそのまま置くだけで動くこともあるな...」というレベル）

<br>

今回はそのあたりについて調べたことをまとめていきます。

# 概要

- 「サーバーを起動」とは
- 「サーバーを起動」する主な環境と仕組み
    - Webサーバーやアプリケーションサーバーでプログラムを実行する場合
    - ローカル環境（開発用のPC等）でサーバーを起動する場合
    - 上記の違い
- 【余談】LaravelとNestJS（Node.js）の違い

# 「サーバーを起動」とは

サーバー（Server）とは「Serve（供給する）」という意味があるように、何かを供給する役割があります。

例えば

- DB（データベース）サーバーはDBに登録されている情報の供給
- WebサーバーはHTMLやCSSといった静的コンテンツの供給
- アプリケーションサーバーは動的コンテンツの生成

といったことをクライアントのリクエストに応じて行うということです。

<br>

サーバーを起動することで、上記のような「**リクエストを受けて何かしらの結果を返す**」機能を利用できるようになります。

# 「サーバーを起動」する主な環境と仕組み

WebサーバーやDBサーバーで実際にどんな処理をさせたいか、ということを考えて実現するのがエンジニアやプログラマーのお仕事ですが、サーバーを起動させたいタイミングや環境としては主に

- 開発中の**ローカル環境**
- テスト等で使用する**検証環境**
- リリース用の**本番環境**

がありますね。

<br>

本番環境や検証環境ではWebサーバー＋アプリケーションサーバーのように役割を分けて実装し、逆に開発中はローカル環境で手軽にアプリケーションを起動、動作確認したい、ということがあると思います。

:::note info
もちろんローカル環境でも、Dockerのような仮想化技術を使用して本番環境や検証環境のように複数のサーバーからアプリケーションを構築することもあります。
:::

では、それぞれの環境でサーバーを実行する場合の違いについて見てみましょう。

## Webサーバーやアプリケーションサーバーでプログラムを実行する場合

Laravel＋PHPを例にすると、よくある構成としては

- Nginxを使用したWebサーバー
- PHP-FPMを使用したアプリケーションサーバー
- MySQL（ここはなんでも）を使用したDBサーバー

といった感じです。

<br>

このようにすることで、

- NginxのWebサーバーがクライアントからのリクエストを受け付け、静的コンテンツを返すだけであればそれをクライアントに返却
- 動的コンテンツを生成する必要があれば、Webサーバーがアプリケーションサーバーに対してリクエストを転送し、アプリケーションサーバーが処理を行う
- アプリケーションサーバーとDBサーバー間で動的コンテンツの生成処理を行い、結果をWebサーバーに返却
- Webサーバーがクライアントに結果を返却


のように、それぞれ役割を持った複数のサーバー同士が連携して1つのアプリケーションとして動作します。

<br>

この場合は複数のサーバーが連動しているため、全てのサーバーが正常に起動・動作していないといけません。

## ローカル環境（開発用のPC等）でサーバーを起動する場合

Laravel の開発でサーバーを起動する時の例でお話ししますが、

```php artisan serve``` では **PHPの組み込みWebサーバー**を使用しています。

<br>

PHPの組み込みWebサーバー（ビルトインWebサーバー）はPHPで使用できる軽量なWebサーバーであり、

```php -S localhost:8000```

のようなコマンドで簡単に起動することができます。

HTTPリクエストの解析に加え、PHPスクリプトを実行して動的コンテンツを生成することもできるため、これだけで簡易的なWebサーバー＋アプリケーションサーバーのように機能します。

:::note info
```php -S``` を実行したディレクトリがドキュメントルートとなり、リクエストされたPHPファイルが存在すればインタープリタで直接実行します。
:::

Laravelの起動時に使用される ```php artisan serve``` は上記の処理を内部で実行しているため、最小限の設定で簡易的なサーバーとして実行することができ、開発に向いています。

<br>

ただし、セキュリティやパフォーマンス面では制限があるので本番環境や検証環境で使用することには不向きとなります。


## 上記の違い

Webサーバーやアプリケーションサーバーといった複数のサーバーを構成している本番環境や検証環境では、**全てのサーバーが正常に起動していなければ動作しません**。

現在はこういった複数のサーバーを一括管理できるツールもあるので管理にそこまで手がかかることはありませんが、それぞれの役割を持つ複数のサーバーで構成していて機能が充実している分、一から構築するために時間がかかります。

そのため**セキュリティやパフォーマンスにこだわりたい本番環境等での使用に適しており**、ローカル環境で動作確認するだけであればここまで構築しなくても問題ありません。

<br>

逆に ```php artisan serve``` のようなビルトインWebサーバーを使用したローカル環境の実行では、リクエスト／レスポンスやそれ以外の最低限の機能に限られますが、**少ない準備で簡易的にサーバーの機能を実行することができます**。

そのため**基本的には開発時の使用に留まり、このような簡易的な仕組みを本番環境や検証環境で使用するべきではありません**。


# 【余談】LaravelとNestJS（Node.js）の違い

少し気になったので調べてみました。

ローカル開発では

- Laravel の `php artisan serve`
- Node.js の `npm run start`

のように実行することで簡易的なサーバーを起動することができます。

<br>

では実際にサーバーへ配置する場合はどうでしょうか。

<br>

### Laravel（Nginx＋PHP-FPMを使用する場合）
- 言語とランタイム
    - PHP-FPM（常駐プロセス）によってPHPコードを実行
- デプロイ方法
    - プロジェクトをそのまま配置し、Nginxから呼び出されるPHP-FPMによって動作
- リバースプロキシの設定
    - PHP-FPMにリクエストを転送する設定が必要
- 構築と処理の流れ
    - WebサーバーにNginx、アプリケーションサーバーにLaravelのプロジェクトを配置
    - Nginxの設定ファイルでLaravelプロジェクトの`public`ディレクトリをドキュメントルートとして指定
    - 上記の設定により、Webサーバーからアプリケーションサーバー（Laravel）へリクエストが転送されるようになる


### NestJS（Node.js）

- 言語とランタイム
    - Node.jsのランタイムでJavaScriptを実行
- デプロイ方法
    - 実行ファイル（`dist`）をサーバーに配置してNode.jsランタイムで動作させる
- リバースプロキシの設定
    - Nginxがリバースプロキシとして動作し、アプリケーションサーバー（Node.js）にリクエストを転送する設定が必要
- 構築と処理の流れ
    - NestJSはTypeScriptで記述されているため、まずはNestJSのソースコードをビルドしてJavaScriptへのトランスパイルを行う
    - 上記で生成された実行ファイル群である`dist`ディレクトリをアプリケーションサーバーに配置
    - サーバー内にはNode.js（JavaScriptの実行環境）が必要で、プロセスマネージャーによってこれを実行する（`pm2 start dist/main.js`）
        - **サーバーのプロセスとしてNode.jsを実行**
    - WebサーバーのNginxをリバースプロキシとして設定し、アプリケーションサーバー（Node.js）へのリクエストを転送


<br>

Laravelの場合はPHP-FPMが常駐プロセスとなるため、開発者がプロセスを管理する必要はなく基本的にサーバーを起動するだけで動作し、NestJSの場合はプロセスマネージャーを使用してNode.jsのプロセスを明示的に管理する必要があるんですね。

# 最後に

ここまで読んでくださりありがとうございました。