前書き
Node.jsアプリケーションの柔軟性とセキュリティを強化する方法は複数あります。 Nginxのようなreverse proxyを使用すると、リクエストの負荷分散、静的コンテンツのキャッシュ、およびTransport Layer Security(TLS)の実装が可能になります。 サーバーで暗号化されたHTTPSを有効にすると、アプリケーションとの通信が安全に保たれます。
コンテナにTLS / SSLを使用してリバースプロキシを実装するには、ホストオペレーティングシステムで直接作業する場合とは異なる一連の手順が必要です。 たとえば、サーバーで実行されているアプリケーションのLet’s Encryptから証明書を取得する場合は、必要なソフトウェアをホストに直接インストールします。 コンテナを使用すると、異なるアプローチを取ることができます。 Docker Composeを使用して、アプリケーション、Webサーバー、および証明書を取得できるようにするCertbot clientのコンテナーを作成できます。 これらの手順に従うことで、コンテナ化されたワークフローのモジュール性と移植性を活用できます。
前提条件
このチュートリアルを実行するには、次のものが必要です。
-
Ubuntu 18.04サーバー、
sudo
権限を持つroot以外のユーザー、およびアクティブなファイアウォール。 これらの設定方法のガイダンスについては、このInitial Server Setup guideを参照してください。 -
サーバーにインストールされたDockerおよびDocker Compose。 Dockerのインストールに関するガイダンスについては、How To Install and Use Docker on Ubuntu 18.04のステップ1と2に従ってください。 Composeのインストールに関するガイダンスについては、How To Install Docker Compose on Ubuntu 18.04のステップ1に従ってください。
-
登録済みドメイン名。 このチュートリアルでは、全体を通してexample.comを使用します。 Freenomで無料で入手するか、選択したドメインレジストラを使用できます。
-
次の両方のDNSレコードがサーバーに設定されています。 this introduction to DigitalOcean DNSをフォローして、DigitalOceanアカウントに追加する方法の詳細を確認できます(使用している場合)。
-
サーバーのパブリックIPアドレスを指す
example.com
を含むAレコード。 -
サーバーのパブリックIPアドレスを指す
www.example.com
を含むAレコード。
-
[[step-1 -—- cloning-and-testing-the-node-application]] ==ステップ1—ノードアプリケーションのクローン作成とテスト
最初のステップとして、Composeを使用してアプリケーションイメージをビルドするために使用するDockerfileを含むNodeアプリケーションコードを使用して、リポジトリのクローンを作成します。 最初に、リバースプロキシやSSLを使用せずに、docker run
commandを使用してアプリケーションをビルドして実行することにより、アプリケーションをテストできます。
root以外のユーザーのホームディレクトリで、DigitalOcean Community GitHub accountからnodejs-image-demo
repositoryのクローンを作成します。 このリポジトリには、How To Build a Node.js Application with Dockerで説明されているセットアップのコードが含まれています。
リポジトリをnode_project
というディレクトリに複製します。
git clone https://github.com/do-community/nodejs-image-demo.git node_project
node_project
ディレクトリに移動します。
cd node_project
このディレクトリには、Docker node:10
imageと現在のプロジェクトディレクトリの内容を使用してノードアプリケーションを構築するための手順を含むDockerfileがあります。 次のように入力して、Dockerfileの内容を確認できます。
cat Dockerfile
OutputFROM node:10-alpine
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
WORKDIR /home/node/app
COPY package*.json ./
USER node
RUN npm install
COPY --chown=node:node . .
EXPOSE 8080
CMD [ "node", "app.js" ]
これらの手順では、プロジェクトコードを現在のディレクトリからコンテナにコピーし、npm install
を使用して依存関係をインストールすることにより、ノードイメージを構築します。 また、プロジェクトのリストされた依存関係を含むpackage.json
とpackage-lock.json
のコピーを、残りのアプリケーションコードのコピーから分離することにより、Dockerのcaching and image layeringを利用します。 最後に、この手順では、コンテナが非ルートnodeユーザーとして実行され、アプリケーションコードとnode_modules
ディレクトリに適切な権限が設定されていることを指定しています。
このDockerfileとNodeイメージのベストプラクティスの詳細については、Step 3 of How To Build a Node.js Application with Dockerの完全な説明を参照してください。
SSLを使用せずにアプリケーションをテストするには、docker build
および-t
フラグを使用してイメージをビルドおよびタグ付けします。 画像をnode-demo
と呼びますが、別の名前を付けることもできます。
docker build -t node-demo .
ビルドプロセスが完了すると、docker images
を使用してイメージを一覧表示できます。
docker images
次の出力が表示され、アプリケーションイメージのビルドが確認されます。
OutputREPOSITORY TAG IMAGE ID CREATED SIZE
node-demo latest 23961524051d 7 seconds ago 73MB
node 10-alpine 8a752d5af4ce 3 weeks ago 70.7MB
次に、docker run
でコンテナを作成します。 このコマンドには3つのフラグが含まれます。
-
-p
:これにより、コンテナーのポートが公開され、ホストのポートにマップされます。 ホストではポート80
を使用しますが、そのポートで別のプロセスを実行している場合は、必要に応じてこれを自由に変更してください。 これがどのように機能するかについての詳細は、port bindingに関するDockerドキュメントのこの説明を参照してください。 -
-d
:これはコンテナをバックグラウンドで実行します。 -
--name
:これにより、コンテナに覚えやすい名前を付けることができます。
次のコマンドを実行して、コンテナを構築します。
docker run --name node-demo -p 80:8080 -d node-demo
実行中のコンテナをdocker ps
で検査します。
docker ps
アプリケーションコンテナが実行されていることを確認する出力が表示されます。
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4133b72391da node-demo "node app.js" 17 seconds ago Up 16 seconds 0.0.0.0:80->8080/tcp node-demo
これで、ドメインにアクセスしてセットアップをテストできます:http://example.com
。 example.com
を独自のドメイン名に置き換えることを忘れないでください。 アプリケーションには、次のランディングページが表示されます。
アプリケーションをテストしたので、コンテナーを停止してイメージを削除できます。 docker ps
を再度使用して、CONTAINER ID
を取得します。
docker ps
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4133b72391da node-demo "node app.js" 17 seconds ago Up 16 seconds 0.0.0.0:80->8080/tcp node-demo
docker stop
でコンテナを停止します。 ここにリストされているCONTAINER ID
を、必ず独自のアプリケーションCONTAINER ID
に置き換えてください。
docker stop 4133b72391da
停止したコンテナと、未使用の画像やぶら下がっている画像を含むすべての画像を、docker system prune
と-a
フラグで削除できるようになりました。
docker system prune -a
出力でプロンプトが表示されたら%(t0)sと入力して、停止したコンテナーとイメージを削除することを確認します。 これによりビルドキャッシュも削除されることに注意してください。
アプリケーションイメージをテストしたら、Docker Composeを使用して残りのセットアップの構築に進むことができます。
[[step-2 -—- defining-the-web-server-configuration]] ==ステップ2—Webサーバー構成の定義
アプリケーションDockerfileを配置したら、Nginxコンテナーを実行するための構成ファイルを作成できます。 まず、ドメイン名、document root、プロキシ情報、およびCertbotの要求を.well-known
ディレクトリに転送するためのロケーションブロックを含む最小限の構成から始めます。ここで、一時ファイルを配置して、それを検証します。ドメインのDNSはサーバーに解決されます。
まず、現在のプロジェクトディレクトリに構成ファイル用のディレクトリを作成します。
mkdir nginx-conf
nano
またはお気に入りのエディターでファイルを開きます。
nano nginx-conf/nginx.conf
次のサーバーブロックを追加して、ユーザーリクエストをノードアプリケーションコンテナにプロキシし、Certbotのリクエストを.well-known
ディレクトリに送信します。 必ずexample.com
を独自のドメイン名に置き換えてください。
~/node_project/nginx-conf/nginx.conf
server {
listen 80;
listen [::]:80;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name example.com www.example.com;
location / {
proxy_pass http://nodejs:8080;
}
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
}
このサーバーブロックにより、Nginxコンテナーをリバースプロキシとして起動し、Nodeアプリケーションコンテナーにリクエストを渡すことができます。 また、Certbotのwebroot pluginを使用して、ドメインの証明書を取得することもできます。 このプラグインはHTTP-01 validation methodに依存します。これは、HTTPリクエストを使用して、Certbotが特定のドメイン名に応答するサーバーからリソースにアクセスできることを証明します。
編集が完了したら、ファイルを保存して閉じます。 Nginxサーバーとロケーションブロックアルゴリズムの詳細については、Understanding Nginx Server and Location Block Selection Algorithmsに関するこの記事を参照してください。
Webサーバー構成の詳細が整ったら、docker-compose.yml
ファイルの作成に進むことができます。これにより、アプリケーションサービスと、証明書の取得に使用するCertbotコンテナーを作成できます。
[[step-3 -—- creating-the-docker-compose-file]] ==ステップ3—Docker作成ファイルの作成
docker-compose.yml
ファイルは、ノードアプリケーションやWebサーバーなどのサービスを定義します。 名前付きボリュームなどの詳細を指定します。これは、コンテナー間でSSL資格情報を共有するために重要であり、ネットワークおよびポート情報も同様です。 また、コンテナの作成時に実行する特定のコマンドを指定できます。 このファイルは、サービスの連携方法を定義する中心的なリソースです。
現在のディレクトリでファイルを開きます。
nano docker-compose.yml
最初に、アプリケーションサービスを定義します。
~/node_project/docker-compose.yml
version: '3'
services:
nodejs:
build:
context: .
dockerfile: Dockerfile
image: nodejs
container_name: nodejs
restart: unless-stopped
nodejs
サービス定義には、次のものが含まれます。
-
build
:これは、Composeがアプリケーションイメージをビルドするときに適用される、context
およびdockerfile
を含む構成オプションを定義します。 Docker Hubなどのレジストリの既存のイメージを使用する場合は、代わりに、ユーザー名、リポジトリ、およびイメージタグに関する情報とともにimage
instructionを使用できます。 -
context
:これは、アプリケーションイメージビルドのビルドコンテキストを定義します。 この場合、それは現在のプロジェクトディレクトリです。 -
dockerfile
:これは、Composeがビルドに使用するDockerfile(Step 1で確認したDockerfile)を指定します。 -
image
、container_name
:これらはイメージとコンテナに名前を適用します。 -
restart
:これは再起動ポリシーを定義します。 デフォルトはno
ですが、コンテナが停止しない限り再起動するように設定しています。
このサービスにはバインドマウントが含まれていないことに注意してください。これは、セットアップが開発ではなく展開に重点を置いているためです。 詳細については、bind mountsおよびvolumesに関するDockerのドキュメントを参照してください。
アプリケーションとWebサーバーコンテナ間の通信を有効にするために、再起動定義の下にapp-network
というブリッジネットワークも追加します。
~/node_project/docker-compose.yml
services:
nodejs:
...
networks:
- app-network
このようなユーザー定義のブリッジネットワークにより、同じDockerデーモンホスト上のコンテナー間の通信が可能になります。 これにより、アプリケーション内のトラフィックと通信が合理化されます。同じブリッジネットワーク上のコンテナ間のすべてのポートが開かれ、ポートが外部に公開されないためです。 したがって、フロントエンドサービスを公開するために必要なポートのみを開くことを選択できます。
次に、webserver
サービスを定義します。
~/node_project/docker-compose.yml
...
webserver:
image: nginx:mainline-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
volumes:
- web-root:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
depends_on:
- nodejs
networks:
- app-network
nodejs
サービスに対して定義した設定の一部は同じままですが、次の変更も加えました。
-
image
:これは、Docker Hubから最新のAlpine-basedNginx imageをプルするようにComposeに指示します。alpine
イメージの詳細については、How To Build a Node.js Application with Dockerのステップ3を参照してください。 -
ports
:これにより、ポート80
が公開され、Nginx構成で定義した構成オプションが有効になります。
次の名前付きボリュームとバインドマウントも指定しました。
-
web-root:/var/www/html
:これにより、web-root
というボリュームにコピーされたサイトの静的アセットがコンテナの/var/www/html
ディレクトリに追加されます。 -
./nginx-conf:/etc/nginx/conf.d
:これにより、ホスト上のNginx構成ディレクトリがコンテナ上の関連ディレクトリにバインドマウントされ、ホスト上のファイルに加えた変更がコンテナに反映されるようになります。 -
certbot-etc:/etc/letsencrypt
:これにより、ドメインに関連するLet’sEncryptの証明書とキーがコンテナの適切なディレクトリにマウントされます。 -
certbot-var:/var/lib/letsencrypt
:これにより、Let’sEncryptのデフォルトの作業ディレクトリがコンテナの適切なディレクトリにマウントされます。
次に、certbot
コンテナーの構成オプションを追加します。 必ずドメインとメール情報を自分のドメイン名と連絡先メールアドレスに置き換えてください:
~/node_project/docker-compose.yml
...
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- web-root:/var/www/html
depends_on:
- webserver
command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --staging -d example.com -d www.example.com
この定義は、Docker Hubからcertbot/certbot imageをプルするようにComposeに指示します。 また、名前付きボリュームを使用して、certbot-etc
のドメイン証明書とキー、certbot-var
のLet’s Encrypt作業ディレクトリ、web-root
のアプリケーションコードなどのリソースをNginxコンテナと共有します。
ここでも、depends_on
を使用して、webserver
サービスの実行後にcertbot
コンテナーを開始するように指定しました。
コンテナの起動時に実行するコマンドを指定するcommand
オプションも含まれています。 これには、次のオプションを含むcertonly
サブコマンドが含まれています。
-
--webroot
:これは、認証のためにwebrootプラグインを使用してファイルをwebrootフォルダーに配置するようにCertbotに指示します。 -
--webroot-path
:これはwebrootディレクトリのパスを指定します。 -
--email
:登録と回復のためのあなたの好みの電子メール。 -
--agree-tos
:これは、ACME’s Subscriber Agreementに同意することを指定します。 -
--no-eff-email
:これは、電子メールをElectronic Frontier Foundation(EFF)と共有したくないことをCertbotに通知します。 必要に応じて、これを省略しても構いません。 -
--staging
:これは、Let’sEncryptのステージング環境を使用してテスト証明書を取得することをCertbotに通知します。 このオプションを使用すると、構成オプションをテストし、ドメイン要求の制限を回避できます。 これらの制限の詳細については、Let’s Encryptのrate limits documentationを参照してください。 -
-d
:これにより、リクエストに適用するドメイン名を指定できます。 この場合、example.com
とwww.example.com
を含めました。 これらを独自のドメイン設定に置き換えてください。
最後のステップとして、ボリュームとネットワークの定義を追加します。 ここのユーザー名は、必ず自分の非ルートユーザーに置き換えてください。
~/node_project/docker-compose.yml
...
volumes:
certbot-etc:
certbot-var:
web-root:
driver: local
driver_opts:
type: none
device: /home/sammy/node_project/views/
o: bind
networks:
app-network:
driver: bridge
名前付きボリュームには、Certbot証明書と作業ディレクトリのボリューム、およびサイトの静的アセットのボリュームweb-root
が含まれます。 ほとんどの場合、Dockerボリュームのデフォルトドライバーはlocal
ドライバーであり、Linuxではmount
commandと同様のオプションを受け入れます。 このおかげで、アプリケーションの静的アセットを含むホスト上のviews
ディレクトリを実行時にボリュームにマウントするdriver_opts
を使用してドライバオプションのリストを指定できます。 その後、ディレクトリの内容をコンテナ間で共有できます。 views
ディレクトリの内容の詳細については、Step 2 of How To Build a Node.js Application with Dockerを参照してください。
終了すると、docker-compose.yml
ファイルは次のようになります。
~/node_project/docker-compose.yml
version: '3'
services:
nodejs:
build:
context: .
dockerfile: Dockerfile
image: nodejs
container_name: nodejs
restart: unless-stopped
networks:
- app-network
webserver:
image: nginx:mainline-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
volumes:
- web-root:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
depends_on:
- nodejs
networks:
- app-network
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- web-root:/var/www/html
depends_on:
- webserver
command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --staging -d example.com -d www.example.com
volumes:
certbot-etc:
certbot-var:
web-root:
driver: local
driver_opts:
type: none
device: /home/sammy/node_project/views/
o: bind
networks:
app-network:
driver: bridge
サービス定義を配置すると、コンテナを起動して証明書リクエストをテストする準備が整います。
[[ステップ-4 -—- ssl-certificates-and-credentialsの取得]] ==ステップ4—SSL証明書と資格情報の取得
コンテナはdocker-compose up
で開始できます。これにより、指定した順序でコンテナとサービスが作成および実行されます。 ドメインリクエストが成功すると、出力に正しい終了ステータスが表示され、webserver
コンテナの/etc/letsencrypt/live
フォルダに適切な証明書がマウントされます。
docker-compose up
および-d
フラグを使用してサービスを作成します。これにより、nodejs
およびwebserver
コンテナーがバックグラウンドで実行されます。
docker-compose up -d
サービスが作成されたことを確認する出力が表示されます。
OutputCreating nodejs ... done
Creating webserver ... done
Creating certbot ... done
docker-compose ps
を使用して、サービスのステータスを確認します。
docker-compose ps
すべてが成功した場合、nodejs
およびwebserver
サービスはUp
である必要があり、certbot
コンテナーは0
ステータスメッセージで終了します。
Output Name Command State Ports
------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
nodejs node app.js Up 8080/tcp
webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp
nodejs
およびwebserver
サービスのState
列にUp
以外のものが表示された場合、またはcertbot
の0
以外の終了ステータスが表示された場合)sコンテナの場合は、必ずdocker-compose logs
コマンドでサービスログを確認してください。
docker-compose logs service_name
これで、資格情報がdocker-compose exec
を使用してwebserver
コンテナにマウントされていることを確認できます。
docker-compose exec webserver ls -la /etc/letsencrypt/live
リクエストが成功した場合、次のような出力が表示されます。
Outputtotal 16
drwx------ 3 root root 4096 Dec 23 16:48 .
drwxr-xr-x 9 root root 4096 Dec 23 16:48 ..
-rw-r--r-- 1 root root 740 Dec 23 16:48 README
drwxr-xr-x 2 root root 4096 Dec 23 16:48 example.com
リクエストが成功することがわかったので、certbot
サービス定義を編集して、--staging
フラグを削除できます。
docker-compose.yml
を開きます:
nano docker-compose.yml
certbot
サービス定義を含むファイルのセクションを見つけ、command
オプションの--staging
フラグを--force-renewal
フラグに置き換えます。これにより、Certbotに次のことを通知します。既存の証明書と同じドメインを持つ新しい証明書を要求します。 certbot
サービス定義は次のようになります。
~/node_project/docker-compose.yml
...
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- web-root:/var/www/html
depends_on:
- webserver
command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com
...
これで、docker-compose up
を実行して、certbot
コンテナーとそれに関連するボリュームを再作成できます。 また、--no-deps
オプションが含まれ、webserver
サービスはすでに実行されているため、開始をスキップできることをComposeに通知します。
docker-compose up --force-recreate --no-deps certbot
証明書要求が成功したことを示す出力が表示されます。
Outputcertbot | IMPORTANT NOTES:
certbot | - Congratulations! Your certificate and chain have been saved at:
certbot | /etc/letsencrypt/live/example.com/fullchain.pem
certbot | Your key file has been saved at:
certbot | /etc/letsencrypt/live/example.com/privkey.pem
certbot | Your cert will expire on 2019-03-26. To obtain a new or tweaked
certbot | version of this certificate in the future, simply run certbot
certbot | again. To non-interactively renew *all* of your certificates, run
certbot | "certbot renew"
certbot | - Your account credentials have been saved in your Certbot
certbot | configuration directory at /etc/letsencrypt. You should make a
certbot | secure backup of this folder now. This configuration directory will
certbot | also contain certificates and private keys obtained by Certbot so
certbot | making regular backups of this folder is ideal.
certbot | - If you like Certbot, please consider supporting our work by:
certbot |
certbot | Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
certbot | Donating to EFF: https://eff.org/donate-le
certbot |
certbot exited with code 0
証明書を配置したら、Nginx構成の変更に進んでSSLを含めることができます。
[[step-5 -—- modifying-the-web-server-configuration-and-service-definition]] ==ステップ5—Webサーバーの構成とサービス定義の変更
Nginx構成でSSLを有効にするには、HTTPリダイレクトをHTTPSに追加し、SSL証明書とキーの場所を指定する必要があります。 また、Perfect Forward Secrecyに使用するDiffie-Hellmanグループの指定も含まれます。
これらの追加を含めるためにwebserver
サービスを再作成するので、ここで停止できます。
docker-compose stop webserver
次に、現在のプロジェクトディレクトリにDiffie-Hellmanキー用のディレクトリを作成します。
mkdir dhparam
openssl
commandを使用してキーを生成します。
sudo openssl dhparam -out /home/sammy/node_project/dhparam/dhparam-2048.pem 2048
キーを生成するのに少し時間がかかります。
関連するDiffie-HellmanおよびSSL情報をNginx構成に追加するには、最初に以前に作成したNginx構成ファイルを削除します。
rm nginx-conf/nginx.conf
ファイルの別のバージョンを開きます。
nano nginx-conf/nginx.conf
次のコードをファイルに追加して、HTTPをHTTPSにリダイレクトし、SSL資格情報、プロトコル、およびセキュリティヘッダーを追加します。 example.com
を独自のドメインに置き換えることを忘れないでください。
~/node_project/nginx-conf/nginx.conf
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
location / {
rewrite ^ https://$host$request_uri? permanent;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_buffer_size 8k;
ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
ssl_ecdh_curve secp384r1;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8;
location / {
try_files $uri @nodejs;
}
location @nodejs {
proxy_pass http://nodejs:8080;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# enable strict transport security only if you understand the implications
}
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
}
HTTPサーバーブロックは、.well-known/acme-challenge
ディレクトリへのCertbot更新要求のWebルートを指定します。 また、HTTPリクエストをルートディレクトリからHTTPSに転送するrewrite directiveも含まれています。
HTTPSサーバーブロックはssl
とhttp2
を有効にします。 HTTP / 2がHTTPプロトコルを反復処理する方法と、HTTP / 2がWebサイトのパフォーマンスにもたらすメリットの詳細については、How To Set Up Nginx with HTTP/2 Support on Ubuntu 18.04の概要を参照してください。 このブロックには、最新のSSLプロトコルと暗号を使用し、OSCPステープルがオンになっていることを確認するための一連のオプションも含まれています。 OSCPステープリングを使用すると、最初のTLS handshakeの間にcertificate authorityからタイムスタンプ付きの応答を提供できるため、認証プロセスを高速化できます。
このブロックは、SSLおよびDiffie-Hellmanの資格情報とキーの場所も指定します。
最後に、プロキシパス情報をこのブロックに移動しました。これには、try_files
ディレクティブを含むロケーションブロック、エイリアスされたNode.jsアプリケーションコンテナーへのリクエストの指定、セキュリティヘッダーを含むそのエイリアスのロケーションブロックが含まれます。これにより、SSL LabsやSecurity HeadersサーバーテストサイトなどでAの評価を取得できるようになります。 これらのヘッダーには、X-Frame-Options
、X-Content-Type-Options
、Referrer Policy
、Content-Security-Policy
、およびX-XSS-Protection
が含まれます。 HTTP Strict Transport Security
(HSTS)ヘッダーはコメント化されています—影響を理解し、その“preload” functionalityを評価した場合にのみ、これを有効にしてください。
編集が完了したら、ファイルを保存して閉じます。
webserver
サービスを再作成する前に、HTTPSに関連するポート情報や、Diffie-Hellmanボリューム定義など、docker-compose.yml
ファイルのサービス定義にいくつか追加する必要があります。
ファイルを開きます。
nano docker-compose.yml
webserver
サービス定義で、次のポートマッピングとdhparam
名前付きボリュームを追加します。
~/node_project/docker-compose.yml
...
webserver:
image: nginx:latest
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- web-root:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- dhparam:/etc/ssl/certs
depends_on:
- nodejs
networks:
- app-network
次に、dhparam
ボリュームをvolumes
定義に追加します。
~/node_project/docker-compose.yml
...
volumes:
...
dhparam:
driver: local
driver_opts:
type: none
device: /home/sammy/node_project/dhparam/
o: bind
web-root
ボリュームと同様に、dhparam
ボリュームは、ホストに格納されているDiffie-Hellmanキーをwebserver
コンテナーにマウントします。
編集が終了したら、ファイルを保存して閉じます。
webserver
サービスを再作成します。
docker-compose up -d --force-recreate --no-deps webserver
docker-compose ps
でサービスを確認してください:
docker-compose ps
nodejs
およびwebserver
サービスが実行されていることを示す出力が表示されます。
Output Name Command State Ports
----------------------------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
nodejs node app.js Up 8080/tcp
webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
最後に、ドメインにアクセスして、すべてが期待どおりに機能していることを確認できます。 ブラウザをhttps://example.com
に移動し、必ずexample.com
を独自のドメイン名に置き換えてください。 次のランディングページが表示されます。
ブラウザのセキュリティインジケータにロックアイコンも表示されます。 必要に応じて、SSL Labs Server Test landing pageまたはSecurity Headers server test landing pageに移動できます。 含まれている構成オプションは、両方でサイトにAの評価を与える必要があります。
[[step-6 -—- renewing-certificates]] ==ステップ6—証明書の更新
Let's Encrypt証明書は90日間有効です。そのため、自動更新プロセスを設定して、失効しないようにしてください。 これを行う1つの方法は、cron
スケジューリングユーティリティを使用してジョブを作成することです。 この場合、証明書を更新してNginx構成を再読み込みするスクリプトを使用して、cron
ジョブをスケジュールします。
プロジェクトディレクトリでssl_renew.sh
というスクリプトを開きます。
nano ssl_renew.sh
次のコードをスクリプトに追加して、証明書を更新し、Webサーバー構成を再読み込みします。
~/node_project/ssl_renew.sh
#!/bin/bash
/usr/local/bin/docker-compose -f /home/sammy/node_project/docker-compose.yml run certbot renew --dry-run \
&& /usr/local/bin/docker-compose -f /home/sammy/node_project/docker-compose.yml kill -s SIGHUP webserver
docker-compose
バイナリの場所を指定することに加えて、docker-compose
コマンドを実行するためにdocker-compose.yml
ファイルの場所も指定します。 この場合、docker-compose run
を使用してcertbot
コンテナーを開始し、サービス定義で提供されるcommand
を別のrenew
サブコマンドでオーバーライドします。これは証明書を更新します。期限切れに近づいています。 スクリプトをテストするために、ここに--dry-run
オプションを含めました。
次に、スクリプトはdocker-compose kill
を使用してSIGHUP
signalをwebserver
コンテナーに送信し、Nginx構成を再ロードします。 このプロセスを使用してNginx構成を再ロードする方法の詳細については、this Docker blog post on deploying the official Nginx image with Dockerを参照してください。
編集が終了したら、ファイルを閉じます。 実行可能にします。
chmod +x ssl_renew.sh
次に、rootcrontab
ファイルを開いて、指定した間隔で更新スクリプトを実行します。
sudo crontab -e
このファイルを初めて編集する場合は、エディターを選択するよう求められます。
crontab
no crontab for root - using an empty one
Select an editor. To change later, run 'select-editor'.
1. /bin/ed
2. /bin/nano <---- easiest
3. /usr/bin/vim.basic
4. /usr/bin/vim.tiny
Choose 1-4 [2]:
...
ファイルの最後に、次の行を追加します。
crontab
...
*/5 * * * * /home/sammy/node_project/ssl_renew.sh >> /var/log/cron.log 2>&1
これにより、ジョブ間隔が5分ごとに設定されるため、更新リクエストが意図したとおりに機能したかどうかをテストできます。 また、ジョブからの関連する出力を記録するために、ログファイルcron.log
を作成しました。
5分後、cron.log
をチェックして、更新要求が成功したかどうかを確認します。
tail -f /var/log/cron.log
更新が成功したことを確認する出力が表示されます。
Output- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates below have not been saved.)
Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/example.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Killing webserver ... done
crontab
ファイルを変更して、1日の間隔を設定できるようになりました。 たとえば、毎日正午にスクリプトを実行するには、ファイルの最終行を次のように変更します。
crontab
...
0 12 * * * /home/sammy/node_project/ssl_renew.sh >> /var/log/cron.log 2>&1
また、ssl_renew.sh
スクリプトから--dry-run
オプションを削除することもできます。
~/node_project/ssl_renew.sh
#!/bin/bash
/usr/local/bin/docker-compose -f /home/sammy/node_project/docker-compose.yml run certbot renew \
&& /usr/local/bin/docker-compose -f /home/sammy/node_project/docker-compose.yml kill -s SIGHUP webserver
cron
ジョブは、Let’s Encrypt証明書が適格なときに更新することで、証明書が失効しないようにします。 set up log rotation with the Logrotate utilityを使用して、ログファイルを回転および圧縮することもできます。
結論
コンテナを使用して、NginxリバースプロキシでNodeアプリケーションをセットアップおよび実行しました。 また、アプリケーションのドメインのSSL証明書を保護し、必要に応じてこれらの証明書を更新するためにcron
ジョブを設定しました。
Let’s Encryptプラグインの詳細に興味がある場合は、Nginx pluginまたはstandalone pluginの使用に関する記事を参照してください。
次のリソースを参照して、Docker Composeの詳細を確認することもできます。
Compose documentationは、マルチコンテナアプリケーションについてさらに学ぶための優れたリソースでもあります。