Nginxリバースプロキシ入門|SSL対応の基本設定

Webサーバーの負荷分散やセキュリティ強化に必須のNginxリバースプロキシを、SSL/TLS対応を含めて完全にマスターしましょう。本記事では、ローカルネットワーク内のサービスを外部公開する際の実践的な設定手順を、具体的なコマンドと共に解説します。NginxのインストールからSSL証明書の取得、リバースプロキシの基本設定、さらには動的なルーティングやキャッシュ設定まで、実務で即戦力となる内容を網羅しています。


目次


Nginxリバースプロキシの概要とメリット

Nginxリバースプロキシは、クライアントからのリクエストを受け取り、内部のサーバーに転送する役割を果たします。この技術を活用することで、以下のようなメリットを享受できます。

  • セキュリティの向上:内部サーバーの直接公開を避け、攻撃対象を最小化
  • 負荷分散:複数のバックエンドサーバーにリクエストを分散
  • SSL/TLS終端:暗号化通信をNginxで処理し、バックエンドサーバーの負荷を軽減
  • 静的コンテンツのキャッシュ:レスポンス速度を向上させる
  • URLリライト:外部に公開するURLを柔軟に変更可能

特に、SSL/TLS対応は現代のWebサイトに必須の要素です。Nginxは高いパフォーマンスでSSL/TLS処理を実行できるため、バックエンドサーバーの負荷を大幅に削減できます。

総務省の調査によると、2023年現在、日本国内のWebサイトのうち85%以上がHTTPS化されている(出典: 総務省「通信利用動向調査2023」)。これは、Googleなどの検索エンジンがHTTPSをランキング要因の一つとしていることや、ユーザーのセキュリティ意識の高まりが背景にあります。Nginxリバースプロキシを導入することで、これらの要件を満たしつつ、柔軟なサーバー構成を実現できます。

リバースプロキシとフォワー…

リバースプロキシとフォワードプロキシは、いずれもプロキシサーバーですが、役割が大きく異なります。

機能リバースプロキシフォワードプロキシ
設置場所サーバー側クライアント側
主な用途負荷分散、セキュリティ、SSL終端匿名性確保、アクセス制限、キャッシュ
代表的な用途例Webサーバーの前段に設置し、リクエストを内部サーバーに転送社内ネットワークからインターネットへのアクセスを制御
Nginxの役割リバースプロキシとして動作フォワードプロキシとして動作(特定の設定が必要)

本記事では、主にリバースプロキシに焦点を当てて解説します。フォワードプロキシについては、必要に応じて補足します。

Nginxのインストールと基本設定

Nginxリバースプロキシを構築する前に、Nginxをインストールし、基本的な設定を行います。以下の手順は、Ubuntu 22.04 LTSを前提としていますが、他のLinuxディストリビューションでも同様の手順でインストール可能です。

Nginxのインストール

まず、Nginxをインストールします。公式リポジトリからインストールする方法と、Nginx Inc.が提供する公式リポジトリを使用する方法があります。ここでは、公式リポジトリを使用する方法を紹介します。

# 1. 必要なパッケージをインストール
sudo apt update
sudo apt install -y curl gnupg2 ca-certificates lsb-release ubuntu-keyring

2. Nginx公式リポジトリを追加

echo "deb http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" | sudo tee /etc/apt/sources.list.d/nginx.list

3. GPGキーをインポート

curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo gpg --dearmor -o /usr/share/keyrings/nginx-archive-keyring.gpg

4. リポジトリを更新し、Nginxをインストール

sudo apt update sudo apt install -y nginx

インストールが完了したら、Nginxを起動します。

sudo systemctl start nginx
sudo systemctl enable nginx

Nginxが正常に起動しているか確認します。

systemctl status nginx

以下のような出力が表示されれば、Nginxは正常に動作しています。

● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2024-02-19 10:00:00 UTC; 1min ago
       Docs: http://nginx.org/en/docs/
   Main PID: 1234 (nginx)
      Tasks: 2 (limit: 1137)
     Memory: 3.4M
     CGroup: /system.slice/nginx.service
             ├─1234 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
             └─1235 nginx: worker process

Nginxの基本設定

Nginxの設定ファイルは、主に/etc/nginx/ディレクトリに格納されています。主な設定ファイルは以下の通りです。

  • nginx.conf:メインの設定ファイル
  • conf.d/:追加の設定ファイルを格納するディレクトリ
  • sites-available/:利用可能なサイトの設定ファイル
  • sites-enabled/:有効化されたサイトの設定ファイル(sites-availableからシンボリックリンク)

まず、nginx.confを確認します。

cat /etc/nginx/nginx.conf

デフォルトの設定では、include /etc/nginx/conf.d/*.conf;という行があり、conf.d/ディレクトリ内の.confファイルが読み込まれます。このため、リバースプロキシの設定はconf.d/ディレクトリに配置するのが一般的です。

次に、sites-available/sites-enabled/を使用する方法もあります。これはApacheの設定に似ており、複数のサイトを管理する際に便利です。ここでは、conf.d/を使用する方法で進めます。

まず、conf.d/ディレクトリに新しい設定ファイルを作成します。

sudo nano /etc/nginx/conf.d/reverse-proxy.conf

以下の内容を記述します。これは、単純なリバースプロキシの設定例です。

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://localhost:8080;
        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;
    }
}

この設定は、example.comに対するリクエストを、localhost:8080に転送します。また、リクエストヘッダーを適切に設定することで、バックエンドサーバーがクライアントの情報を正しく認識できるようにします。

設定を保存したら、Nginxを再読み込みします。

sudo nginx -t  # 構文チェック
sudo systemctl reload nginx

nginx -tコマンドは、設定ファイルの構文をチェックします。エラーがなければ、systemctl reload nginxで設定を反映します。

バックエンドサーバーの準備

リバースプロキシを動作させるためには、バックエンドサーバーが必要です。ここでは、簡単なHTTPサーバーを起動して、リバースプロキシが正しく動作するか確認します。

Pythonの簡易HTTPサーバーを使用します。

# 任意のディレクトリで実行
mkdir -p ~/reverse-proxy-test
cd ~/reverse-proxy-test
echo "Hello, Reverse Proxy!" > index.html

Python 3を使用してHTTPサーバーを起動(ポート8080)

python3 -m http.server 8080

別のターミナルで、Nginxの設定で指定したexample.comにアクセスします。ローカル環境では、/etc/hostsファイルに以下の行を追加して、example.comをlocalhostに解決させます。

127.0.0.1 example.com

その後、ブラウザでhttp://example.comにアクセスすると、Hello, Reverse Proxy!というメッセージが表示されます。これにより、Nginxリバースプロキシが正しく動作していることが確認できます。

SSL/TLS証明書の取得とNginxへの適用

現代のWebサイトにとって、SSL/TLS対応は必須です。Nginxリバースプロキシでも、SSL/TLSを有効にすることで、セキュアな通信を実現できます。ここでは、Let’s Encryptを使用して無料のSSL/TLS証明書を取得し、Nginxに適用する方法を解説します。

Let’s Encryptとは

Let’s Encryptは、非営利団体のInternet Security Research Group (ISRG)が運営する、無料で利用できるSSL/TLS証明書を発行する認証局です。2024年現在、世界中で2億件以上の証明書が発行されており、その信頼性は高く評価されています。

Let’s Encryptの証明書は、以下の特徴を持ちます。

  • 無料:個人や小規模なサイトでも利用可能
  • 自動更新:証明書の有効期限が近づくと自動的に更新される
  • 広範な互換性:主要なブラウザやOSでサポートされている
  • 90日間有効:セキュリティ向上のため、有効期限が短い

Certbotのインストール

Let’s Encryptの証明書を取得するためには、Certbotというツールを使用します。Certbotは、証明書の取得と更新を自動化するツールです。

Certbotをインストールします。

sudo apt install -y certbot python3-certbot-nginx

このコマンドは、Certbot本体と、Nginx用のプラグインをインストールします。Nginx用のプラグインを使用することで、自動的にNginxの設定を更新できます。

SSL/TLS証明書の取得

Certbotを使用して、SSL/TLS証明書を取得します。ここでは、example.comをドメイン名として使用します。実際の運用では、取得したドメインに置き換えてください。

sudo certbot --nginx -d example.com

Certbotが起動し、以下のような対話型のプロンプトが表示されます。

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel): admin@example.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(A)gree/(C)ancel: A

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
protecting the privacy of individuals like you.
- - - - - - - - - - - - - - - - - - - - - - - - - - "Y" to subscribe, "N" to
decline, "C" to cancel: N

メールアドレスの入力と、利用規約への同意、EFFへのメール配信の可否を選択します。その後、Certbotが自動的にドメインの検証を行い、SSL/TLS証明書を取得します。

証明書の取得が完了すると、以下のようなメッセージが表示されます。

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/example.com/privkey.pem
   Your cert will expire on 2024-05-18. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the "certonly" option. To non-interactively renew *all* of
   your certificates, run "certbot renew"
 - If you like Certbot, please consider supporting our work by:
   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

Certbotは、自動的にNginxの設定ファイルを更新し、SSL/TLSを有効にします。/etc/nginx/conf.d/reverse-proxy.confファイルを確認すると、以下のような設定が追加されていることがわかります。

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:8080;
        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;
    }
}

この設定により、HTTP(ポート80)へのアクセスはHTTPS(ポート443)にリダイレクトされ、SSL/TLSが有効になります。

SSL/TLSの設定最適化

Let’s Encryptから発行される証明書は、デフォルトでTLS 1.2とTLS 1.3をサポートしています。しかし、セキュリティを向上させるために、より厳格な設定を行うことを推奨します。以下は、NginxのSSL/TLS設定を最適化するための例です。

server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # SSL/TLS設定
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_stapling on;
    ssl_stapling_verify on;

    location / {
        proxy_pass http://localhost:8080;
        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;
    }
}

主な設定項目の説明は以下の通りです。

  • ssl_protocols:使用するSSL/TLSプロトコルを指定します。TLS 1.2とTLS 1.3のみを許可します。
  • ssl_prefer_server_ciphers:サーバー側の暗号スイートを優先します。
  • ssl_ciphers:使用する暗号スイートを指定します。安全な暗号スイートのみを許可します。
  • ssl_session_timeout:SSLセッションの有効期限を設定します。
  • ssl_session_cache:SSLセッションのキャッシュを有効にします。
  • ssl_stapling:OCSP Staplingを有効にします。これにより、証明書の失効確認が高速化されます。

設定を更新したら、Nginxを再読み込みします。

sudo nginx -t
sudo systemctl reload nginx

SSL/TLS証明書の自動更新

Let’s Encryptの証明書は90日間有効です。このため、証明書の自動更新を設定することが重要です。Certbotには、証明書の自動更新を行うcertbot renewコマンドが用意されています。

自動更新を設定するためには、cronジョブを使用します。以下のコマンドで、毎週月曜日の午前2時に証明書の更新を確認するように設定します。

sudo crontab -e

以下の行を追加します。

0 2 * * 1 /usr/bin/certbot renew --quiet

--quietオプションを使用することで、更新が行われた場合のみログが出力されます。更新が行われた場合は、自動的にNginxが再読み込みされます。

リバースプロキシの基本設定と動作確認

Nginxをリバースプロキシとして動作させるための基本的な設定方法と、動作確認の手順を解説します。ここでは、具体的なバックエンドサーバーとして、Apache HTTP ServerNode.jsアプリケーションを例に挙げます。

Apache HTTP S…

Apache HTTP Serverをバックエンドサーバーとして使用する場合の設定例を紹介します。Apacheはデフォルトでポート80で動作しますが、Nginxと競合しないようにポートを変更します。

Apacheの設定ファイルを編集します。

sudo nano /etc/apache2/ports.conf

以下の行を変更します。

Listen 8080

次に、Apacheの仮想ホスト設定を編集します。

sudo nano /etc/apache2/sites-available/000-default.conf

以下の内容に書き換えます。

<VirtualHost *:8080>
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html

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

Apacheを再起動します。

sudo systemctl restart apache2

次に、Nginxのリバースプロキシ設定を更新します。

sudo nano /etc/nginx/conf.d/reverse-proxy.conf

以下の内容に書き換えます。

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:8080;
        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;
    }
}

設定を保存したら、Nginxを再読み込みします。

sudo nginx -t
sudo systemctl reload nginx

ブラウザでhttps://example.comにアクセスすると、Apacheが提供するコンテンツが表示されます。これにより、Nginxリバースプロキシを介してApacheが動作していることが確認できます。

Node.jsアプリケーシ…

Node.jsアプリケーションをバックエンドサーバーとして使用する場合の設定例を紹介します。ここでは、簡単なExpress.jsアプリケーションを例に挙げます。

まず、Node.jsとnpmをインストールします。

sudo apt install -y nodejs npm

次に、Express.jsアプリケーションを作成します。

mkdir -p ~/node-app
cd ~/node-app
npm init -y
npm install express

app.jsファイルを作成します。

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello from Node.js!');
});

app.listen(port, () => {
  console.log(`Node.js app listening at http://localhost:${port}`);
});

アプリケーションを起動します。

node app.js

アプリケーションがポート3000で動作していることを確認します。次に、Nginxのリバースプロキシ設定を更新します。

sudo nano /etc/nginx/conf.d/reverse-proxy.conf

以下の内容に書き換えます。

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:3000;
        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;
    }
}

設定を保存したら、Nginxを再読み込みします。

sudo nginx -t
sudo systemctl reload nginx

ブラウザでhttps://example.comにアクセスすると、Node.jsアプリケーションが提供するメッセージが表示されます。これにより、Nginxリバースプロキシを介してNode.jsアプリケーションが動作していることが確認できます。

リバースプロキシの動作確認

リバースプロキシが正しく動作しているか確認するためには、以下の方法があります。

  • ログの確認:Nginxのアクセスログとエラーログを確認します。
  • ヘッダーの確認:ブラウザの開発者ツールを使用して、レスポンスヘッダーを確認します。
  • curlコマンドの使用curl -v https://example.comを実行し、レスポンスヘッダーを確認します。

例えば、curl -v https://example.comを実行すると、以下のような出力が表示されます。

*   Trying 192.168.1.100:443...
* Connected to example.com (192.168.1.100) port 443 (#0)
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 TLS_AES_256_GCM_SHA384
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=example.com
*  start date: Jan 1 00:00:00 2024 GMT
*  expire date: Mar 31 23:59:59 2024 GMT
*  subjectAltName: host "example.com" matched cert's "example.com"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55a1b3a5e2a0)
> GET / HTTP/2
> Host: example.com
> user-agent: curl/7.81.0
> accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200
< server: nginx/1.25.3
< date: Mon, 19 Feb 2024 10:00:00 GMT
< content-type: text/html
< content-length: 21
< last-modified: Mon, 19 Feb 2024 09:00:00 GMT
< etag: "65d3a1a0-15"
< x-powered-by: Express
< via: 1.1 example.com
< strict-transport-security: max-age=63072000; includeSubDomains; preload
<
Hello from Node.js!

この出力から、以下の情報を確認できます。

  • server: nginx/1.25.3:Nginxがリバースプロキシとして動作している
  • x-powered-by: Express:バックエンドがExpress.jsアプリケーションである
  • via: 1.1 example.com:リバースプロキシを経由している
  • strict-transport-security:HSTSヘッダーが設定されている

応用的なリバースプロキシ設定(負荷分散・キャッシュ)

基本的なリバースプロキシ設定をマスターしたら、次は応用的な設定に挑戦しましょう。ここでは、負荷分散キャッシュ

この記事で学んだスキルをさらに深めたい方へ

インフラセキュリティを体系的に学ぶための技術書です。SSL/TLS・ファイアウォール・VPNを網羅しています。

Amazonアソシエイトプログラムを利用しています。

【編集・制作ポリシー】
本記事はRoute Bloom編集部が公式ドキュメント・技術仕様書の一次情報をもとに作成しています。ITインフラ・技術情報は急速に変化するため、実装前に最新の公式ドキュメントをご確認ください。情報の正確性には万全を期していますが、最新情報は各公式サイトをご確認ください。
【編集・制作ポリシー】
本記事はRoute Bloom編集部が各ベンダー公式ドキュメント・エンジニア監修をもとに作成しています。インフラ・クラウド構築は環境により異なります。本番環境への適用前に必ずテストを実施してください。情報の正確性には万全を期していますが、最新情報は各公式ドキュメントをご確認ください。
【編集・制作ポリシー】
本記事はRoute Bloom編集部が各ベンダー・技術標準の公式ドキュメントをもとに作成しています。 インフラ・クラウド技術に関する最終判断は実際の環境・バージョンで検証のうえ実施してください。 情報の正確性には万全を期していますが、最新情報は各公式ドキュメントをご確認ください。

編集ポリシー:この記事は、Route Bloom の編集チームが最新情報を元に執筆・監修しています。情報の正確性を保つために定期的な見直しを行っています。

ABOUT ME
たから
サラリーマンをしながら開業して経営やってます。 今年、本業で独立・別事業を起業予定です。 ◆経験:IT講師/インフラエンジニア/PM/マネジメント/採用/運用・保守・構築・設計 ◆取得資格:CCNA/CCNP/LPIC-1/AZ-900/FE/サーティファイC言語 ◆サイドビジネス:アパレル事業/複数のWEBメディアを運営