Laravel 、Nginx 、MySQL 、Next.js を用いたDocker環境構築とSSL対応

# はじめに
今回は、LaravelとNext.jsの勉強用の環境を構築しました。
いままで何となく行っていた環境構築をこの機会に少し掘り下げてみようということで、今回はNginx用のコンテナも立ち上げ、さらにSSL対応をさせてみましたので備忘録です。

また、今回はSSLの理解を深める目的があったので、Nginxコンテナの説明は他より細かく書いています。

# 動作環境
・Windows 10 (WSL2)
・Linux

# ディレクトリ構成
```
.
├── src    // Laravelプロジェクトのソースコード
├── .docker
│   ├── app    // PHPコンテナ
│   │   ├── Dockerfile
│   │   └── php.ini
│   │
│   ├── db     // MySQLコンテナ
│   │   ├── Dockerfile
│   │   ├── init.sql
│   │   └── my.conf
│   │
│   └── web    // Nginxコンテナ
│       ├── ssl (※ディレクトリ)
│       ├── default.conf
│       └── Dockerfile
│
├── frontend // Next.jsプロジェクトのソースコード
│   ├──　... (※省略)
│   └── Dockerfile
└── compose.yml 
```

バックエンドとフロントエンドは分けています。
コンテナごとに、紹介する編集ファイルをそれぞれ記載します。
※compose.ymlは最後に紹介します。


## 1. PHPコンテナ
- **Dockerfile**
- **php.ini**

## 2. MySQLコンテナ
- **Dockerfile**
- **init.sql**
- **my.conf**

## 3. Nginxコンテナ
- **Dockerfile**
- **ssl(※ディレクトリ）**
    - **ここに秘密鍵などが格納される**
- **default.conf**

## 4. frontendコンテナ（Next.js）
- **Dockerfile**

---
※バックエンドの環境は主に下記記事を参考にいたしました。

https://qiita.com/hinako_n/items/f15646ea548bcdc8ac6c

---
以下、ファイルの内容です。

## **1. PHPコンテナ**

### Dockerfile

``` /.docker/app/Dockerfile
FROM php:8.2-fpm

ENV TZ Asia/Tokyo

COPY --from=composer:2.5.5 /usr/bin/composer /usr/bin/composer

RUN apt-get -y update \
    && apt-get install -y curl apt-utils git zip unzip zlib1g-dev libzip-dev vim \
    && rm -rf /var/lib/apt/lists/* \
    && docker-php-ext-install pdo_mysql bcmath \
    && curl https://deb.nodesource.com/setup_12.x | bash -

COPY ./.docker/app/php.ini /usr/local/etc/php/php.ini

WORKDIR /var/www/src
```
上からざっくり説明します。
```
FROM php:8.2-fpm
```
PHP 8.2 FPM（FastCGI Process Manager）イメージをベースとして使用します。


```
ENV TZ Asia/Tokyo
```
環境変数TZをAsia/Tokyoに設定し、コンテナのタイムゾーンを東京に設定します。

```
COPY --from=composer:2.5.5 /usr/bin/composer /usr/bin/composer
```
Composer 2.5.5イメージを使用します。

```
RUN apt-get -y update \
    && apt-get install -y curl apt-utils git zip unzip zlib1g-dev libzip-dev vim \
    && rm -rf /var/lib/apt/lists/* \
    && docker-php-ext-install pdo_mysql bcmath \
    && curl https://deb.nodesource.com/setup_12.x | bash -
```
必要なパッケージや拡張ライブラリをインストールします。
（細かい内容は割愛します。）


```
COPY ./.docker/app/php.ini /usr/local/etc/php/php.ini
```
後で記載するカスタムPHP設定ファイルphp.iniをコンテナ内の適切な場所にコピーします。

```
WORKDIR /var/www/src
```
作業ディレクトリを/var/www/srcに設定しています。

---
### php.ini

 ```/.docker/app/php.ini
 zend.exception_ignore_args = off
expose_php = on
max_execution_time = 30
max_input_vars = 1000
upload_max_filesize = 64M
post_max_size = 128M
memory_limit = 256M
error_reporting = E_ALL
display_errors = on
display_startup_errors = on
log_errors = on
error_log = /var/log/php/php-error.log
default_charset = UTF-8

[Date]
date.timezone = Asia/Tokyo

[mysqlnd]
mysqlnd.collect_memory_statistics = on

[Assertion]
zend.assertions = 1

[mbstring]
mbstring.language = Japanese
 ```
 PHPの起動時に読み込まれる設定ファイル。
 ※内容の詳細は、参照させていただいた下記記事をご覧ください。

参照元

 https://qiita.com/ucan-lab/items/0d74378e1b9ba81699a9
 
---
## 2. MySQLコンテナ
### Dockerfile
```/.docker/db/Dockerfile
FROM mysql:8.0

COPY ./.docker/db/my.conf /etc/my.conf
```

- MySQL8.0 の公式 Docker イメージをベースイメージとして使用。
- ホストマシン上の ./.docker/db/my.confファイルをコンテナ内の /etc/my.conf にコピー。

### init.sql
```/.docker/db/init.sql
CREATE DATABASE IF NOT EXISTS testdb;
GRANT ALL PRIVILEGES ON `testdb`.* TO 'user'@'%';
FLUSH PRIVILEGES;
```
データベースの初期設定を行っています。
init.sql は、MySQL コンテナが初めて起動される際に自動的に実行されます。
内容は、上から順に下記になります。
- データベース作成
- データベース内のすべてのテーブルに対して、userが全ての権限を使えるようにしています。
- MySQLサーバーに対して権限のキャッシュをリフレッシュするよう指示します。

※userへの権限付与を行った理由として、コンテナを立ち上げたときにpermissionエラーが発生したためでした。(※危険なので本番環境では行わない)


### my.conf
```/.docker/db/my.conf
[mysqld]
# character
character_set_server = utf8mb4
collation_server = utf8mb4_0900_ai_ci

# timezone
default-time-zone = SYSTEM
log_timestamps = SYSTEM

# Error Log
log-error = mysql-error.log

# Slow Query Log
slow_query_log = 1
slow_query_log_file = mysql-slow.log
long_query_time = 1.0
log_queries_not_using_indexes = 0

# General Log
general_log = 1
general_log_file = mysql-general.log

[mysql]
default-character-set = utf8mb4

[client]
default-character-set = utf8mb4
```
MySQL サーバーの設定ファイルです。このファイルには、MySQL サーバーの動作を制御するための様々な設定オプションが含まれています。

- 文字セット設定
```
# character
character_set_server = utf8mb4
collation_server = utf8mb4_0900_ai_ci
```
- タイムゾーン設定
```
# timezone
default-time-zone = SYSTEM
log_timestamps = SYSTEM
```
- エラーログ設定
```
# Error Log
log-error = mysql-error.log
```
・スロークエリログ設定
```
# Slow Query Log
slow_query_log = 1
slow_query_log_file = mysql-slow.log
long_query_time = 1.0
log_queries_not_using_indexes = 0
```
- 一般ログ設定
```
# General Log
general_log = 1
general_log_file = mysql-general.log
```
- デフォルト文字セット
```
[mysql]
default-character-set = utf8mb4
[client]
default-character-set = utf8mb4
```
参照元は下記です。

https://it-blue-collar-dairy.com/mysql_on_docker-compose/

---
## 3. Nginxコンテナ
今回、SSLの理解が個人的に重要な部分だったのでSSLについて記載します。

### SSLについて
Webアプリケーションの通信は、盗聴やデータの改ざんの危険性があります。それを防ぐための手段として、通信を暗号化するために「SSL化」を行います。

具体的には、通信を行う際に「HTTP」ではなく「HTTPS」プロトコルを使用するように設定します。

暗号化された通信は、第三者には解読できません。
このままでは自分でも通信が解読できないので、「僕のウェブサイトは本物ですよ」という証明が必要です。それが「SSL証明書」と「秘密鍵」です。

### 「SSL証明書」と「秘密鍵」を作成する前に
「SSL証明書」と「秘密鍵」を作成する前に「証明書要求（CSR）」というものを作成しています。
CSRには、SSL証明書を発行するために、必要な公開鍵とサーバーの情報が含まれています。

ちなみに、今回はテスト環境なので、「自己署名証明書」というもので作っていますが、本番環境であれば、「認証局（CA）」というところから正式な証明書を発行してもらうのが安全です。（基本有料らしいのですが、無料のところもあるみたいです）

CSRを生成する際の設定を、openssl.cnfファイルに記載します。

### ※補足
初めは、openssl.cnfファイルは作成せずに「SSL証明書」と「秘密鍵」を作成してました。すると、Chromeで「この接続ではプライバシーが保護されません」というエラーが出てしまいました。
エラー内容を見ると、どうやら証明書が正しく設定されていないために証明書が無効？になってたみたいです。
原因としては、「SAN（Subject Alternative Name）」というものを設定しないといけなかったみたいです。

というわけで、SANを記載したopenssl.cnfファイルをもとにCSRファイルを作成した次第です。

### SAN（Subject Alternative Name）について
「サブジェクトの別名」という意味で、証明書が複数のホスト名やドメイン名で使用できるようにするためのフィールドです。例えば、1つの証明書で 「example.com」 や 「www.example.com」 のような複数のドメイン名に対応させたい場合に使用するものです。

SANに記述する内容は、そのサーバー証明書を設定・使用するサーバーを示すドメイン名・IPアドレス・URIなど。

※現在の主要ブラウザでは、証明書の検証において、コモンネームではなくSANの値を参照しているために、エラーが出たのかも？ 詳しいことは調べてみる必要がありそうです。。。

### SSL化の手順

1. SANを記載したopenssl.cnfを作成
2. 秘密鍵を生成
3. 証明書署名要求（CSR）を作成
4.  自己署名のSSL証明書を生成
5. 作成したSSL証明書と秘密鍵をウェブサーバーの設定ファイルに指定(default.conf)
6. HTTPでのアクセスをHTTPSにリダイレクトする設定を行う(default.conf)

---

以下からファイルの内容を紹介します。
SSLから紹介し、その後にDockerfileなどの内容記載します。

※SSLについては上記「SSL化の手順」を追いながら紹介します。

### SSL

``1. SANを記載したopenssl.cnfを作成``
```/.docker/web/ssl/openssl.cnf
[ req ]
default_bits        = 2048
default_md          = sha256
distinguished_name  = req_distinguished_name
req_extensions      = req_ext

[ req_distinguished_name ]
countryName                 = Country Name (2 letter code)
countryName_default         = JP
stateOrProvinceName         = State or Province Name (full name)
stateOrProvinceName_default = Tokyo
localityName                = Locality Name (eg, city)
localityName_default        = Shibuya
organizationName            = Organization Name (eg, company)
organizationName_default    = Laranext
commonName                  = Common Name (e.g. server FQDN or YOUR name)
commonName_default          = localhost

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1   = localhost
```

以下ブロックごとに説明します。
```
[ req ]
default_bits        = 2048
default_md          = sha256
distinguished_name  = req_distinguished_name
req_extensions      = req_ext
```

このセクションは、CSRを生成するための全体的な設定を定義しています。

以下詳細　↓↓

```
default_bits        = 2048
default_md          = sha256
```
秘密鍵の生成方法を記述。2048ビットとSHA-256ハッシュを使用するようにしている。

```
distinguished_name  = req_distinguished_name
```
証明書に含める識別名の詳細を指定しています。
（後述の [req_distinguished_name] セクションに内容を記述）

```
req_extensions      = req_ext
```
CSRに含める拡張情報（ここでSANを記述）を指定しています。
（後述の [req_ext] セクションに内容を記述）



```
[ req_distinguished_name ]
countryName                 = Country Name (2 letter code)
countryName_default         = JP
prefectureName              = Prefecture Name
prefectureName_default      = Tokyo
cityName                    = City Name
cityName_default            = Shibuya
organizationName            = Organization Name
organizationName_default    = Laranext
commonName                  = Common Name (e.g. server FQDN or YOUR name)
commonName_default          = localhost
```
証明書に含める識別情報（識別名）を定義しています。
ここでは、国名、件名、都市名、組織名、共通名などのデフォルト値を指定。


```
[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1   = localhost
```
この部分では、証明書署名要求（CSR）に拡張情報を追加するための設定を定義しています。具体的には、SANを設定しています。
```
[ req_ext ]
subjectAltName = @alt_names:
```
これは、CSRにSANフィールドを追加しています。
※@alt_names は、下記の[alt_names] セクションを参照しているということです。
```
[ alt_names ]
DNS.1   = localhost
```

このセクションで、代替名（SAN）のリストを定義します。各代替名は DNS.1, DNS.2 のように番号付きで指定されます。
ここでは、DNS.1 に localhost を指定して、localhost が代替名として有効になるようにします。

---

``2. 秘密鍵を生成``

OpenSSLを使用して秘密鍵を生成します。
/.docker/web/ssl ディレクトリ内に格納

下記コマンドで生成
```
$ openssl genrsa 2048 > self-signed.key
```
2048bitの秘密鍵を生成します。
self-sidgned.keyという名前になります。

※今回は、genrsaコマンドを使用していますが、genpkeyコマンドを使えば より詳細に鍵生成の方法を指定できるみたいです。



---


``3. 証明書署名要求（CSR）を作成``
作成したopenssl.cnfをもとに証明書署名要求（CSR）を作成します。
/.docker/web/ssl ディレクトリ内に格納

下記コマンドで生成
```
$ openssl req -new -key self-signed.key -out self-signed.csr -config openssl.cnf
```

---
``4. 自己署名のSSL証明書を生成``
自己署名のSSL証明書を生成を作成します。
/.docker/web/ssl ディレクトリ内に格納

下記コマンドで生成
```
openssl x509 -req -days 365 -in self-signed.csr -signkey self-signed.key -out self-signed.crt -extensions req_ext -extfile openssl.cnf
```
サーバ証明書に署名するにはopenssl x509コマンドを実行します。
これまでに作成した秘密鍵等を用いて自己署名でSSL証明書を生成します。
また、有効期限は365日としています。

この段階で、SSLディレクトリの中にこのようなファイルが作成されているはずです。

```
.
└── .docker
    └── web    
        └── ssl 
            │── openssl.cnf
            ├── self-signed.crt
            ├── self-sigend.csr
            └── self-signed.key
```
--- 

``5. 作成したSSL証明書と秘密鍵をウェブサーバーの設定ファイルに指定``
``6. HTTPでのアクセスをHTTPSにリダイレクトする設定を行う``

上記二項目とも default.confに記載する内容なので一緒に紹介します。

### default.conf

このdefault.confに、Nginxの設定を書き込みます。

```/.docker/web/default.conf
# HTTPからHTTPSへのリダイレクト設定
server {
    listen 80;
    server_name localhost;

    # HTTPをHTTPSへリダイレクト
    return 301 https://$host$request_uri;
}

# HTTPS設定
server {
    listen 443 ssl http2;
    server_name localhost;
    root /var/www/src/public;

    # ssl証明書のパス指定
    ssl_certificate /etc/nginx/ssl/self-signed.crt;
    ssl_certificate_key /etc/nginx/ssl/self-signed.key;

    # セキュリティヘッダー
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.php;
    error_log      /var/www/error.log warn;
    access_log     /var/www/access.log combined;

    charset utf-8;

    # リクエストの処理
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_pass app:9000;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

```
上から順に、ブロックごとに説明を行います。


```
# HTTPからHTTPSへのリダイレクト設定
server {
    listen 80;
    server_name localhost;

    # HTTPをHTTPSへリダイレクト
    return 301 https://$host$request_uri;
}
```
ここでは、HTTPからアクセスしたら、HTTPSへのリダイレクトを行うようになっています。
具体的には、下記内容です。
- Nginxがポート80（HTTP）でリクエストを受け付けるようにします。
- このサーバーブロックが処理するドメイン名を指定します。ここでは localhost に設定されています。
- HTTPリクエストが来たら、HTTPSに301リダイレクトするようにしています。

下記参照

https://improved-move.com/blogs/how_to_configure_https_redirect_and_why_you_need_it/


続いて、リダイレクト先のHTTPSの設定についての説明です。
```
# HTTPS設定
server {
    listen 443 ssl http2;
    server_name localhost;
    root /var/www/src/public;

    # ssl証明書のパス指定
    ssl_certificate /etc/nginx/ssl/self-signed.crt;
    ssl_certificate_key /etc/nginx/ssl/self-signed.key;

    # セキュリティヘッダー
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.php;
    error_log      /var/www/error.log warn;
    access_log     /var/www/access.log combined;

    charset utf-8;

    # リクエストの処理
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_pass app:9000;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}
```
細かい内容は下記
```
listen 443 ssl http2;
server_name localhost;
root /var/www/src/public;
```

- Nginxがポート443（HTTPS）でリクエストを受け付け、HTTP/2プロトコルを使用するようにする
- ここでもドメイン名を localhost に設定
- Nginxサーバーのドキュメントルートを設定

```
ssl_certificate /etc/nginx/ssl/self-signed.crt;
ssl_certificate_key /etc/nginx/ssl/self-signed.key;
```
- SSLに必要な「証明書」と「秘密鍵」を指定。

```
    # セキュリティヘッダー
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    # デフォルトのインデックスファイルを'index.php'に設定
    index index.php;

    # ログ設定
    error_log      /var/www/error.log warn;
    access_log     /var/www/access.log combined;

    # 文字エンコーディングの設定
    charset utf-8;

    # ルートリクエストの処理
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # 特定のファイルの処理
    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    # 404エラーページの設定
    error_page 404 /index.php;

    # PHPファイルの処理
    location ~ \.php$ {
        fastcgi_pass app:9000;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # 隠しファイルのアクセス制限
    location ~ /\.(?!well-known).* {
        deny all;
    }
```

上記コード内にコメントで簡単に説明書きを残しています。
こちらの内容は、下記記事のdefault.confを参考にさせていただきました。


https://qiita.com/hinako_n/items/f15646ea548bcdc8ac6c

---
以上で、SSLの設定は一通り終了です。
以下からは、残りのNginxに必要なファイルをサッと紹介します。


### Dockerfile
```/.docker/web/Dockerfile
FROM nginx:1.21.3

ENV TZ Asia/Tokyo

COPY ./.docker/web/ssl/self-signed.crt /etc/nginx/ssl/self-signed.crt
COPY ./.docker/web/ssl/self-signed.key /etc/nginx/ssl/self-signed.key
COPY ./.docker/web/default.conf /etc/nginx/conf.d/default.conf
```

- Nginx 1.21.3 の公式 Docker イメージをベースイメージとして使用
- SSL証明書と秘密鍵をコピーしてNginxサーバーがSSL証明書と鍵を使用できるようにする
- nginxの設定ファイル（default.conf）をコンテナ内にコピー

---

## 4. frontendコンテナ（Next.js）
続いて、フロントエンドコンテナに必要なファイルの紹介です。


### Dockerfile
``` ./frontend/Dockerfile
# ベースイメージとして Node.js を使用
FROM node:20.12.2

# 作業ディレクトリの設定
WORKDIR /app

# package.jsonとpackage-lock.jsonをコピー
COPY package*.json ./

# 依存関係をインストール
RUN npm install

# ソースコードをコピー
COPY . .

# ビルド
RUN npm run build

# ポートを公開
EXPOSE 3000

# Next.jsアプリケーションを起動
CMD ["npm", "start"]
```

ここも説明はコード内のコメントに簡単に記します。

--- 

以上までで、それぞれのコンテナに必要なファイルを紹介してきました。
最後にcompose.ymlファイルを紹介します。

# compose.yml
``` compose.yaml
version: "3.9"

services:
  # PHPコンテナ
  app:
    build:
      context: .
      dockerfile: ./.docker/app/Dockerfile
    working_dir: /var/www/src
    depends_on:
      - db
    volumes:
      - type: bind
        source: ./src
        target: /var/www/src
    # 依存するサービスとして 'db' を指定
    # ソースコードをバインドマウント

  # Nginxコンテナ
  web:
    build:
      context: .
      dockerfile: ./.docker/web/Dockerfile
    ports:
      - 80:80
      - 443:443
    depends_on:
      - app
    volumes:
      - type: bind
        source: ./.docker/web/default.conf
        target: /etc/nginx/conf.d/default.conf
      - type: bind
        source: ./.docker/web/ssl
        target: /etc/nginx/ssl
      - type: bind
        source: ./src
        target: /var/www/src
    # ポート80と443をホストに公開
    # 依存するサービスとして 'app' を指定
    # Nginx設定ファイルとSSLをバインドマウント

  # MySQLコンテナ
  db:
    build:
      context: .
      dockerfile: ./.docker/db/Dockerfile
    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: testdb
      MYSQL_USER: user
      MYSQL_PASSWORD: password
      TZ: Asia/Tokyo
    volumes:
      - type: volume
        source: db
        target: /var/lib/mysql
      - type: bind
        source: ./.docker/db/my.conf
        target: /etc/my.conf
      - type: bind
        source: ./.docker/db/init.sql
        target: /docker-entrypoint-initdb.d/init.sql
    # ポート3306をホストに公開
    # 環境変数でMySQLの設定を行う
    # データボリュームと設定ファイル、初期化スクリプトをバインドマウント

  # フロントエンドコンテナ（Next.js）
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    volumes:
      - type: bind
        source: ./frontend
        target: /app
    depends_on:
      - app
    # ポート3000をホストに公開
    # 依存するサービスとして 'app' を指定
    # フロントエンドのソースコードをバインドマウント

volumes:
  db:
    # データベースデータの永続化に使用するボリューム
```
※注意
MySQLコンテナについて：
environmentをここに直接記載していますが、実際の開発では、環境変数は .env に書いて、.gitignoreを行うのが安全です。

---

# Dockerイメージのビルドとコンテナの起動
ついにコンテナを起動していきます。
下記コマンドでイメージの作成とコンテナの起動を行います。
```
$ docker compose up -d --build
```

起動が完了したら、ちゃんと立ち上がっているか確認します。
```
$ docker ps
CONTAINER ID   IMAGE                              COMMAND                  CREATED          STATUS          PORTS
       NAMES
501fa8721add   for-code-study-laranext-web        "/docker-entrypoint.…"   29 seconds ago   Up 26 seconds   0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   for-code-study-laranext-web-1
b21cfd2391c6   for-code-study-laranext-frontend   "docker-entrypoint.s…"   29 seconds ago   Up 27 seconds   0.0.0.0:3000->3000/tcp
       for-code-study-laranext-frontend-1
6fde563fdff4   for-code-study-laranext-app        "docker-php-entrypoi…"   29 seconds ago   Up 27 seconds   9000/tcp
       for-code-study-laranext-app-1
9980972d3213   for-code-study-laranext-db         "docker-entrypoint.s…"   29 seconds ago   Up 28 seconds   0.0.0.0:3306->3306/tcp, 33060/tcp          for-code-study-laranext-db-1
```

# Laravelの準備
次に、PHPコンテナにLaravelをインストールします。
appコンテナに入り、コンテナ内でlaravelをインストールする下記コマンドを打ちます。
``composer create-project --prefer-dist laravel/laravel .``
```
$ docker compose exec app bash
root@6fde563fdff4:/var/www/src# composer create-project --prefer-dist laravel/laravel .
```
特にバージョンの指定はしていません。
これで、しばらく待てばLaravelプロジェクトが、ホスト側の/src配下にも作成されているはずです。

続いて、初めのマイグレーションを行ってMySQLと接続確認を行います。
appコンテナ内で``php artisan migrate``コマンドを打ちます。

```
root@6fde563fdff4:/var/www/src# php artisan migrate

   INFO  Preparing database.

  Creating migration table ..................................................................................................... 117.49ms DONE

   INFO  Running migrations.

  0001_01_01_000000_create_users_table ......................................................................................... 324.17ms DONE
  0001_01_01_000001_create_cache_table .......................................................................................... 93.62ms DONE
  0001_01_01_000002_create_jobs_table .......................................................................................... 318.51ms DONE
  2024_05_21_025934_create_personal_access_tokens_table ........................................................................ 391.21ms DONE
```

これで、該当するテーブルがDB内に作成されているはずです。

---


続いて、``https://localhost``にアクセスしてみましょう。
下記のようなLaravelのページが表示されていれば成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760062/f091d121-448e-b9e4-a88e-594ffb76ec57.png)

また、接続が保護されていることを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760062/750f1d17-8599-8f36-1f13-179c2f336527.png)

※もし、SSL化がうまくいっていない場合は下記記事などを参考に調査してみてください。

https://kinsta.com/jp/blog/your-connection-is-not-private/

# Next.jsの準備
続いて、Next.jsをインストールしていきます。

同じく、フロントエンドコンテナにはいり、Next.jsのインストールコマンドを打つだけです。

```
$ docker compose exec frontend bash
root@b21cfd2391c6:/app# npx create-next-app@latest .
```

こちらも、最新版をインストールしています。
インストールが終わったら``http://localhost:3000``にアクセスしてみましょう。

下記のような画面が表示されていたら成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760062/d1a51660-4b41-8b61-b569-9a6b8dd4f9c6.png)


# まとめ
今回は、LaravelとNext.jsの勉強用の環境構築手順を紹介しました。
今後は、この環境を使って、APIの準備だったりをしていこうと思っています。

また、環境構築についての理解を深めるために、webサーバーを置いて、SSL化させたりなどしましたが、もちろん、本番環境で使うにはまだまだ安全性に欠けた作りになっています。

セキュリティの観点は、サービス開発において非常に重要な点であるにもかかわらず、まだまだビギナーのうちは何となく後回しにしてしまいがちなところです。

これをきっかけにもっとサイトの安全性についても勉強していこうと思います。🐈

# 参照 
https://www.php.net/manual/ja/install.fpm.php

https://docs.docker.com/build/building/multi-stage/

https://qiita.com/hinako_n/items/f15646ea548bcdc8ac6c

https://entreprogrammer.jp/laravel-nginx-docker/

https://zenn.dev/bs_kansai/articles/3706c12408160c

https://www.php.net/manual/ja/configuration.file.php

https://it-blue-collar-dairy.com/mysql_on_docker-compose/

https://cn.teldevice.co.jp/blog/p39750/

https://www.bestssl.net/faq/install-nginx/

https://qiita.com/rumrais1n/items/8e6e62f4626c56ebfd12

https://jprs.jp/glossary/index.php?ID=0268

https://www.cybertrust.co.jp/blog/ssl/knowledge/certificate-errors04.html

https://qiita.com/rumrais1n/items/8e6e62f4626c56ebfd12

https://kaede.jp/2018/06/10191854/

https://improved-move.com/blogs/how_to_configure_https_redirect_and_why_you_need_it/

https://kinsta.com/jp/blog/your-connection-is-not-private/