nginx で SNI(Server Name Indication)

目次

最初に

クライアントからリバースプロキシ経由の Web サーバー接続を SSL 化してみた。

今まではリバースプロキシの nginx で SSL を終端させ、リバースプロキシから Web サーバーへは http 通信していた。http 通信は自宅の LAN 内だけだから盗聴される可能性は低いだろう。

でも今どきはグローバル IP アドレスが一つでも、名前ベースの Virtualhost と同じように、アクセス先のサーバー名で接続先をコントロールできることを知った。せっかくの自鯖だし誰にも迷惑をかけないし、知ってしまったら実行してみたくなるのも人の常ということでやってみた。

準備

リバースプロキシでは SSL を終端させないから、サーバー証明書を一端削除(失効ではない)する。
コマンドはこちら。削除対象のドメインを数字で選択すれば良い。

$ sudo certbot delete

あとで、Web サーバーの動いているバックエンドの仮想マシンにサーバー証明書をインストールする。

プロキシサーバーの設定

まずは、nginx の stream コンテキストの設定ファイルを作成する。ここの設定で、クライアントからの https 通信に対する Web サーバーの振り分けを行う。詳しくは次のサイトを参照。

ファイルは nginx.conf に書き込んでも良いけど、シンボリックで有効化・無効化が可能な modules-available に作ってみた。ファイル名の stream.conf は適当。
シンボリックを modules-enabled に作るのを忘れないように。

下の例で Web サーバーが動作している仮想マシンは次のイメージ。

  • 192.168.1.101 : backend1(Web サーバーは2つ)
  • 192.168.1.102 : backend2(Web サーバーは1つ)
  • 192.168.1.103 : backend3(Web サーバーは2つ)

これで、クライアントからの https 通信に関しては、SSL を終端させることなく運用中のサーバーに振り分けられる。

$ sudo vi /etc/nginx/modules-available/stream.conf 

stream {
    map $ssl_preread_server_name $name {
        example1.com          backend1;
        example2.com          backend1;
        example.jp            backend2;
        example.net           backend3;
        www.example.net       backend3;
    }
    upstream backend1 {
        server 192.168.1.101:443;
    }
    upstream backend2 {
        server 192.168.1.102:443;
    }
    upstream backend3 {
        server 192.168.1.103:443;
    }
    server {
        listen      443;
        proxy_pass  $name;
        ssl_preread on;
    }
}

続いて、certbot で 無料のサーバー証明書(Let's Encrypt)を取得するため、http 通信が backend1〜3 に届くように設定する。が、こちらは今まで使っていた名前ベース VirtualHost 用の設定ファイルをシンプルにするだけ。
http → https のリダイレクトはバックエンドの仮想マシンで行う。

$ sudo vi /etc/nginx/sites-available/example1.com.conf

server {
    server_name example1.com;
    listen 80;
    location / {
        proxy_set_header    Host    $host;
        proxy_set_header    X-Real-IP    $remote_addr;
        proxy_set_header    X-Forwarded-Host       $host;
        proxy_set_header    X-Forwarded-Server    $host;
        proxy_set_header    X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_pass    http://192.168.1.101;
    }
}

proxy_set_header で色々設定しているのはそのまま残してリダイレクト関係は削除。各サーバーごとに設定ファイルを作って sites-enabled にシンボリックを作成する。

sudo nginx -t でエラーがなければプロキシサーバーの設定は終了。

バックエンドサーバ−(apache)の設定

port 80 で待ち受けるファイルを用意する。あとで certbot を実行してサーバー証明書を取得するときに、port 443 で待ち受ける設定ファイルを自動で作成してくれる。
apache の場合はコマンド sudo a2ensite でシンボリックを作成できる。

$ sudo apachectl -t でチェックして、問題がなければ apache を起動。念の為 http でアクセスできることを確認してから、sudo certbot でサーバー証明書を取得する。

~$ sudo vi /etc/apache2/sites-available/example1.com.conf 

<VirtualHost *:80>
    ServerName example1.com
    DocumentRoot /var/www/example1.com.conf
    ErrorLog /var/log/apache2/virtual.host.error.log
    CustomLog /var/log/apache2/virtual.host.access.log combined
    LogLevel warn
  <Directory /var/www/example1.com.conf>
    Options FollowSymlinks Includes
    AllowOverride All
    AddType text/html .html
    Require all granted
  </Directory>
</VirtualHost>

mod_http2 を有効化してから、certbot を実行してできた example.com-le-ssl.conf に次の1行を加えて http/2 を有効にする。

$ sudo a2enmod http2

$ vi /etc/apache2/sites-enabled/example.com-le-ssl.conf

〜
Protocols h2 http/1.1
〜
〜

その他

若干の注意事項を。

アクセスログ

Web サーバーのアクセスログに残るのは、SSL で通信が暗号化されているためリバースプロキシの IP アドレスになる。接続元の IP アドレスは判らないからアクセス解析している場合はキッパリ諦める。Google アナリティクスならそれなりに表示されるかな。

Basic 認証

Basic 認証の設定で LAN 内(192.168.1.0/24)を認証不要にしていると、リバースプロキシからのアクセスも認証不要、その結果、外部からも認証不要となるので注意。

コメント

コメント一覧 (1件)

コメントする

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

目次
閉じる