2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

conoha-cliでnginxリバースプロキシをConoHa VPSにワンコマンドデプロイ — 教育用プロキシ設定サンプル

2
Posted at

はじめに

「リバースプロキシって何をしてるの?」「X-Forwarded-For とか X-Real-IP って何?」——Webインフラを学ぶとき、nginx のリバースプロキシ設定は避けて通れないテーマです。しかし、設定ファイルを読むだけでは理解しにくく、実際にリクエストを飛ばしてヘッダーやレスポンスを確認して初めて「なるほど」と腹落ちするものです。

この記事では、教育用に設計したnginxリバースプロキシのサンプルを、ConoHa VPS3上に conoha app deploy ワンコマンドでデプロイする方法を紹介します。

単なるプロキシ転送だけでなく、以下のような実務で頻出するリバースプロキシ機能を1つの nginx.conf にまとめています。

  • Forwarded Headers(X-Real-IP、X-Forwarded-For など)
  • セキュリティヘッダー(X-Content-Type-Options、X-Frame-Options など)
  • Rate Limiting(IPごとのリクエスト制限)
  • IP Filtering(特定IPのブロック)
  • 機密パスのブロック.env.git へのアクセス拒否)
  • CORS設定
  • ヘッダー確認用デバッグエンドポイント

デプロイには conoha-cli を使います。サーバー作成からアプリ起動まで、手元のターミナルだけで完結します。


conoha-cli とは

conoha-cli は、ConoHa VPS3 をターミナルから操作するためのCLIツールです。

主な機能

  • サーバー管理: VPSの作成・削除・一覧表示
  • app deploy: compose.yml があるディレクトリをVPSにデプロイ
  • app logs: コンテナログのリアルタイム表示
  • app status: コンテナの稼働状態確認
  • 環境変数管理: app env set でセキュアに環境変数を注入

app deploy コマンドは内部でDockerとDocker Composeを自動セットアップし、ディレクトリをgit push形式でVPSへ転送してコンテナを起動します。SSHキーさえ設定すれば、コマンド1本でデプロイが完了します。


構成

サービス 技術 役割
proxy nginx:alpine リバースプロキシ(ポート80)
app1 Node.js 24 (Alpine) フロントエンド(/
app2 Python 3.13 (slim) APIサーバー(/api/

アーキテクチャ

ブラウザ → :80 → [nginx (proxy)]
                     ├── /          → [app1 (Node.js :3000)]
                     ├── /api/      → [app2 (Python :8000)]
                     ├── /debug/headers → [app2 (ヘッダー確認)]
                     ├── /health    → nginx直接応答
                     └── /.env, /.git → 404 ブロック

nginx が全リクエストを受け、パスに応じて適切なバックエンドにルーティングします。


前提条件

  • conoha-cli がインストール済み
  • ConoHa VPS3 アカウント
  • SSH キーペア設定済み(conoha keypair create で作成可能)

ファイル構成

nginx-reverse-proxy/
├── compose.yml       # 3サービス定義
├── nginx.conf        # リバースプロキシ設定(本記事のメイン)
├── app1/
│   ├── Dockerfile    # Node.js 24 Alpine
│   └── app.js        # フロントエンドHTML + ヘッダー確認UI
└── app2/
    ├── Dockerfile    # Python 3.13 slim
    └── app.py        # APIサーバー + /debug/headers エンドポイント

nginx.conf — リバースプロキシ設定の詳細解説

この nginx.conf が本記事のメインコンテンツです。実務で頻出するリバースプロキシの設定パターンを1つのファイルにまとめています。

Rate Limiting

limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=api:10m rate=5r/s;

IPアドレスごとにリクエストレートを制限します。フロントエンドは秒間10リクエスト、APIはより厳しく秒間5リクエストに設定しています。$binary_remote_addr を使うことで、文字列IPより省メモリで管理できます。

location / {
    limit_req zone=general burst=20 nodelay;
    ...
}

location /api/ {
    limit_req zone=api burst=10 nodelay;
    ...
}

burst は制限超過時の待機列サイズ、nodelay はバースト分を即座に処理する設定です。

IP Filtering

geo $blocked_ip {
    default 0;
    # 192.168.100.0/24 1;   # example: block this subnet
    # 10.0.0.5 1;            # example: block single IP
}

server {
    if ($blocked_ip) {
        return 403;
    }
}

geo ディレクティブでIPアドレスやサブネット単位のブロックリストを定義します。コメントアウトを外すだけで有効化できます。

Forwarded Headers

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;
proxy_set_header X-Forwarded-Host  $host;
proxy_set_header X-Forwarded-Port  $server_port;
proxy_set_header X-Request-ID      $request_id;
ヘッダー 説明
X-Real-IP クライアントの実IPアドレス
X-Forwarded-For プロキシチェーン全体のIPリスト。CDNやロードバランサーが前段にある場合、カンマ区切りで追加される
X-Forwarded-Proto クライアントが使用したプロトコル(http/https)。バックエンドでHTTPS判定に利用
X-Forwarded-Host クライアントがリクエストしたホスト名
X-Forwarded-Port クライアントがアクセスしたポート番号
X-Request-ID nginxが自動生成するリクエスト固有のID。ログ追跡やマイクロサービス間のトレーシングに利用

Security Headers

add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Served-By "nginx-reverse-proxy-demo" always;
ヘッダー 効果
X-Content-Type-Options: nosniff ブラウザのMIMEタイプスニッフィングを防止
X-Frame-Options: SAMEORIGIN 他サイトからの <iframe> 埋め込みを防止(クリックジャッキング対策)
X-XSS-Protection: 1; mode=block ブラウザのXSSフィルターを有効化
Referrer-Policy リファラー情報の送信ポリシーを制御
X-Served-By どのプロキシを経由したか識別するカスタムヘッダー

CORS

location /api/ {
    add_header Access-Control-Allow-Origin  "*" always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;

    if ($request_method = OPTIONS) {
        return 204;
    }
}

APIパスにCORSヘッダーを付与し、異なるオリジンからのJavaScriptリクエストを許可します。OPTIONS リクエスト(プリフライト)には 204 No Content で即座に応答します。

機密パスのブロック

location ~ /\.(env|git|htpasswd) {
    return 404;
}

.env(環境変数ファイル)、.git(リポジトリ情報)、.htpasswd(認証ファイル)へのアクセスをブロックします。デプロイ時にこれらのファイルが意図せず公開されるリスクを防ぎます。

ヘッダー確認用デバッグエンドポイント

location /debug/headers {
    proxy_pass http://app2;
    # ... 全Forwarded Headersを転送
}

バックエンド(Python)がリクエストヘッダーをJSON形式で返します。プロキシが何を転送しているのかを実際に確認できる教育用エンドポイントです。


compose.yml

services:
  proxy:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - app1
      - app2

  app1:
    build: ./app1

  app2:
    build: ./app2

nginx の設定ファイルは volumes でリードオンリーマウントしています。depends_on により、app1 と app2 が先に起動してから nginx が起動します。


デプロイ手順

1. リポジトリのクローン

git clone https://github.com/crowdy/conoha-cli-app-samples.git
cd conoha-cli-app-samples/nginx-reverse-proxy

2. サーバー作成(既存サーバーがあればスキップ)

conoha server create --name myserver --flavor g2l-t-1 --image ubuntu-24.04 --key mykey --wait

1GB RAM(g2l-t-1)で十分動作します。

3. アプリ初期化

conoha app init myserver --app-name reverse-proxy
Initializing app "reverse-proxy" on vm-18268c66-ae (133.88.116.147)...
==> Installing Docker...
==> Installing Docker Compose plugin...
==> Installing git...
==> Creating directories...
==> Installing post-receive hook...
==> Done!

4. デプロイ

conoha app deploy myserver --app-name reverse-proxy
Archiving current directory...
Uploading to vm-18268c66-ae (133.88.116.147)...
Building and starting containers...
 Image reverse-proxy-app1 Building
 Image reverse-proxy-app2 Building
 ...
 Container reverse-proxy-app1-1 Started
 Container reverse-proxy-app2-1 Started
 Container reverse-proxy-proxy-1 Started
Deploy complete.

動作確認

コンテナ状態

conoha app status myserver --app-name reverse-proxy
NAME                      IMAGE                  STATUS        PORTS
reverse-proxy-app1-1      reverse-proxy-app1     Up            3000/tcp
reverse-proxy-app2-1      reverse-proxy-app2     Up            8000/tcp
reverse-proxy-proxy-1     nginx:alpine           Up            0.0.0.0:80->80/tcp

各エンドポイントの確認

フロントエンド(App 1 → Node.js):

$ curl -sI http://<サーバーIP>/

X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
X-Served-By: nginx-reverse-proxy-demo

セキュリティヘッダーが付与されていることが確認できます。

API(App 2 → Python):

$ curl -sI http://<サーバーIP>/api/hello

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization

CORSヘッダーが付与されています。

ヘッダーデバッグ — プロキシが転送するヘッダーの可視化:

$ curl -s http://<サーバーIP>/debug/headers | python3 -m json.tool
{
    "headers": {
        "Host": "133.88.116.147",
        "X-Real-IP": "210.172.128.230",
        "X-Forwarded-For": "210.172.128.230",
        "X-Forwarded-Proto": "http",
        "X-Forwarded-Host": "133.88.116.147",
        "X-Forwarded-Port": "80",
        "X-Request-ID": "396ca3a7623519ee9b914661d1292f5d",
        "User-Agent": "curl/8.5.0",
        "Accept": "*/*"
    }
}

自分のIPアドレスが X-Real-IPX-Forwarded-For に入っていること、リクエストごとにユニークな X-Request-ID が生成されていることが確認できます。

機密パスのブロック:

$ curl -sI http://<サーバーIP>/.env
HTTP/1.1 404 Not Found

$ curl -sI http://<サーバーIP>/.git
HTTP/1.1 404 Not Found

.env.git へのアクセスはブロックされています。

ヘルスチェック:

$ curl -s http://<サーバーIP>/health
{"status":"ok"}

機能一覧

機能 説明 確認方法
X-Real-IP / X-Forwarded-For クライアントの実IPをバックエンドに転送 /debug/headers で確認
X-Forwarded-Proto/Host/Port プロキシ経由情報をバックエンドに転送 /debug/headers で確認
X-Request-ID リクエストごとのユニークID(トレーシング用) /debug/headers で確認
Security Headers X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, Referrer-Policy レスポンスヘッダーで確認
X-Served-By カスタムヘッダー(どのプロキシ経由か表示) レスポンスヘッダーで確認
Rate Limiting フロント 10r/s、API 5r/s に制限 limit_req_zone 設定
IP Blocking geo $blocked_ip でIP/サブネット単位でブロック可能 nginx.conf で有効化可能
機密パスブロック /.env, /.git, /.htpasswd へのアクセスを404で拒否 /.env → 404 で確認
CORS /api/ パスにCORSヘッダー付与 レスポンスヘッダーで確認
Headers Debug /debug/headers でプロキシ転送ヘッダーを可視化 JSON出力で確認

教育用として使うポイント

このサンプルは以下のような学習シナリオで活用できます。

1. Forwarded Headersの理解

/debug/headers にアクセスして、プロキシが何を転送しているかを実際に確認できます。VPN経由やモバイルからアクセスすると X-Real-IP が変わることを体験できます。

2. セキュリティヘッダーの効果

ブラウザのDevToolsでレスポンスヘッダーを確認し、各ヘッダーがどのような攻撃を防ぐのかを学べます。ヘッダーを1つずつコメントアウトして、ブラウザの挙動がどう変わるか試してみるのも有効です。

3. Rate Limitingの体験

# 連続リクエストを送信して制限を体験
for i in $(seq 1 20); do curl -s -o /dev/null -w "%{http_code}\n" http://<IP>/api/hello; done

制限を超えると 503 Service Temporarily Unavailable が返ります。

4. IP Filteringのテスト

nginx.confgeo $blocked_ip に自分のIPを追加し、再デプロイすることでブロックの動作を確認できます。


まとめ

conoha app initconoha app deploy の2コマンドで、教育用のnginxリバースプロキシ環境をConoHa VPS3上に構築できました。

アクセス先 URL
フロントエンド(Node.js) http://<IP>/
API(Python) http://<IP>/api/hello
ヘッダー確認 http://<IP>/debug/headers
ヘルスチェック http://<IP>/health

リバースプロキシの設定は読むだけでは理解しにくいですが、実際にデプロイしてリクエストを飛ばし、ヘッダーの変化を目で見ることで格段に理解が深まります。ぜひ手元でデプロイして試してみてください。

サンプルのソースコードは以下で公開しています。

他にもWordPress、Strapi、Next.js + FastAPI、Outline、Quickwit + OpenTelemetryなど30種類以上のサンプルが揃っていますので、ぜひ試してみてください。

参考

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?