自宅サーバをnginxで公開するときのssl設定はどうすればいいの?

SSL Test
自宅でNextcloudというクラウドサーバみたいなものを動かしています。これをインターネットに公開したいわけです。nginxというリバースプロキシを使うと簡単に公開する設定ができます。ですが安全かつ実用的に公開するには設定しなければならない事がたくさんあります。
facebookで自宅サーバの画像をシェアしたらサムネイルが表示されなかったので真面目に設定してみました。

以前にNextcloudというブラウザで操作するファイル共有サーバを動かしました。
関連記事:Raspberry Pi 3でNextcloudを動かす時の注意点

この時はとりあえず動く設定までしかしませんでした。ラズパイ3Bでは遅くて実用的にではないし、Windowsサーバとのsmb接続にも問題がありました。
関連記事:Raspberry Pi 3で64bit ubuntuを使ってNextcloudのSMB共有アクセスが成功した

新たにラズパイ4Bを手に入れました。3Bに比べとても速くなりました。これならサーバとして使えそうだと思い、Nextcloudを真面目に動かすことにしました。


基本的な動作は以前に確認済みです。64bitのubuntu 19.10.1を使うのでWindowsサーバの共有ファイルへのアクセスも問題ありません。自宅で動かすには十分な動作速度です。

しかし自宅の外、インターネットへ公開するにはもう少し設定を詰めなくてはなりません。前回の状態でも外からhttps接続で自宅サーバを見ることができます。

いろいろ実験していたのですがNextcloudで公開設定した画像をfacebookでシェアした時にfacebook上でサムネイル画像が付きませんでした。あまりやる事も無いのですがちょっと気になるなぁ。
少し真面目に調べるとfacebookはリンクされた先のssl設定のチェックを細かくしているようでした。怪しい点があるとサムネイルを作ってくれません。つまり、今の自宅サーバの公開設定には問題がありそうだということです。

我が家のSSLサーバ証明書はWindows ServerのDDNSサービスのものを使っています。
これを使ってnginxで安全なssl設定を行うまでを書いてみます。

SSL証明書の準備

自宅のIPアドレスがグローバルアドレスでなければそもそも公開できません。ケーブルテレビやマンションのインターネットだとグローバルアドレスでは無い所が多いです。マンションを買う時は慎重に物件を選びましょう。こんな場合はレンタルサーバを使うしかありません。するとファイルは自宅に置けなくなるので普通にクラウドサービス使ったほうがいいかな。

自宅のサーバを信用してもらうためにSSLサーバ証明書を用意します。そのためにはドメインを取得しなくてはなりません。ダイナミックDNSサービスでも証明書の取得は可能です。自宅で簡単にサーバを公開するならDDNSサービスから始めると良いでしょう。
無料のDDNSサービスにLet's Encryptがあります。linux上での自動設定プログラムもあり使いやすいのですが、ドメインは別に取得しておく必要があります。
ドメインの取得は少し敷居が高いですね。

そんな場合はASUSのルータを使うと良いでしょう。自宅がグローバルIPアドレスであればLet's Encryptを使って自動的にDDNS設定をしてくれます。証明書のエクスポートもできます。
関連記事:ASUSのルータでSSL/TLSサーバ証明書を無料で取得できるようになりました


ドメインを取ってる方ならSSLサーバ証明書はすでにあるでしょう。SSLサーバ証明書の他に中間CA証明書とルート証明書を用意します。domainを取得したサービス会社で公開されているはずです。

Windowsサーバの証明書を変換する場合

私の場合、WindowsサーバのDDNSサービスを使っているのでWindowsサーバでサーバ証明書をエクスポートします。エクスポート時は"証明書のパスにある証明書を可能であれば含む"をチェックして中間CA証明書とルート証明書を含むようにします。

証明書はPKCS#12という形式になっているのでLinuxでよく使うPEM形式に変換します。変換はラズパイ(linux)上でやった方が楽です。
SSLサーバ証明書を作ります。
openssl pkcs12 -in exported.pfx -clcerts  -nokeys -out server.crt
中間CA証明書とルート証明書を作ります。
openssl pkcs12 -in exported.pfx -cacerts -nokeys -out ca.crt
秘密鍵を作ります。このファイルは他人に知られてはいけません。
openssl pkcs12 -in exported.pfx -nocerts -nodes -out server.key
それぞれエクスポート時に設定したパスワードを聞かれるので入れます。
これで主要なファイルは揃いました。

nginx用の証明書を作る

nginxでSSL証明書を使うのですが、ファイルを3種類用意する必要があります。nginxで指定する文だと次の通り。カッコ内は作るファイル名とします。前節と同じファイル名がありますが秘密鍵以外は異なる新しいファイルだと思ってください。
  • ssl_certificate_key (server.key)
    • 秘密鍵
  • ssl_certificate (server.crt)
    • SSLサーバ証明書と中間CA証明書を連結したもの
  • ssl_trusted_certificate (trusted.crt)
    • 中間CA証明書とルート証明書を連結したもの
前節で用意したファイルから上のファイルを作ります。証明書はテキスト形式なのでテキストエディタで連結できます。中間CA証明書は複数ある場合もあります。
注意点として、連結する順番があります。自宅に近い証明書から順番にファイルの先頭からつなげます。今回私がWindowsでエクスポートした中間CA証明書とルート証明書の入ったca.crtファイルはルート証明書が先頭に書かれていたので編集する必要がありました。

他の多くのサイトの例と異なるのはserver.crtに中間CA証明書を連結している点とtrusted.crtを作っている点だと思います。

nginx用のSSL設定ファイルssl.confを作る

nginxの設定にSSL用の記述をします。直接書いても良いのですが後々メンテナンスが大変になるのでSSLだけの設定をssl.confファイルにまとめて書きます。

推奨するSSL設定の記述は次のサイトで見ることができます。
SSL Configuration Generator
その時々で最適な設定が表示されるでしょう。いろいろなサーバソフトウエア用のSSL設定を見ることができます。Server Softwareは"nginx"を選びます。Mozilla Configurationは"Intermediate"を選びます。自宅サーバで古いブラウザを使わないなら"Modern"を選ぶと良いでしょう。Miscellaneousの"OCSP Stapling"はチェックしておきましょう。

この設定例の"ssl_"で始まる文を抜き出してssl.confファイルに書きます。この記事公開時の場合は次のようになります。
# certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
ssl_certificate /path/to/signed_cert_plus_intermediates;
ssl_certificate_key /path/to/private_key;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;  # about 40000 sessions
ssl_session_tickets off;

# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam.pem
ssl_dhparam /path/to/dhparam.pem;

# intermediate configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;

# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000" always;

# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;

# verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;
よく見ると必要なファイルがもう一つあります。"dhparam.pem"というファイルです。どうやって作るのでしょうか?コメントに書いてありますね。
curl https://ssl-config.mozilla.org/ffdhe2048.txt > dhparam.pem
これで必要な証明書のファイルが揃いました。
あとはnginxのインストール先に合わせてファイルパスを設定します。
ssl.confファイルを読み込むためにnginxの設定ファイルのinclude文でファイルを指定します。
このあたりは環境により違いが大きいので紹介しにくいです。私がdocker composeで作った環境の例を次に紹介します。

nginxのSSL設定例

docker composeでnginxを動かすと色々なサーバソフトウエアとの連携が簡単に実現できます。その際のSSLの設定部分だけを紹介します。
docker-compose.ymlファイルにnginxの記述をします。
services:
  nginx1:
    image: nginx
    volumes:
      - ./nginx1/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx1/conf.d:/etc/nginx/conf.d
      - ./nginx1/html:/usr/share/nginx/html
      - ./nginx1/ssl/serverchain.crt:/etc/pki/tls/certs/server.crt
      - ./nginx1/ssl/trusted.crt:/etc/pki/tls/certs/trusted.crt
      - ./nginx1/ssl/dhparam.pem:/etc/pki/tls/certs/dhparam.pem
      - ./nginx1/ssl/server.key:/etc/pki/tls/private/server.key
      - ./nginx1/ssl/ssl.conf:/etc/nginx/snippets/ssl.conf
    ports: 
      - 443:443
volumesでホストOS上にある証明書ファイルをdockerコンテナ内のnginxから使えるようにします。ホストOS上のdocker-compose.ymlファイルのあるディレクトリの下にnginx1というディレクトリを作ります。ここにSSLという名前のサブフォルダを作りSSL証明書、秘密鍵やssl.confファイルを置きます。SSLサーバ証明書と中間CA証明書をつなげたものはserverchain.crtというファイルで作ったとします。
nginxのコンテナでは、
/etc/pki/tls/private/server.key に秘密鍵
/etc/pki/tls/certs/server.crt にSSLサーバ証明書と中間CA証明書
/etc/pki/tls/certs/trusted.crt に中間CA証明書とルート証明書
/etc/pki/tls/certs/dhparam.pem にdhparam.pemファイル
/etc/nginx/snippets/ssl.conf にssl.confファイル
が置かれることになります。このパスに合わせてssl.confファイルを修正します。
ssl.confファイルはsslを使用するnginxのserver節でincludeします。
server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name my.domain.com;

  include /etc/nginx/snippets/ssl.conf;
  .....

SSL証明書の確認

公開できた自宅サーバの証明書のテストをしてみます。
SSL Server Test | Qualys SSL Labs
上のサイトで自宅サーバのドメイン名を入れます。数分すると結果が表示されます。
SSL Test
Aになりました。今回の設定をする前はBでした。
古いブラウザに対応すると脆弱性のある暗号化方式を使うので評価が下がります。古いブラウザを考慮しない設定によってはA+にできました。
設定見直し後、再度テストするには"Clear chache"をクリックします。

まとめ

今回の設定でNextcloudの画像ファイルをfacebookにシェアするとサムネイルが作成されるようになりました。
facebookでシェア時のサムネイル
facebookではSSLサーバ証明書と中間CA証明書をいっしょにしておかないとサムネイルが作られないようです。考えてみれば当たり前でルートへ辿れない証明書など意味が無いわけです。
多くのサイトで紹介されているSSL設定手順では中間CA証明書を含まない例が多いです。

自宅サーバを公開するときの証明書周りはわかりづらくて面倒です。一度動かすとしばらくいじらないので設定を忘れてしまいます。セキュリティの状況や新しい技術も次々更新されるので1年に一度は設定状況を見直す必要があるでしょう。ですが脆弱性が見つかっても、じゃあどうしたらいいの?という点にまで理解が進みません。
この他にルータのポートフォワーディングの設定もしなくてはなりません。

インターネットの情報は年を追うごとにノイズが増えます。ソフトウエア関係は数年経つと使えない情報になるものが多いです。私の過去の記事も・・・
Goggle検索もそろそろ限界を迎えそうな感じがします。

いろいろ面倒だからみんなクラウドを使っちゃうわけです。
でもやはりファイルは手元に置いておきたい!

コメント

最近のコメント

Threaded Recent Comments will be here.