「nginx + Webアプリ」のDocker環境にローカルから独自ドメインでアクセスする方法

インフラ

ローカル環境において、ドメイン名でWebアプリケーションに接続できる「nginx + Webアプリ」のDocker環境構築手順について紹介します。
なお、Docker ComposeでWebアプリケーションが起動できる前提とします。

今回は例としてhttp://web.local.example-dev.comでWebアプリケーションに接続できるDocker環境を構築します。

下準備

ローカル環境の/etc/hostsを編集する

localhost127.0.0.1を指すホスト名です。
任意のドメインでローカル環境を参照するには/etc/hosts127.0.0.1にドメインをマッピングします。

# 以下を追加する
127.0.0.1   web.local.example-dev.com

RailsでWebアプリを構築する場合: ホスト名によるアクセスをアプリケーション側で許可する

Rails 6以降1、DNSリバインディング攻撃からの保護のためデフォルトでは.localhost0.0.0.0::からのアクセスのみ許可されています。
ですので、設定ファイルにconfig.hosts << "web.local.example-dev.com"config.hosts.clearを追加してweb.local.example-dev.comでコンテナにアクセスできるように設定する必要があります。
設定をしないと[ActionDispatch::HostAuthorization::DefaultResponseApp] Blocked host: web.local.example-dev.comというエラーが発生します。
詳細解説はlocalhost以外のホスト名でローカル環境のRailsに接続する方法で紹介しています。

docker-compose.ymlにnginxコンテナを追加

docker-compose.ymlにnginxコンテナを追加します。

docker-compose.yml

version: '3'
services:
  app:
    ports:
      - '3001:3000'
    (略)
nginx:
  image: nginx:1.21
  ports:
    - '80:80'
  command: [nginx-debug, '-g', 'daemon off;']
  depends_on:
    - app

設定ファイルを追加する

nginxの設定ファイルは/etc/nginx/nginx.confです。
設定ファイルにはinclude /etc/nginx/conf.d/*.conf;という記述があり、/etc/nginx/conf.d/配下の.confという拡張子の設定が読み込まれます。

今回はnginxの/etc/nginx/conf.d/ディレクトリとローカルディレクトリをバインドマウントさせて設定ファイルを配置します。

docker-compose.yml

version: '3'
services:
  app:
  (略)
nginx:
  image: nginx:1.21
  ports:
    - '80:80'
  command: [nginx-debug, '-g', 'daemon off;']
+  volumes:
+    - ./nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf

nginxの設定ファイルを編集

server_nameディレクティブを利用するとserverブロックで処理するリクエストのドメインを指定できます。server_nameディレクティブでは完全一致、ワイルドカード、正規表現が利用できます。2
リクエストのプロキシはproxy_passで行います。

80番ポートで受け取ったweb.local.example-dev.comのリクエストをappコンテナの3000番ポートへプロキシする設定は以下の通りです。

nginx/conf.d/default.conf

server {

  ### 80番ポートをlisten
  listen 80;

  ### 『web.local.example-dev.com』からのリクエストを処理する
  server_name  web.local.example-dev.com;

  ### "/"にアクセスがあったときの処理
  location / {

    ### リクエストヘッダに$hostをセット
    # $host: Hostリクエストヘッダがあればそのサーバ名、なければプライマリサーバ名(server_name)
    proxy_set_header Host $host;

    ### appコンテナの3000ポートにリクエストを送る
    proxy_pass http://app:3000;
  }
}

さいごに

Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!

参考資料