はじめに
WordPress は、世の中で最も人気のあるコンテンツ管理システム(CMS)の1つです。統計的には、全ウェブサイトの39%以上を支えています。プラグインによる拡張性や柔軟なテンプレートシステムにより、人気の高い選択肢となっています。数秒で外観を変更することができます。さらに、管理はWebインターフェースを通じて行うことができ、多くの技術的知識を必要としません。
さらに、WordPressは無料でオープンソースであり、MySQL データベースとPHP処理で構築されています。LAMPスタック(Linux、Apache、MySQL、PHP)上にWordPressをデプロイする ことや、LEMPスタック(Linux、Nginx、MySQL、PHP)上にデプロイすることができます。しかし、デプロイするたびにスタックをセットアップするのは時間がかかることがわかります。
幸いなことに、クラウドコンピューティング, Docker、そしてDocker Compose などの現代的なソフトウェア配信手法により、開発者体験全体がスムーズになりました。これらのツールは、アプリケーションをデプロイするたびに個々のコンポーネントをインストールして設定するオーバーヘッドを回避し、任意のスタックをセットアップするプロセスを簡素化します。代わりに、イメージをプルして作成し、Dockerコンテナで実行するために使用される設定ファイルを記述することで、コマンド1つでアプリケーションをデプロイできるようになります。
コンテナは、軽量で仮想化された、ポータブルでソフトウェア定義の標準化された環境であり、 物理ホストマシン上で実行されている他のソフトウェアから隔離された状態でソフトウェアを実行できます。Docker Composeを使用すると、複数のコンテナを管理し、それらが確実に通信できるようにすることができます。たとえば、アプリケーションのソースコードとデータベースは通信する必要があります。
このチュートリアルでは、 複数のコンテナ化されたWordPressアプリケーションを構築します。完全なWordPressアプリには、MySQLデータベース、Nginxサーバー、WordPressソースコードの3つのコンテナが必要です。 現代のウェブサイトではセキュリティが最優先事項であるため、Let’s Encrypt からSSL証明書を取得して、インストールを保護します。その後、cron ジョブを設定して、証明書を定期的に確認および更新し、ウェブサイトのセキュリティが継続的に維持されるようにします。
前提条件
- これは実践的なチュートリアルであるため、初期の動作環境としてUbuntu 20.04がインストールされている必要があります。また、sudo権限を持つ非ルートユーザーも必要です。こちらは、Ubuntuサーバーのセットアップに役立つステップバイステップのチュートリアル.
- です。また、Dockerをインストールする必要があります。これについては、Ubuntu 18.04にDockerをインストールして操作する方法.
- のチュートリアルを参照してください。Docker Composeのインストール。次のチュートリアル「Ubuntu 20.04にDocker Composeをインストールして設定する方法」のステップ1に従うことができます。.
- 登録済みのドメイン名は、Let’s EncryptからTLS/SSL証明書を取得するために必要です。このチュートリアルでは、
example.com. - を使用します。VPSにトラフィックを向けるようにDNSレコードを設定します。2つのDNSレコードが必要です。
- サーバーのパブリックIPアドレスを指す、
example.comのAレコード。 - サーバーのパブリックIPアドレスを指す、
www.example.comのAレコード。
- サーバーのパブリックIPアドレスを指す、
ステップ1:Webサーバーの設定を定義する
Webサーバーはウェブサイトのファイルを保持し、ユーザーがWebアプリケーションにアクセスできるようにします。したがって、最初のステップでWebサーバーの設定を定義するのが適切です。ここでは、Nginxサーバー設定ファイルを定義します。これにはWordPress固有のlocationブロックが含まれます。また、証明書の自動更新のために、Let’s Encryptの検証リクエストをCertbotクライアントに転送するlocationブロックも含めます。
まず、プロジェクト用のディレクトリを作成することから始めましょう。お好みのディレクトリ名を選択できます。このチュートリアルでは、wordpress_dockerを使用します。次のコマンドを入力してディレクトリを作成し、その中に移動します。
|
1 |
mkdir wordpress_docker && cd wordpress_docker |
次に、次のコマンドを使用して、Nginx設定ファイルを保持するディレクトリを作成します。
|
1 |
mkdir nginx-conf |
次のコマンドで nano を使用してファイルを開きます。
|
1 |
nano nginx-conf/nginx.conf |
このファイルでは、Nginxサーバーブロック設定の基本的なディレクティブを定義します。これには、サーバー名、ドキュメントルート、および証明書、静的ファイル、PHP処理に対するCertbotプラグインのリクエストを転送するためのlocationブロックのディレクティブが含まれます。詳細については、次のチュートリアルを参照してください:Let’s EncryptでNginxを保護する方法。次のコードをファイルに追加し、example.com を登録済みのドメイン名に置き換えてください:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
server { listen 80; listen [::]:80; server_name example.com www.example.com; index index.php index.html index.htm; root /var/www/html; location ~ /.well-known/acme-challenge { allow all; root /var/www/html; } location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } location ~ /\.ht { deny all; } location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { log_not_found off; access_log off; allow all; } location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ { expires max; log_not_found off; } } |
追加したセクションを定義しましょう:
-
ディレクティブ:
listen:Nginxにポート80でリッスンするように指示します。これにより、Certbotのwebrootプラグインを使用して証明書のリクエストを行うことができます。SSL証明書を取得したら、この設定を更新してポート443.server_name:これは、この設定が処理するドメイン名を定義します。ここで定義されたドメイン名へのトラフィックは、この特定のサーバーブロック、つまりドキュメントroot.root:上記のドメイン名へのリクエストのルートディレクトリを定義します。通常は、実際のウェブサイトファイルが保存されているディレクトリです。ここでは、ディレクトリを/var/www/htmlに設定しました。これはDockerマウントポイントとして作成されます(コンテナのビルド時に実行されます。このプロセスの指示は、以下の内部で定義します:WordPress Dockerfile.index:これは、リクエストを処理する際にインデックスまたはWebサーバーへのエントリポイントとして使用されるファイルを定義します。Nginxが優先するように、index.htmlの前にindex.phpを移動しました:index.php.
-
Locationブロック:
location ~ /.well-known/acme-challenge:Certbotが一時ファイルを追加して、指定されたドメインのDNSが、SSL証明書を要求している特定のサーバーを指していることを検証する、well-knownディレクトリへのリクエストを処理します。このステップを機能させるために、このチュートリアルで使用しているexample.comの代わりに、有効なドメインを追加する必要があります。location /:URIリクエストを取得し、処理のための引数を要求するためにWordPressのindex.phpに制御を渡します。location ~ \.php$:PHPの処理を処理し、リクエストをWordPressコンテナに渡します(これについては後のステップで設定ファイルを定義します)。ここでは、FastCGIプロトコル固有の設定を定義しました。これは、WordPressのDockerイメージがphp:fpmイメージに基づいているためです。Nginxは、PHP固有のリクエストに対して独立したPHPプロセッサを使用します。ここでは、php-fpmプロセッサを使用します。これは、php:fpmDockerイメージに付属しているものです。location ~ /\.ht:.htaccessファイルを処理します(Nginxはこれを使用しません)。deny allディレクティブにより、これらのファイルがウェブサイトの訪問者に提供されないようになります。location = /favicon.ico, location = /robots.txt:定義にあるように、これにより/favicon.icoおよび/robots.txtファイルへのリクエストのログ記録を防ぎます。location ~* \.(css|gif|ico|jpeg|jpg|js|png)$:静的ファイルへのリクエストのログ記録をオフにし、サーバーの負荷を軽減するためにそれらがキャッシュされるようにします。
これで、CTRL+X, Yを押し、次にENTERを押すことで、ファイルを保存して閉じることができます。これで最初のステップは完了です。
Step 2: Define Environment Variables
環境変数は、WordPressアプリケーションとデータベース間の通信を容易にするために必要です。また、アプリケーションデータが永続化されることも保証します。環境変数には、データベースの資格情報などの機密情報や、データベース名やホストなどの機密ではない情報が含まれます。
セキュリティ上の理由から、プロジェクトのリポジトリに機密情報を追加しないことを常にお勧めします。したがって、Docker Composeファイルに機密の値を設定する代わりに、.envファイル内にMySQLの資格情報を定義します。このファイルはプロジェクトのリポジトリにコミットされないため、公開されるリスクを回避できます。プロジェクトのroot ~/wordpress_docker内で、.envファイルを開きます:
|
1 |
nano .env |
|
1 2 3 |
MYSQL_ROOT_PASSWORD=your_strong_root_password MYSQL_USER=your_wordpress_database_user MYSQL_PASSWORD=strong_wordpress_database_password |
次に行う必要があるのは、.envファイルを.gitignoreおよび.dockerignoreファイルに追加して、それぞれリポジトリやDockerイメージに追加されないようにすることです。
このチュートリアルでは必須ではありませんが、バージョン管理にGitを使用したい場合は、次のコマンドを入力して現在のディレクトリをgitリポジトリとして初期化します:
|
1 |
git init |
nanoで.gitignoreを開きます:
|
1 |
nano .gitignore |
次の行を追加します:
|
1 |
.env |
ファイルを保存して閉じます。次に、nanoで.dockerignoreを開きます:
|
1 |
nano .dockerignore |
次の行を追加します:
|
1 |
.env |
その際、必要に応じて、アプリケーションの開発に関連する他のファイルやディレクトリを追加することもできます:
|
1 2 3 |
.env .git docker-compose.yml |
完了したらファイルを保存して閉じます。このステップは以上です。Docker Composeの定義に進みましょう。
ステップ 3: Docker Composeを使用したサービスの設定
Docker Composeは、イメージをビルドするためにdocker-compose.ymlファイルを使用します。このファイルには、アプリケーションの完全なセットアップのためのサービス定義が含まれています。サービス定義は、基本的にはコンテナがどのように実行されるかについての指示です。サービスとは、実際に実行されているコンテナのことです。
Docker Composeを使用すると、共有ネットワークとボリュームによってさまざまなサービスを相互にリンクさせることで、マルチコンテナアプリケーションの異なるサービスを定義できます。このチュートリアルでは、アプリケーション用にウェブサーバー、WordPressのインストール、データベースの3つのコンテナを定義し、実際に動作を確認します。さらに、証明書の更新用にCertbotクライアントを実行する4つ目のコンテナを追加します。
次のコマンドを入力して、docker-compose.ymlファイルを作成します。
|
1 |
nano docker-compose.yml |
The first line in a docker-compose.ymlファイルの最初の行は、version definition行です。ここでは3を設定しています。次に、サービスの定義を開始できます。ファイルに次のコードスニペットを追加して、dbサービスを定義します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
version: '3' services: #MySQL Service db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network |
以下のdbサービス定義の内容について説明します。
image:コンテナのベースとなるイメージを決定します。特定のバージョン(mysql:8.0)を指定する方が、最新のタグ(mysql:latest)を使用するよりも常に望ましいです。将来のバージョンのMySQL imagesは、このイメージを再ビルドした際にアプリケーションと競合する可能性があります。詳細については、Dockerfiles Best practices on the official Dockerfile Docs.container_name:ここでコンテナ名を指定します。restart:このディレクティブは、コンテナの再起動動作を決定します。デフォルトはnoですが、ここでは常にrestartするように設定しています(ただし、手動で停止された場合を除きます)。env_file:このディレクティブは、アプリケーションで使用される環境変数が含まれるファイル(.env)の場所を指定するために使用されます。environment:追加の環境変数を指定するために使用されます。このチュートリアルでは、アプリケーションのデータベース名を保持するためにMYSQL_DATABASE変数を指定しています。データベース名は、次のファイルに含めることができます:docker-compose.yml.volumes:マウント場所を指定するために使用されます。この例では、volumeという名前のdbdataボリュームを、コンテナ上の/var/lib/mysqlディレクトリにマウントしています。これは通常、MySQLの標準データディレクトリです。command:このディレクティブは、イメージのデフォルトのCMD instructionを上書きするコマンドを指定します。コンテナ内でMySQLサーバーを起動するDockerイメージの標準的なmysqldコマンドにオプションを追加しました。追加したオプションは--default-authentication-plugin=mysql_native_passwordで、これによりMySQLのデフォルトの認証プラグインがパスワード認証(mysql_native_password)を使用するように更新されます。これは、PHP(WordPressアプリケーション)がデータベースにアクセスするためにユーザー名とパスワードを使用するため、動作に必要です。新しいMySQLバージョンでは、default authentication plugin has changed。ただし、ほとんどのアプリケーションはパスワード認証を使用します。そのため、アプリケーションを動作させるにはこの設定を変更する必要があります。networks:このディレクティブは、dbサービスがapp-networkに参加することを指定するために使用されます。これはチュートリアルの進行に合わせて定義します。
次に、WordPressアプリケーションのサービス設定を定義しましょう。サービス名とcontainer_nameをappと呼びます。適切なインデントに注意しながら、次のコードスニペットをdbサービス定義の下に追加してください。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#WordPressアプリケーションコードサービス app: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: app restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - app:/var/www/html networks: - app-network |
Just like we did with the dbサービスと同様に、コンテナに名前を付け、再起動ポリシーを定義しました。追加したその他のオプションは以下の通りです:
depends_on: このディレクティブは、コンテナが依存関係の順序で起動されることを保証します。今回のケースでは、appコンテナはdbコンテナに依存しています。したがって、dbコンテナが起動した後に起動します。WordPressアプリが機能するためにはMySQLデータベースが利用可能である必要があるため、この順序で実行される必要があります。image: コードスニペットにあるように、WordPress version 5.1.1 fpm alpineイメージを使用します。NginxがPHP処理に必要とするphp-fpmプロセッサについて説明しました。このイメージがその処理を担当します。また、Alpine Linux projectに基づいたalpineイメージは、イメージサイズを小さく抑えるのに役立ちます。イメージのバリエーションに関する詳細情報が必要な場合は、こちらのリンクからDocker Hub Wordpress images.env_file: データベースの認証情報が含まれている.envファイルの場所を指定します。environment: このディレクティブは、追加の環境変数を定義します。今回のケースでは、WordPressが期待する変数を定義し、それらに.envファイルの変数の値を割り当てています。これらは、WORDPRESS_DB_USER,WORDPRESS_DB_PASSWORD、およびWORDPRESS_DB_HOSTであり、これはdbコンテナで実行されているMySQLサーバーを指し、MySQLのデフォルトポートからアクセス可能です。3306。最後に、WORDPRESS_DB_NAMEが表示されており、これはWordPressに設定されています。同じ値がdbコンテナのMySQLサービス定義でも指定されています:MYSQL_DATABASE=wordpress.volumes: このディレクティブは、appというボリュームを、/var/www/htmlマウントポイントにマウントします。これはWordPress imageによって作成されます。ボリュームに名前を付けることで、アプリケーションコードを他のコンテナと共有できるようになります。networks: 最後に、appコンテナをapp-networkに追加して、ネットワーク上の他のコンテナと通信できるようにします。
WordPressイメージのappサービスコンテナについては以上です。次に、Nginxイメージのwebserverサービスを定義しましょう。まず、docker-compose.ymlファイルのappサービス定義の下に、次のコードスニペットを追加します:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#Webserver Nginx サービス webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network |
すでにdepends_onオプションについては説明しました。このwebserverサービスの場合、コンテナはappコンテナが起動した後に起動します。ウェブサーバーコンテナは、alpine Nginx imageに基づいています。これには、以前のサービス定義と同様の再起動ポリシーがあります。webserverサービス定義のその他のオプションは以下の通りです:
ports: ホストマシンとコンテナの間のポートをバインドします。ステップ1において、ポート80をnginx.confファイルで定義しました。このポートは、コンテナ上のポート80にマッピングされます。volumes: このオプションの下には、バインドマウントと名前付きボリュームの組み合わせがあります:app:/var/www/html: このボリューム定義は、WordPressアプリケーションを、先ほどNginxサーバーブロックでルートとして設定した/var/www/htmlディレクトリにマウントします。./nginx-conf:/etc/nginx/conf.d: この定義は、ホストマシン上のNginx設定ディレクトリを、コンテナ用に定義したNginx設定ディレクトリにバインドマウントします。したがって、ホストマシン上での変更は自動的にコンテナに反映されます。certbot-etc:/etc/letsencrypt: この定義は、ドメインのLet’s Encrypt証明書と鍵をコンテナ上の適切なディレクトリにマウントします。
networks: 以前のサービス定義と同様に、networksディレクティブは、webserverサービスをapp-networks.
に追加します。webserverの定義が完了したので、Certbotサービスの手順を追加しましょう。これにより、Let’s EncryptからTLS/SSL証明書を取得する処理が行われます。Nginxサーバーのセキュリティ保護について詳しく知りたい場合は、Let’s EncryptでNginxを保護する方法に関するこのチュートリアルが優れた情報源です。
次に、webserverサービスの下に以下のコードスニペットを追加します。正しいドメイン名とメールアドレスを設定することを忘れないでください:
|
1 2 3 4 5 6 7 8 9 10 |
#certbot サービス certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com |
The certbotイメージは、webserverが起動した後にのみ起動します。これはdepends_onディレクティブがあるためです。Docker Composeは、定義に従ってDocker HubからCertbotイメージをプルします。
volumesの定義において、Certbotコンテナはcertbot-etc内のドメイン証明書と鍵をNginxのwebserverコンテナと共有し、アプリケーションコードをappコンテナと共有します。
Under the command定義の下で、コンテナのデフォルトのCertbotのcertonlyコマンドを、以下に示す追加オプションとともに実行するサブコマンドを指定しました。
-
--webroot: 認証のためにwebrootフォルダにファイルを配置するwebrootプラグインの使用を指定します。--webroot-path: webrootディレクトリのパスを指定します。--agree-tos: ACMEの利用規約への同意を指定します。.--no-eff-email: メールアドレスをEFFと共有したくないことを指定します。共有したい場合は、これを省略できます。--staging: 実際の証明書を取得する前に、設定をテストするためにLet’s Encryptのステージング環境からテスト証明書を最初に取得することをCertbotに指示します。Let’s Encryptにはドメインリクエストのレート制限があります。そのため、最初に設定をテストすることで、ドメインが制限されるのを防ぐことができます。-d: このオプションは、証明書リクエストのドメイン名を受け取ります。このチュートリアルでは、example.comとwww.example.comを含めています。実際に登録されているドメインを指定してください。
作成したdocker-compose.ymlファイルはほぼ完成しています。ただし、Certbotサービスの下にネットワークとボリュームの定義も追加する必要があります:
|
1 2 3 4 5 6 7 8 9 10 |
#Volumes volumes: certbot-etc: app: dbdata: #Networks networks: app-network: driver: bridge |
このvolumesキーは、このcomposeファイルで定義されているすべてのサービス(コンテナ)と共有されるボリュームを定義します:certbot-etc, app、およびdbdata。Dockerが作成するボリュームの内容は、ホストファイルシステム上のDockerによって管理されるディレクトリに保存されます:/var/lib/docker/volumes/。その後、各ボリュームの内容は、そのボリュームを使用する任意のコンテナにマウントされます。これにより、コンテナ間でデータやコードを共有することが可能になります。
The networks キーは、コンテナ間の通信を可能にするブリッジネットワークを定義します。同じブリッジネットワーク上にあるコンテナ(たとえば webserver や db など)は、外部ネットワークにトラフィックを公開することなく、ポートを介して安全に通信できます。フロントエンドのウェブサイトページへのアクセスを許可するために、ポート 80 のみを公開します。
完成した docker-compose.yml ファイルは次のようになります:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
version: '3' services: #MySQL サービス db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network #WordPress アプリケーションコードサービス app: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: app restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - app:/var/www/html networks: - app-network #Webserver Nginx サービス webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network #certbot サービス certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com #ボリューム volumes: certbot-etc: app: dbdata: #ネットワーク networks: app-network: driver: bridge |
ファイルを保存して閉じることができます。次のステップでは、コンテナの起動とテスト、および証明書のリクエストを行います。
ステップ 4: コンテナの実行とSSL証明書の取得
Docker Composeの最大の利点は、すべてのサービスをdocker-compose.yml ファイルを使用すると、次の1つのコマンドだけで、すべてのコンテナを起動できます。 docker-compose up。このコマンドは、指定されたすべての命令を実行します。ドメインのリクエストが成功した場合、ターミナルに正しい終了ステータスが表示されるはずです。コンテナを作成するには、次のコマンドを入力します。-d フラグは、コンテナをバックグラウンドで実行するためのものです。
|
1 |
docker-compose up -d |
下のスクリーンショットのような出力が表示されれば、サービスは正常に作成されています。
サービスのステータスを確認するには、次のコマンドを実行します。docker-compose ps コマンド:
|
1 |
docker-compose ps |
すべてが成功した場合、コマンドの出力は以下のようになります。app, db、および webserver コンテナの状態は up になり、certbot コンテナのステータスは Exit0 になるはずです。
もし、Up 以外の状態が app, db または webserver, の状態列に表示されている場合、あるいは Exit ステータスが 0 ではない場合(certbot コンテナにおいて)、何らかのエラーが発生しています。次のコマンドを使用して、各コンテナのログを確認できます:docker-compose logs。そして、次のように service_name:
|
1 |
docker-compose logs service_name |
たとえば、次のコマンドを入力して、certbot コンテナのログを確認できます。
|
1 |
docker-compose logs certbot |
証明書が webserver コンテナにマウントされているか確認するには、docker-compose exec コマンドを使用します。
|
1 |
docker-compose exec webserver ls -la /etc/letsencrypt/live |
もし、example.com 以外の実際に登録されたドメイン名を使用し、証明書のリクエストが成功した場合、以下のような出力が表示されるはずです。
証明書のリクエストが成功したことを確認したら、docker-compose.yml ファイルを編集して、--staging フラグを削除できます。次のコマンドでファイルを開きます:nano:
|
1 |
nano docker-compose.yml |
Certbot サービス定義セクションまでスクロールし、command オプション内の --staging フラグを --force-renewal フラグに置き換えます。これにより、同じドメインの証明書の更新をリクエストしていることを Certbot に伝えます。Certbot のサービス定義は以下のようになります。
|
1 2 3 4 5 6 7 8 9 10 |
#certbot service certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com |
編集が終わったらファイルを保存します。
次のコマンドを入力して、certbot コンテナを再作成します。含まれている --no-deps フラグは、Web サーバーサービスがすでに実行されているため、その再起動をスキップするよう Compose に指示します。
|
1 |
docker-compose up --force-recreate --no-deps Certbot |
コマンドを実行すると、次のスクリーンショットのように出力され、証明書のリクエストが成功したことが示されます。
このステップは以上です。次のステップでは、SSL 証明書を含めるように Nginx の設定ファイルを変更します。
ステップ 5:Nginx の設定とサービス定義での SSL の有効化
Nginx が安全な SSL 経由でトラフィックを処理できるようにするため、まず Nginx の設定ファイルを変更して、HTTP から HTTPS へのリダイレクトを追加します。次に、証明書とキーの場所を指定し、最後にセキュリティパラメータとヘッダーを追加します。
設定ファイルを変更する前に、次のコマンドで 推奨される Nginx セキュリティパラメータ を Certbot の GitHub リポジトリから curl を使用して取得する必要があります。
|
1 |
curl -sSLo nginx-conf/options-ssl-nginx.conf |
コマンドが実行され、取得したパラメータがoptions-ssl-nginx.confというファイルに保存されます。保存先はnginx-confディレクトリ内です。次のコマンドを使用して新しい設定ファイルを作成できるように、Nginx設定ファイルを削除します。
|
1 2 |
rm nginx-conf/nginx.conf nano nginx-conf/nginx.conf |
空になったnginx.confファイルに、HTTPからHTTPSへのリダイレクト、SSL証明書プロトコル、およびセキュリティヘッダーを含む次のコードを追加します。先ほどと同様に、example.comドメインをご自身が登録したドメインに置き換えてください:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
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; index index.php index.html index.htm; root /var/www/html; server_tokens off; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; include /etc/nginx/conf.d/options-ssl-nginx.conf; 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-セキュリティ-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always; # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # 影響を理解している場合のみ、Strict Transport Securityを有効にしてください location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } location ~ /\.ht { deny all; } location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { log_not_found off; access_log off; allow all; } location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ { expires max; log_not_found off; } } |
ポートを使用する、保護されていないリクエストを処理する最初のサーバーブロックでは、80、Certbotの更新リクエスト用のウェブルートを指定します。また、リダイレクトディレクティブも含めており、これはHTTPリクエストをHTTPSにリダイレクトします。.
2番目のサーバーブロックは、安全なHTTPSトラフィックを処理します。このトラフィックはポート443で受信されます。ご覧のとおり、SSLとHTTP2. HTTP/2はサーバーのパフォーマンスを向上させます。詳細については、HTTP/2に関する公式のNginxドキュメントを参照してください。.
このブロックでは、NginxがSSL証明書とキーの場所、およびcurlがnginx-conf/options-ssl-nginx.confディレクトリに保存した推奨されるCertbotセキュリティパラメータを含めるように指定しています。
追加のセキュリティヘッダーは、Security HeadersやSSL Labsなどのセキュリティテストサイトにおけるウェブサイトの評価を向上させるのに役立ちます。詳細については、これらのヘッダーのリンクを参照してください:X-Frame-Options, Referrer Policy, X-Content-Type-Options, X-XSS-Protection, Content-Security-Policy。また、HTTP Strict Transport Security(HSTS)ヘッダーはコメントアウトしています。そのプリロード機能について読み、有効にするかどうかを自由に決定してください。
その他のディレクティブ(root、index、WordPress固有のlocationブロックなど)は、ステップ1で説明したとおりです。編集が完了したら、ファイルを保存して閉じてかまいません。
これで、HTTPSトラフィックを有効にし、ポート443,を使用するようになったため、ウェブサーバーのサービス定義でもそのポートを有効にする必要があります。次のコマンドを入力して、docker-compose.ymlファイルをnanoで開きます:
|
1 |
nano docker-compose.yml |
webserverセクションのportsオプションの下に、以下のようにハイライトされたポート443のマッピングを追加します:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" - "443:443" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network |
完成したdocker-compose.ymlファイルは次のようになります:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
version: '3' services: #MySQLサービス db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network #WordPressアプリケーションコードサービス app: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: app restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - app:/var/www/html networks: - app-network #WebサーバーNginxサービス webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" - "443:443" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network #certbotサービス certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com #ボリューム volumes: certbot-etc: app: dbdata: #ネットワーク networks: app-network: driver: bridge |
すべてが正しく表示されていることを確認したら、ファイルを保存して閉じます。その後、次のコマンドを実行して、webserver サービスを再作成します:
|
1 |
docker-compose up -d --force-recreate --no-deps webserver |
|
1 |
docker-compose ps |
すべてのコンテナが実行されたので、WebインターフェースからWordPressの設定を進めることができます。
ステップ6:WebインターフェースからWordPressの設定を完了する
インストールを続行するには、サーバーのドメイン名にアクセスしてください。WordPressのセットアップホームページが表示されるはずです。続行する前に言語を選択するよう促されます。
言語を選択して、続行 をクリックして次のページに進みます。
このページでは、ウェブサイトのタイトルを入力し、覚えやすいユーザー名と強力なパスワードを選択します。セキュリティ上の理由から、ユーザー名としてAdmin を使用しないことをお勧めします。メールアドレスを入力し、WordPress をインストール ボタンをクリックして、WordPressのインストールを開始します。
インストールが完了すると、ログイン画面が表示され、設定したユーザー名とパスワードを入力します。有効な資格情報を入力すると、WordPressのダッシュボードが表示されるはずです。
これでWordPressのインストールが正常に完了しました!次に、SSL証明書が自動更新されるようにするための手順を実行する必要があります。
ステップ 7: SSL証明書の自動更新の設定
Let’s EncryptのTLS/SSL証明書の有効期限は90日間のみです。期限切れにならないように自動更新の設定を行う必要があります。これは、スクリプトを作成し、それをcronジョブ ユーティリティでスケジュール設定することで実現できます。このステップでは、証明書を更新するスクリプトの作成方法を説明します。その後、cronジョブユーティリティを使用して定期的に実行するようにスケジュールし、有効期限が近づいたときに証明書を更新します。
の内部で、wordpress_docker プロジェクトディレクトリで、ssl_renewer.sh という名前のスクリプトをnano:
|
1 |
nano ssl_renewer.sh |
自動更新とNginx設定の再読み込みを処理するために、スクリプトに次のコードを追加します。ハイライトされたユーザー名を、非rootユーザー名に置き換えることを忘れないでください。
|
1 2 3 4 5 6 7 8 |
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose –ansi never" DOCKER="/usr/bin/docker" cd /home/hackins/wordpress_docker/ $COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af |
このスクリプトでは、docker-compose バイナリをCOMPOSE という変数に割り当てます。また、–ansi never オプションも含めており、これによりスクリプトはdocker-compose コマンドをANSI制御 文字なしで実行するよう指示されます。さらに、DockerバイナリをDOCKER.
という変数に割り当てます。その後、スクリプトはプロジェクトディレクトリであるwordpress_docker に移動し、次のコマンドを実行します。
docker-compose run: certbotコンテナを起動し、certbotサービス定義で指定したコマンドをオーバーライドします。certonlyサブコマンドを実行する代わりに、renewサブコマンドを実行して、Let’s EncryptのSSL/TLS証明書の有効期限が近づいている場合に更新します。docker-compose kill: SIGHUP シグナルをwebserverコンテナに送信して、Nginxの設定を再読み込みします。Dockerによる次のチュートリアルを参照するとよいでしょう:「公式Nginx Dockerイメージの使用方法」.docker system prune: このコマンドは、使用されていないすべてのコンテナとイメージを削除します。
編集が完了したら、ファイルを保存して閉じます。次に、以下のコマンドを実行して実行可能にします。
|
1 |
chmod +x ssl_renewer.sh |
実行可能にしたら、rootのcrontab ファイルを開き、指定する間隔でスクリプトを定期的に実行します。
|
1 |
sudo crontab -e |
初めて使用する場合、crontab は好みのエディタを選択するよう求めてきます:
好みのエディタを選択し、Enter を押してファイルを開きます。ファイルの一番下に次の行を追加します。
|
1 |
*/5 * * * * /home/hackins/wordpress_docker/ssl_renewer.sh >> /var/log/cron_docker.log 2>&1 |
これにより、更新スクリプトが機能するかどうかをテストできるように、間隔が5分に設定されます。また、ジョブからの出力を保持するログファイルも指定しました:cron_docker.log.
5分間待って、cron.log を確認します。:スクリプトが更新リクエストに成功したかどうかを確認します:
|
1 |
tail -f /var/log/cron_docker.log |
リクエストが成功した場合、以下のスクリーンショットのような内容が表示されるはずです:
テストして動作が確認できたので、crontab ファイルを修正して、毎日の更新を指定できます。たとえば、毎日午後6時にスクリプトを実行するように指定したいとします。そのためには、crontab の最後の行を以下のように修正します:
|
1 |
0 18 * * * /home/hackins/wordpress_docker/ssl_renewer.sh >> /var/log/cron_docker.log 2>&1 |
さらに、–dry-run フラグを ssl_renewer.sh スクリプトから削除して、実行時に実際の更新が行われるようにする必要があります。以下のようになるはずです:
|
1 2 3 4 5 6 7 8 |
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose --ansi never" DOCKER="/usr/bin/docker" cd /home/hackins/wordpress_docker/ $COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af |
次に、ファイルを保存して閉じます。これで、cronジョブが90日の期限が切れる前に証明書を更新し、有効に保ちます。
結論
チュートリアルのここまで到達できたなら、DevOpsエンジニアに一歩近づいたと言えるでしょう。Nginxの設定スクリプトを作成し、docker-compose.yml ファイルを作成し、DockerとDocker ComposeでWordPressアプリケーションを実行するために必要な複数のサービスを定義しました。Let’s EncryptからSSL/TLS証明書を取得して、Webサーバーの安全性を確保しました。最後に、証明書が期限切れにならないようにcronジョブを作成しました。素晴らしい仕事です!
DevOpsについてさらに深く学びたい場合は、次の場所からコンテナに関するその他のリソースをご覧ください: 当社のブログ:
- Kubernetesを知る
- Ubuntu 20.04でDockerを使用してNode.js (Express.js) アプリをデプロイする方法
- Ubuntu 18.04でKubernetesクラスターにPHPアプリケーションをデプロイする
- Docker Composeを使用したLaravel、Nginx、MySQLのデプロイ
ハッピーコンピューティング!










コメント
コメントはまだありません。最初のコメントを投稿しましょう。