コンテナ化されたNode.jsアプリケーションをNginx、Let'sEncrypt、DockerComposeで保護する方法
序章
Node.jsアプリケーションの柔軟性とセキュリティを強化する方法は複数あります。 Nginx のようなリバースプロキシを使用すると、リクエストの負荷分散、静的コンテンツのキャッシュ、トランスポート層セキュリティ(TLS)の実装が可能になります。 サーバーで暗号化されたHTTPSを有効にすると、アプリケーションとの間の通信が安全に保たれます。
コンテナにTLS/SSLを使用してリバースプロキシを実装するには、ホストオペレーティングシステムで直接作業する場合とは異なる一連の手順が必要です。 たとえば、サーバーで実行されているアプリケーションの Let's Encrypt から証明書を取得する場合は、必要なソフトウェアをホストに直接インストールします。 コンテナを使用すると、別のアプローチを取ることができます。 Docker Compose を使用すると、アプリケーション、Webサーバー、およびCertbotクライアントのコンテナーを作成して証明書を取得できます。 これらの手順に従うことで、コンテナ化されたワークフローのモジュール性と移植性を活用できます。
このチュートリアルでは、Docker Composeを使用して、Nginxリバースプロキシを使用してNode.jsアプリケーションをデプロイします。 アプリケーションに関連付けられているドメインのTLS/SSL証明書を取得し、 SSLLabsから高いセキュリティ評価を受けていることを確認します。 最後に、 cron ジョブを設定して証明書を更新し、ドメインのセキュリティを維持します。
前提条件
このチュートリアルに従うには、次のものが必要です。
- Ubuntu 18.04サーバー、
sudo
権限を持つ非rootユーザー、およびアクティブなファイアウォール。 これらの設定方法のガイダンスについては、この初期サーバー設定ガイドを参照してください。 - サーバーにインストールされているDockerとDockerCompose。 Dockerのインストールに関するガイダンスについては、 Ubuntu18.04にDockerをインストールして使用する方法のステップ1と2に従ってください。 Composeのインストールに関するガイダンスについては、 Ubuntu18.04にDockerComposeをインストールする方法のステップ1に従ってください。
- 登録されたドメイン名。 このチュートリアルでは、全体を通してexample.comを使用します。 Freenom で無料で入手するか、選択したドメインレジストラを使用できます。
- 次の両方のDNSレコードがサーバー用に設定されています。 DigitalOceanアカウントに追加する方法の詳細については、このDigitalOcean DNSの概要をフォローしてください(使用している場合)。
- サーバーのパブリックIPアドレスを指す
example.com
のAレコード。 - サーバーのパブリックIPアドレスを指す
www.example.com
のAレコード。
- サーバーのパブリックIPアドレスを指す
ステップ1—ノードアプリケーションのクローン作成とテスト
最初のステップとして、Composeを使用してアプリケーションイメージを構築するために使用するDockerfileを含むNodeアプリケーションコードを使用してリポジトリのクローンを作成します。 最初に、リバースプロキシやSSLを使用せずに、 docker runコマンドを使用してアプリケーションをビルドし、実行することで、アプリケーションをテストできます。
root以外のユーザーのホームディレクトリで、 DigitalOceanCommunityGitHubアカウントからnodejs-image-demoリポジトリのクローンを作成します。 このリポジトリには、Dockerを使用してNode.jsアプリケーションを構築する方法で説明されているセットアップのコードが含まれています。
リポジトリをnode_project
というディレクトリに複製します。
git clone https://github.com/do-community/nodejs-image-demo.git node_project
node_project
ディレクトリに移動します。
cd node_project
このディレクトリには、 Docker node:10imageと現在のプロジェクトディレクトリの内容を使用してノードアプリケーションを構築するための手順を含む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のキャッシュとイメージレイヤーを利用します。コード。 最後に、この手順では、コンテナが非ルート node ユーザーとして実行され、アプリケーションコードとnode_modules
ディレクトリに適切な権限が設定されていることを指定しています。
このDockerfileとNodeイメージのベストプラクティスの詳細については、Dockerを使用してNode.jsアプリケーションを構築する方法のステップ3の完全な説明を参照してください。
SSLを使用せずにアプリケーションをテストするには、 dockerbuildと-t
フラグを使用してイメージをビルドおよびタグ付けできます。 画像をnode-demo
と呼びますが、別の名前を付けることもできます。
docker build -t node-demo .
ビルドプロセスが完了すると、 dockerimagesを使用してイメージを一覧表示できます。
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
を使用しますが、そのポートで別のプロセスを実行している場合は、必要に応じてこれを自由に変更してください。 これがどのように機能するかについての詳細は、ポートバインディングに関するDockerドキュメントのこの説明を参照してください。-d
:これはコンテナーをバックグラウンドで実行します。--name
:これにより、コンテナーに覚えやすい名前を付けることができます。
次のコマンドを実行して、コンテナーを作成します。
docker run --name node-demo -p 80:8080 -d node-demo
dockerpsを使用して実行中のコンテナーを検査します。
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
dockerstopでコンテナを停止します。 ここにリストされているCONTAINER ID
は、必ず独自のアプリケーションCONTAINER ID
に置き換えてください。
docker stop 4133b72391da
docker system pruneと-a
フラグを使用して、停止したコンテナーと、未使用のぶら下がっているイメージを含むすべてのイメージを削除できるようになりました。
docker system prune -a
出力でプロンプトが表示されたら、y
と入力して、停止したコンテナーとイメージを削除することを確認します。 これにより、ビルドキャッシュも削除されることに注意してください。
アプリケーションイメージをテストしたら、DockerComposeを使用して残りのセットアップの構築に進むことができます。
ステップ2—Webサーバー構成の定義
アプリケーションDockerfileを配置したら、Nginxコンテナーを実行するための構成ファイルを作成できます。 ドメイン名、ドキュメントルート、プロキシ情報、および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コンテナをリバースプロキシとして起動し、ノードアプリケーションコンテナにリクエストを渡すことができます。 また、Certbotのwebrootプラグインを使用してドメインの証明書を取得することもできます。 このプラグインは、 HTTP-01検証メソッドに依存しています。このメソッドは、HTTPリクエストを使用して、Certbotが特定のドメイン名に応答するサーバーからリソースにアクセスできることを証明します。
編集が終了したら、ファイルを保存して閉じます。 Nginxサーバーとロケーションブロックアルゴリズムの詳細については、Nginxサーバーとロケーションブロック選択アルゴリズムについての記事を参照してください。
Webサーバー構成の詳細が整ったら、docker-compose.yml
ファイルの作成に進むことができます。これにより、アプリケーションサービスと、証明書の取得に使用するCertbotコンテナーを作成できます。
ステップ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
:これは、context
やdockerfile
など、Composeがアプリケーションイメージをビルドするときに適用される構成オプションを定義します。 Docker Hub などのレジストリの既存のイメージを使用する場合は、代わりに image命令を使用して、ユーザー名、リポジトリ、イメージタグに関する情報を使用できます。context
:これは、アプリケーションイメージビルドのビルドコンテキストを定義します。 この場合、それは現在のプロジェクトディレクトリです。dockerfile
:これは、Composeがビルドに使用するDockerfile(ステップ1で確認したDockerfile)を指定します。image
、container_name
:これらは画像とコンテナに名前を適用します。restart
:これは再起動ポリシーを定義します。 デフォルトはno
ですが、コンテナが停止しない限り再起動するように設定しています。
セットアップは開発ではなく展開に重点を置いているため、このサービスにはバインドマウントが含まれていないことに注意してください。 詳細については、バインドマウントおよびボリュームに関する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
:これは、DockerHubから最新のAlpineベースNginxイメージをプルするようにComposeに指示します。alpine
イメージの詳細については、Dockerを使用してNode.jsアプリケーションを構築する方法のステップ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
この定義は、DockerHubからcertbot / certbotimageをプルするようにComposeに指示します。 また、名前付きボリュームを使用して、certbot-etc
のドメイン証明書とキー、certbot-var
のLet'sEncrypt作業ディレクトリ、web-root
のアプリケーションコードなど、Nginxコンテナとリソースを共有します。 ]。
ここでも、depends_on
を使用して、webserver
サービスの実行後にcertbot
コンテナーを開始するように指定しました。
コンテナの起動時に実行するコマンドを指定するcommand
オプションも含まれています。 これには、certonly
サブコマンドと次のオプションが含まれています。
--webroot
:これは、認証のためにwebrootプラグインを使用してファイルをwebrootフォルダーに配置するようにCertbotに指示します。--webroot-path
:これはwebrootディレクトリのパスを指定します。--email
:登録と復旧のためのご希望のメールアドレス。--agree-tos
:これは、ACMEのサブスクライバー契約に同意することを指定します。--no-eff-email
:これは、電子メールを Electronic Frontier Foundation (EFF)と共有したくないことをCertbotに通知します。 必要に応じて、これを省略してください。--staging
:これは、Let'sEncryptのステージング環境を使用してテスト証明書を取得することをCertbotに通知します。 このオプションを使用すると、構成オプションをテストして、ドメイン要求の制限を回避できます。 これらの制限の詳細については、Let'sEncryptのレート制限のドキュメントを参照してください。-d
:これにより、リクエストに適用するドメイン名を指定できます。 この場合、example.com
とwww.example.com
が含まれています。 これらを独自のドメイン設定に置き換えてください。
最後のステップとして、ボリュームとネットワークの定義を追加します。 ここでのユーザー名は、root以外のユーザーに置き換えてください。
〜/ 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コマンドと同様のオプションを受け入れます。 このおかげで、アプリケーションの静的アセットを含むホスト上のviews
ディレクトリを実行時にボリュームにマウントするdriver_opts
を使用してドライバーオプションのリストを指定できます。 その後、ディレクトリの内容をコンテナ間で共有できます。 views
ディレクトリの内容の詳細については、Dockerを使用してNode.jsアプリケーションを構築する方法のステップ2を参照してください。
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証明書とクレデンシャルを取得する
コンテナはdocker-composeup で開始できます。これにより、指定した順序でコンテナとサービスが作成および実行されます。 ドメイン要求が成功すると、出力に正しい終了ステータスが表示され、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
以外のものが表示された場合、または0
以外の終了ステータスが表示された場合certbot
コンテナーの場合は、必ず docker-composelogsコマンドを使用してサービスログを確認してください。
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を含めることができます。
手順5—Webサーバーの構成とサービス定義を変更する
Nginx構成でSSLを有効にするには、HTTPSへのHTTPリダイレクトを追加し、SSL証明書とキーの場所を指定する必要があります。 また、 Perfect ForwardSecrecyに使用するDiffie-Hellmanグループの指定も含まれます。
webserver
サービスを再作成してこれらの追加を含めるので、ここで停止できます。
docker-compose stop webserver
次に、現在のプロジェクトディレクトリにDiffie-Hellmanキーのディレクトリを作成します。
mkdir dhparam
opensslコマンドを使用してキーを生成します。
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ディレクティブも含まれています。
HTTPSサーバーブロックは、ssl
およびhttp2
を有効にします。 HTTP / 2がHTTPプロトコルを反復処理する方法と、それがWebサイトのパフォーマンスにもたらすメリットの詳細については、 Ubuntu18.04でHTTP/2サポートを使用してNginxをセットアップする方法の概要を参照してください。 このブロックには、最新のSSLプロトコルと暗号を使用し、OSCPステープリングがオンになっていることを確認するための一連のオプションも含まれています。 OSCPステープリングを使用すると、最初の TLSハンドシェイク中に、認証局からタイムスタンプ付きの応答を提供できます。これにより、認証プロセスを高速化できます。
このブロックは、SSLとDiffie-Hellmanの資格情報とキーの場所も指定します。
最後に、プロキシパス情報をこのブロックに移動しました。これには、 try_files ディレクティブを含むロケーションブロック、エイリアス化されたNode.jsアプリケーションコンテナへのリクエストのポインティング、およびそのエイリアスのロケーションブロックが含まれます。 SSLLabsやSecurityHeadersサーバーテストサイトなどでA評価を取得できるようにするセキュリティヘッダー。 これらのヘッダーには、 X-Frame-Options 、 X-Content-Type-Options 、 Referrer Policy 、 Content-Security-Policy 、およびX-XSS-Protection。 HTTP Strict Transport Security (HSTS)ヘッダーはコメント化されています。これは、影響を理解し、「プリロード」機能を評価した場合にのみ有効にしてください。
編集が終了したら、ファイルを保存して閉じます。
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
を自分のドメイン名に置き換えてください。 次のランディングページが表示されます。
ブラウザのセキュリティインジケータにも鍵のアイコンが表示されます。 必要に応じて、SSLLabsサーバーテストのランディングページまたはセキュリティヘッダーサーバーのテストランディングページに移動できます。 含まれている構成オプションは、両方でAの評価をサイトに与えるはずです。
ステップ6—証明書の更新
Let's Encryptの証明書は90日間有効なので、自動更新プロセスを設定して、証明書が失効しないようにする必要があります。 これを行う1つの方法は、cron
スケジューリングユーティリティを使用してジョブを作成することです。 この場合、証明書を更新してNginx構成を再読み込みするスクリプトを使用して、cron
ジョブをスケジュールします。
プロジェクトディレクトリでssl_renew.sh
というスクリプトを開きます。
nano ssl_renew.sh
次のコードをスクリプトに追加して、証明書を更新し、Webサーバー構成を再ロードします。
〜/ node_project / ssl_renew.sh
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose --no-ansi" DOCKER="/usr/bin/docker" cd /home/sammy/node_project/ $COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af
このスクリプトは、最初にdocker-compose
バイナリをCOMPOSE
という変数に割り当て、--no-ansi
オプションを指定します。このオプションはANSI制御なしでdocker-compose
コマンドを実行します。文字。 次に、docker
バイナリでも同じことを行います。 最後に、~/node_project
ディレクトリに移動し、次のdocker-compose
コマンドを実行します。
docker-compose run
:これにより、certbot
コンテナーが起動し、certbot
サービス定義で提供されるcommand
がオーバーライドされます。 ここでは、certonly
サブコマンドを使用する代わりに、renew
サブコマンドを使用しています。これにより、有効期限が近づいている証明書が更新されます。 スクリプトをテストするために、ここに--dry-run
オプションを含めました。- docker-compose kill :これにより、SIGHUPシグナルが
webserver
コンテナーに送信され、Nginx構成が再ロードされます。 このプロセスを使用してNginx構成をリロードする方法の詳細については、Dockerを使用した公式のNginxイメージのデプロイに関するこのDockerブログ投稿を参照してください。
次に、 docker system prune を実行して、未使用のコンテナーとイメージをすべて削除します。
編集が終了したら、ファイルを閉じます。 実行可能にする:
chmod +x ssl_renew.sh
次に、 root crontab
ファイルを開いて、指定した間隔で更新スクリプトを実行します。
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 COMPOSE="/usr/local/bin/docker-compose --no-ansi" DOCKER="/usr/bin/docker" cd /home/sammy/node_project/ $COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af
cron
ジョブは、Let's Encrypt証明書が適格なときに更新することで、証明書が失効しないようにします。 Logrotateユーティリティを使用してログローテーションを設定し、ログファイルをローテーションおよび圧縮することもできます。
結論
コンテナを使用して、Nginxリバースプロキシを使用してNodeアプリケーションをセットアップして実行しました。 また、アプリケーションのドメインのSSL証明書を保護し、cron
ジョブを設定して、必要に応じてこれらの証明書を更新します。
Let's Encryptプラグインの詳細については、Nginxプラグインまたはスタンドアロンプラグインの使用に関する記事をご覧ください。
次のリソースを参照して、DockerComposeの詳細を確認することもできます。
- Ubuntu18.04にDockerComposeをインストールする方法。
- Ubuntu16.04でDockerおよびDockerComposeを使用して継続的インテグレーションテスト環境を構成する方法。
- Docker Composeを使用してLaravel、Nginx、およびMySQLをセットアップする方法。
構成ドキュメントは、マルチコンテナアプリケーションについてさらに学ぶための優れたリソースでもあります。