Apache + Passenger + Docker + Docker-composeでRuby on Railsの環境を構築

# 概要
`Docker`と`Docker Compose`を使用して、`Apache`サーバー上に`Phusion Passenger`を動作させ、`Ruby on Rails`を展開する環境を構築します。今のこのご時世にこの構成で`Rails`を動かす事はほぼないと思っておりますので、構築手順は、シンプルに記載します。

# Apacheの概要
`Apache`は、`HTTP`サーバーの一つであり、クライアントからの`HTTP`リクエストを受け取り、ウェブページやウェブコンテンツを提供する役割を果たす

https://httpd.apache.org/

# Phusion Passengerの概要
`Apache`や`Nginx`等の`web`サーバーと連携して使用する。`Passenger`は`Web Application`を処理する為の`Application`サーバーとして機能し、`web`サーバー（`Apache`や`Nginx`）と連携する事で、リクエストの受け入れ、アプリケーションの処理、レスポンスの送信を行う

https://www.phusionpassenger.com/docs/tutorials/fundamental_concepts/ruby/

# 前提条件
以下がインストールされている事が前提です。
- Docker Desktop
- Visual Studio Code

# ディレクトリー構成
```sh
.
├── apache/
│   ├── conf-available/
│   │   └── fqdn.conf
│   ├── mods-available/
│   │   └── passenger.conf
│   ├── mods-available/
│   │   └── passenger.load
│   ├── .htaccess
│   ├── ports.conf
│   └── virtual_host_enabler.sh
├── backend/
│   ├── conf/
│   │   ├── .env
│   │   └── database.yml
│   ├── web１/
│   │   ├── # その他Railsの設定ファイル
│   │   ├── InitDockerfile ← 新規のRailsを立ち上げる為に使用した
│   │   └── Dockerfile
│   └── web２/ 
│       └── # その他Railsの設定ファイル/
│           └── Dockerfile
├── db/
│   ├── conf/
│   │   └── .env
│   └── postgres_volume ← 自動生成  
└── docker-compose.yml

```



# 構築ファイル
## Apacheの設定
- 任意で指定したドメインからアクセスできるように設定
```/conf-available/fqdn.conf
ServerName 任意のドメイン名
# 入力例
127.0.0.1 web１.localhost.com
```

```/sites-available/web1.conf
<VirtualHost *:3000>
  ServerAdmin webmaster@localhost
  DocumentRoot /backend/web1/public

  <Directory "/backend/web1/public">
    AllowOverride all
    Require all granted
    Options MultiViews
    RailsEnv development
  </Directory>

  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

```

```ports.conf
Listen 3000

<IfModule ssl_module>
        Listen 443
</IfModule>

<IfModule mod_gnutls.c>
        Listen 443
</IfModule>
```


- `sites-available`にある`000-default.conf`と`default-ssl.conf`、以外の`confファイル`を有効にする
（Apacheのデフォルト設定で、`000-default.conf`と`default-ssl.conf`は無視される）
```virtual_host_enabler.sh
#!/bin/sh

default_name="000-default"
default_ssl_name="default-ssl"

dir_path="/etc/apache2/sites-available"
dirs=`find $dir_path -type f -name *.conf`

for dir in $dirs;
do
    filename=`basename $dir .conf`
    if [ $filename = $default_name ]; then
        continue
    elif [ $filename = $default_ssl_name ]; then
        continue
    else
        a2ensite $filename
    fi
done

```

## Passengerの設定
```/mods-available/passenger.conf
<IfModule mod_passenger.c>
  PassengerRoot /usr/local/bundle/gems/passenger-バージョン
  PassengerDefaultRuby /usr/local/bin/ruby
  PassengerInstanceRegistryDir /tmp
  PassengerUserSwitching off
  PassengerDefaultUser root
  PassengerDisableSecurityUpdateCheck on
  PassengerSpawnMethod smart
  PassengerFriendlyErrorPages on
  PassengerPoolIdleTime 0
</IfModule>

# バージョンは、インストールしたpassengerのバージョンを記載する
# 基本的には、最新のpassengerをインストールする事を推奨する
```

```/mods-available/passenger.load
LoadModule passenger_module /usr/local/bundle/gems/passenger-バージョン/buildout/apache2/mod_passenger.so

# バージョンは、インストールしたpassengerのバージョンを記載する
# 基本的には、最新のpassengerをインストールする事を推奨する
```
- [passengerのバージョン](https://rubygems.org/gems/passenger/versions/2.2.7?locale=ja)

```.htaccess
# リダイレクトのテスト
Redirect /jp/ https://www.google.com/

# シンボリックリンク（ショートカットとも呼ばれます）を追跡することを許可する
Options +FollowSymLinks

<IfModule mod_rewrite.c>
    # CORS設定
    <IfModule mod_headers.c>
        Header set Access-Control-Allow-Origin "*"
        Header set Access-Control-Allow-Credentials "true"
    </IfModule>
</IfModule>

# Access-Control-Allow-Origin : すべてのオリジンからのリクエストを許可する
# Access-Control-Allow-Credentials : リクエストの資格情報（クッキー、HTTP認証、クライアントSSL証明書など）を送信する際、そのレスポンスがフロントエンドのJavaScriptコードに公開されるかどうかを制御する

# オリジンとは
# https://www.example.com:443は一つのオリジン
# httpsはプロトコル、www.example.comはホスト、443はポート
```

## Dockerfileの設定
- `/backend/web1`に記載してあるDockerfile
```Dockerfile
ARG RUBY_VERSION=3.3.0
FROM ruby:${RUBY_VERSION}-slim-bookworm

# タイムゾーン設定
ENV LANG=C.UTF-8 \
    TZ=Asia/Tokyo

RUN mkdir -p /backend/web1
WORKDIR /backend/web1

# パッケージインストール
RUN apt-get update && apt-get install -y \
    git \
    vim \
    curl \
    build-essential \
    nodejs \
    libpq-dev \
    apache2 \
    apache2-dev \
    ruby-dev \
    libcurl4-openssl-dev \
    libpcre3-dev \
    && apt-get clean \
    && rm -r /var/lib/apt/lists/*

# apacheをセットアップする為に必要なファイル
COPY ./apache/sites-available /etc/apache2/sites-available
COPY ./apache/ports.conf /etc/apache2/ports.conf
COPY ./apache/conf-available/fqdn.conf /etc/apache2/conf-available/fqdn.conf
COPY ./apache/mods-available/passenger.conf /etc/apache2/mods-available/passenger.conf
COPY ./apache/mods-available/passenger.load /etc/apache2/mods-available/passenger.load
COPY ./apache/virtual_host_enabler.sh /backend

# railsのセットアップ
COPY ./backend/web1/Gemfile /backend/web1/Gemfile
COPY ./backend/web1/Gemfile.lock /backend/web1/Gemfile.lock
COPY ./backend/web1 /backend/web1

# .htaccessのファイルをコピー
COPY ./apache/.htaccess /backend/web1/public/.htaccess

# passengerとapache関連
RUN gem install passenger
RUN passenger-install-apache2-module

# railsのセットアップ
RUN bundle install
# .htaccessを有効化
RUN a2enmod rewrite
# .htaccessに記述したheader要素の有効化
RUN a2enmod headers
# passenger.loadファイルを有効化
RUN a2enmod passenger
# proxyモジュールを有効化
RUN a2enmod proxy_http
# fqdnモジュールを有効化
RUN a2enconf fqdn

RUN a2dissite 000-default \
    && sh /backend/virtual_host_enabler.sh

# apacheリスタート
RUN service apache2 restart
CMD ["apachectl", "-D", "FOREGROUND"]

```

- `/backend/web2`に記載してある`Dockerfile`
<font color="red">**※`web2`は`puma`を使用して`Rails`を起動させています**</font>
```Dockerfile
ARG RUBY_VERSION=3.3.0
FROM ruby:${RUBY_VERSION}-slim-bookworm

ENV LANG=ja_JP.UTF-8 \
    TZ=Asia/Tokyo

RUN apt-get update && apt-get install -y \
    build-essential \
    curl \
    git \
    nodejs \
    vim \
    libpq-dev \
    && apt-get clean \
    && rm -r /var/lib/apt/lists/*

WORKDIR /web2
COPY Gemfile /web2/Gemfile
COPY Gemfile.lock /web2/Gemfile.lock
RUN bundle install

```

## docker-compose.ymlの設定
- 不要であれば、`web2`、`pgadmin`の記述を消去して問題ないです
```docker-compose.yml
version: "3.9"
services:
  db:
    container_name: pgsql
    image: postgres:latest
    env_file: ./db/conf/.env
    volumes:
      - ./db/postgres_volume:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    restart: always
  web1:
    container_name: web1
    build:
      context: ./
      dockerfile: ./backend/web1/Dockerfile
    env_file: ./backend/conf/.env
    ports:
      - 3000:3000
    volumes:
      - ./backend/web1:/web1
      - ./backend/conf/database.yml:/backend/web1/config/database.yml
      - ./apache/.htaccess:/backend/web1/public/.htaccess
    depends_on:
      - db
    tty: true
    stdin_open: true
  web2:
    container_name: web2
    build: ./backend/web2
    env_file: ./backend/conf/.env
    ports:
      - 3001:3001
    volumes:
      - ./backend/web2:/web2
      - ./backend/conf/database.yml:/web2/config/database.yml
    depends_on:
      - db
    tty: true
    stdin_open: true
    command: >
      bash -c "
        rm -f rm -f tmp/pids/server.pid &&
        rails db:migrate &&
        bundle exec rails s -p 3001 -b '0.0.0.0'
      "
  pgadmin:
    container_name: pgadmin
    image: dpage/pgadmin4
    restart: always
    env_file:
      - ./pgadmin/conf/.env
    volumes:
      - ./pgadmin/pgadmin_volume:/var/lib/pgadmin
    depends_on:
      - db
    ports:
      - 8081:80
volumes:
  db_volume: {}
  pgadmin_volume: {}

```

## /etc/hostsの設定
```sh
vim /etc/hosts

# 下記はvimでの表示画面

127.0.0.1 fqdn.confで設定したドメイン名
#　入力例
127.0.0.1 web1.localhost.com
```

## index.htmlの設置
- `public/`の配下に`index.html`を設置する
```index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>Welcome Index.html page</h1>
  </body>
</html>

```

## 動作
- ブラウザー or CLIからHTMLファイルの内容が表示されたら完了
```sh
# CLI等のターミナル
curl http://web1.localhost.com:3000/index.html
```

```sh
# ブラウザー
http://web1.localhost.com:3000/index.html
```

## 補足
:::note warn
- `Apache` + `Passenger`を正常に接続してもRailsは起動しない。もう少し具体的に述べると環境構築完了時に表示される`Welcome Rails`の画面が表示されない
- 表題の構成を立ち上げた際は、`Rails`を`API`として使用する以外、使用できないと考えて頂いて問題はない
:::

# 筆者が作成したディレクトリ
https://github.com/kengo-sk8/docker_apache_passenger_rails_environment

# 参考資料
## 環境構築関連
- [Docker Rails + Reactの本番環境構築(ubuntu + Apache + rails + React + MySQL)](https://qiita.com/NNKK1234/items/bcd88e030403215348a8)
- [Ruby on Railsアプリが動くApache Passenger Postgresql環境をdockerでつくる](https://qiita.com/itagakishintaro/items/7bad20470f7942c116c4)
- [Rails+Passenger+Debian](https://qiita.com/ryokubozono/items/e9451e88f7ab5f7c11ca)


## apache関連
- [dockerで構築したapacheでHeader関係の関数が使えない件の対応](https://blog.websandbag.com/entry/2017/11/04/212907)
- [Docker で Apache .htaccess の挙動を確認してみる](https://qiita.com/mochizukikotaro/items/57c429d5fd6ab8725868)
- [.htaccess 効いてるか 確認する方法](https://it-afi.com/apache/htaccess-%E5%8A%B9%E3%81%84%E3%81%A6%E3%82%8B%E3%81%8B-%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/)
- [dockerで構築したapacheでHeader関係の関数が使えない件の対応](https://blog.websandbag.com/entry/2017/11/04/212907)
- [htaccessがどうしても効かないときの対処法】Apacheのデフォルト設定をチェック！](https://takabus.com/tips/2661/)
- [UbuntuにてApacheのモジュールを有効化する](https://www.t3a.jp/blog/infrastructure/apache2-mod-add/)

## Phusion passenger関連
- [[Phusion passenger公式]Configuration reference](https://www.phusionpassenger.com/library/config/apache/reference/#configuration-reference-for-passenger-+-apache)
- [Phusion passenger Security check update holding connection](https://stackoverflow.com/questions/60414033/phusion-passenger-security-check-update-holding-connection)
- [PassengerDisableSecurityUpdateCheck](https://www.phusionpassenger.com/library/config/apache/reference/#passengerdisablesecurityupdatecheck)
- [Phusion Passenger: permission denied で ruby を実行できない問題](https://tkrd.hatenablog.com/entry/2017/07/18/121511)
- [PassengerDefaultUser](https://www.phusionpassenger.com/library/config/apache/reference/#passengerdefaultuser)
- [Passenger　ユーザースイッチングを利用できる要件](https://ameblo.jp/hbnizm31/entry-11708905395.html)
- [Passenger はどのユーザーアカウントで動くのか？](https://yuumi3.hatenablog.com/entry/20090312/1236871330)

# まとめ
今回は、表題の開発環境を作成しました。`Apache`、`Passenger`について詳しくなれたのでとても良い学びでした。また、新しい開発環境を作成する機会があれば記事にしたいと思います。