nginx

nginxでWebアプリの管理画面をIPアドレスで制限する方法

nginx セキュリティ Docker

nginxでWebアプリの管理画面を
IPアドレスで制限する方法

DjangoやRailsなどのWebアプリケーションを公開するとき、管理画面(/admin/など)は誰でもアクセスできる状態にしておくべきではありません。
この記事では、nginxのリバースプロキシでIPアドレスによるアクセス制限を設定する方法を解説します。

こんな人向けの記事です

  • VPSでWebアプリケーションを公開している(またはこれから公開する)
  • 管理画面へのアクセスを自分だけに制限したい
  • nginxをリバースプロキシとして使っている

なぜ管理画面のアクセス制限が必要なのか

Webアプリケーションの管理画面は、データの作成・編集・削除ができる強力な機能を持っています。攻撃者にとっては最も価値の高い標的です。

管理画面がインターネット上で誰でもアクセスできる状態だと、以下のリスクがあります。

  • ブルートフォース攻撃: ログインフォームにパスワードを総当たりで試行
  • 脆弱性の悪用: 管理画面フレームワーク自体の脆弱性を狙った攻撃
  • 情報漏洩: ログインページの存在自体が、使用しているフレームワークの情報を与える

そもそも管理画面にアクセスできなければ、これらの攻撃は成立しません。IPアドレスで制限することで、ネットワークレベルで管理画面を保護できます。

構成イメージ

nginxが全てのリクエストを受け取り、URLパスに応じてアクセス制御を行います。

リクエストの流れ
ブラウザ → nginx(80番ポート) → アプリケーション(8000番ポート)

/admin/ /manage/ → 許可されたIPのみ通過、それ以外は 403 Forbidden
/ (一般ページ)→ 全てのIPからアクセス可能

アプリケーション(gunicornなど)は外部に直接ポートを公開せず、nginxのみが外部からのリクエストを受け付けます。これにより、IP制限を確実に適用できます。

nginx の設定ファイルを作成する

nginxの envsubst 機能を使って、環境変数 ADMIN_IP から許可するIPアドレスを設定ファイルに埋め込みます。

nginx.conf.template
server {
    listen 80;

    # 管理画面: 特定IPのみ許可
    location /admin/ {
        allow ${ADMIN_IP};
        deny all;

        proxy_pass http://web:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location /manage/ {
        allow ${ADMIN_IP};
        deny all;

        proxy_pass http://web:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # 一般ページ: 全員アクセス可
    location / {
        proxy_pass http://web:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

設定のポイント

  • allow に許可するIPアドレスを指定し、deny all でそれ以外を拒否
  • location ブロックはパスごとに独立して設定できる
  • \${ADMIN_IP} はnginxコンテナ起動時に環境変数から置換される
  • 制限したいパスが増えた場合は、location ブロックを追加するだけ

nginx の Dockerfile

テンプレートファイルを /etc/nginx/templates/ に配置すると、nginxの公式Dockerイメージが起動時に自動で envsubst を実行してくれます。

nginx/Dockerfile
FROM nginx:alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf.template /etc/nginx/templates/default.conf.template

Docker Compose での構成

Docker Compose を使ってnginxとWebアプリケーションを連携させます。

.env
# 管理画面にアクセスを許可するIPアドレス
ADMIN_IP=あなたのグローバルIPアドレス
docker-compose.yml
services:
  web:
    build: .
    expose:
      - "8000"    # 外部に公開しない(nginxのみが接続)

  nginx:
    build: ./nginx
    ports:
      - "80:80"   # nginxだけが外部公開
    environment:
      - ADMIN_IP=\${ADMIN_IP:-127.0.0.1}
    depends_on:
      - web
expose と ports の違い
expose はDocker内部のコンテナ間通信のみを許可します。ports はホストマシンのポートにマッピングし、外部からアクセスできるようにします。
Webアプリを expose のみにすることで、全てのリクエストがnginxを経由するようになり、IP制限を確実に適用できます。

自分のグローバルIPアドレスを調べる

以下のコマンドで確認できます。

ローカル(自分のPC)
curl -s ifconfig.me

表示されたIPアドレスを .env ファイルの ADMIN_IP に設定してください。

固定IPでない場合
家庭のインターネット回線は、プロバイダーによってIPアドレスが変わることがあります(動的IP)。IPが変わった場合は .env を更新して docker compose restart nginx を実行してください。
固定IPが必要な場合は、VPNサービスやプロバイダーの固定IPオプションを検討してください。

IP アドレスの偽装は可能なのか

「IPアドレスを偽装されたら意味がないのでは?」と思うかもしれませんが、結論から言うとIPアドレスの偽装ではこの制限を突破できません

その理由は、TCP通信の仕組みにあります。

TCP 3ウェイハンドシェイク

HTTPはTCPプロトコル上で動作します。TCP接続は以下の3ステップで確立されます。

  1. SYN: クライアント → サーバー「接続したい」
  2. SYN-ACK: サーバー → クライアント「OK、接続を受け入れる」
  3. ACK: クライアント → サーバー「確認した、通信を開始する」

攻撃者が送信元IPを偽装した場合、サーバーからのSYN-ACK応答は偽装先のIPアドレスに届きます。攻撃者はこの応答を受け取れないため、TCP接続を確立できません。

TCP接続が確立しなければHTTPリクエストは送信できず、管理画面にアクセスすることは不可能です。

多層防御: アプリケーション側の保護

IP制限は強力ですが、これだけに頼るのではなく、アプリケーション側でも保護を行うのが安全です。これを多層防御(Defense in Depth)と呼びます。

Django の場合

管理ビューに @staff_member_required デコレータを追加して、ログイン済みのスタッフユーザーのみがアクセスできるようにします。

views.py
from django.contrib.admin.views.decorators import staff_member_required

@staff_member_required
def classification_manage(request):
    # 管理画面の処理
    ...

こうすることで、万が一nginxのIP制限が突破されても、Django側でブロックできます。

防御レイヤー 対策 ブロックする対象
ネットワーク層 nginx IP制限 許可IP以外の全てのリクエスト
アプリケーション層 Django @staff_member_required 未認証・非スタッフユーザー

動作確認

設定が正しく動作するか確認します。

許可されていないIPからアクセス

別のネットワーク、またはスマートフォン(Wi-Fi OFF)
curl -s -o /dev/null -w "%{http_code}" http://サーバーのIP/admin/
403

403 Forbidden が返れば、IP制限が正しく動作しています。

許可されたIPからアクセス

許可IPのPC
curl -s -o /dev/null -w "%{http_code}" http://サーバーのIP/admin/
200

200 または 302(ログイン画面へのリダイレクト)が返れば正常です。

一般ページは誰でもアクセスできるか

どこからでも
curl -s -o /dev/null -w "%{http_code}" http://サーバーのIP/
200

まとめ

nginxのリバースプロキシでIP制限を設定することで、管理画面への不正アクセスをネットワークレベルで防ぐことができます。

  1. nginxで管理パス(/admin/ /manage/)にIP制限をかける
  2. Webアプリケーションは expose のみにし、nginxだけを外部公開する
  3. .env ファイルで許可IPを管理し、変更時はnginxを再起動する
  4. アプリケーション側でも認証を設定して多層防御にする
  5. TCP 3ウェイハンドシェイクにより、IP偽装での突破は不可能

SSH のセキュリティ対策と合わせて設定すれば、VPS のセキュリティは大幅に向上します。