IT

【Nginx】リバースプロキシと複数コンテナの設定方法と落とし穴

この記事では、Nginxを使用してリバースプロキシを設定し、単一サーバにて複数のコンテナアプリケーションをルーティングする方法について説明します。

同一ドメイン上で異なるパスを持つ複数のアプリケーションを提供する際の注意点も含めています。

目的

一台のサーバ内でコンテナアプリをポートをずらして複数起動し、リバースプロキシを介してルーティングさせる。

目的としては、少しだけ差異のあるアプリケーションを同一ドメインでPathを可変にして提供することが目的です。

実行イメージ

  • http://example.com

→Nginx が 404 のエラーを吐く

  • http://example.com/app_1

→ ポート 5001 で起動したコンテナアプリにアクセスできる

  • http://example.com/app_2

→ ポート 5002 で起動したコンテナアプリにアクセスできる

ディレクトリ構成

/home/
├── app_1/
│   ├── Dockerfile
│   ├── app.py
│   └── requirements.txt
├── app_2/
│   ├── Dockerfile
│   ├── app.py
│   └── requirements.txt
└── docker-compose.yml

アプリケーション関連

重要ポイント

通常のWebアプリケーションでは、ルートパスを"/"や"/login"のように設定しますが、Nginxのリバースプロキシ設定と合わせるために、アプリケーション側のルーティングを適切に設定する必要があります。

設定を実施しないと、それぞれのアプリケーションがドメイン自体を参照してしまい強制404祭りになります。

以下の例では、各アプリケーションのベースパスをハードコードしていますが、実際の運用では環境変数を使用してより柔軟に管理することをおすすめします。

  • docker-compose.yml
services:
  app_1:
    build: ./app_1
    ports:
      - "5001:5001"
  app_2:
    build: ./app_2
    ports:
      - "5002:5002"
  • Dockerfile
FROM python:3.12-slim
WORKDIR /app
RUN pip install flask
COPY . .
CMD ["python", "app.py"]
  • app_1/app.py
from flask import Flask

app = Flask(__name__)

@app.route('/app_1/')
def hello():
    return "Hello from App 1!"

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5001)
  • app_2/app.py
from flask import Flask

app = Flask(__name__)

@app.route('/app_2/')
def hello():
    return "Hello from App 2!"

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5002)

Nginxの設定

  • インストール自体は公式ドキュメントの通り
  • サーバ内で https 対応する場合にはLet's Encrypt 等で証明書を突っ込み設定をいじる必要があります。

リバースプロキシの設定

/etc/nginx/sites-available/ディレクトリに以下の内容の設定ファイル(例:docker-setting)を作成します

server {
    listen 80;
    server_name example.com;

    location / {
        try_files $uri $uri/ =404;
    }

    location /app_1 {
        proxy_pass http://localhost:5001;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /app_2 {
        proxy_pass http://localhost:5002;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

設定の有効化と反映

  • 上記のファイルに対してシンボリックリンクを設定

sudo ln -s /etc/nginx/sites-available/docker-setting /etc/nginx/sites-enabled/

  • 設定ファイルのシンタックスチェックと設定読み込み

sudo nginx -t

sudo systemctl reload

おまけ

localhostを指定しているので、ローカル環境で該当ポートを開いている場合にはそちらが参照される場合があります。

対策としては、Docker側でNetWorkを設定しそちらを参照させる方法と、マシン自体のIP(例:proxy_pass http://172.17.0.1:5000;)を参照するように修正することでこの事象は回避できます。

まとめと学んだこと

リバースプロキシの設定では、単にポートを指定するだけでなく、アプリケーション側のルーティングとNginxの設定を適切に合わせることが重要です。「配下にあるからあとはよしなになっている」と思い込むのは危険で、細部まで注意を払う必要があります。

この経験から、以下の点を学びました。

  1. アプリケーションとNginxの設定を整合させることの重要性
  2. ルーティングの詳細な理解の必要性
  3. 想定外の動作に対する冷静な分析と対応の重要性

この記事が、同様の設定に取り組む方々の助けになれば幸いです。

  • この記事を書いた人

緑川縁

ニートからシステムエンジニアになった人
クラウド案件をメインにやっています。
保持資格:CCNA,AWS SAA&SAP,秘書検定2級
趣味でボカロ曲作り始めました。

-IT
-