1つのIPアドレス、1つのドメインを割り当てている Apache サーバーで、複数のホスト名へのリクエストを VirtualHost で振り分け、それぞれに異なる Let's Encrypt の SSL 証明書を割り当てて HTTPS アクセスを可能にしてみた 投稿一覧へ戻る
Published 2022年3月14日9:28 by mootaro23
SUPPORT UKRAINE
- Your indifference to the act of cruelty can thrive rogue nations like Russia -
この記事は順次更新していきます。
気長にお付き合いください。
イメージは以下の通りです:
certbot-auto スクリプトのアンインストール:
Certbot を一からインストールし直して Let's Encrypt の証明書を取得し直すために、サポートが終了している certbot-auto をアンインストールしました。
手順は Uninstalling certbot-auto の記事を参照に行いました。
1: cron を利用して証明書の自動更新をスケジュールしていたので、設定を行ったのと同じユーザーで、
コマンドを実行してエディタを開き、該当部分を削除しました。
ですべてのスケジュールを削除することもできます。
2: certbot-auto スクリプトを削除します:
3: certbot-auto でインストールされた Certbot を削除します:
Certbot のインストール:
Let's Encrypt の証明書の取得には ACME クライアントが必要ですが、公式 HP では Certbot が推薦されているため改めて Certbot をインストールします。
Certbot のサイト で、自分が使用しているサーバーソフトウェアと OS を入力するとインストール手順書が表示されますので、その通りに進めていきます。
私は AlmaLinux 8 を利用していますが選択項目には含まれていなかったため CentOS 8 を選択しました。
1: snap パッケージ管理システムのインストール:
Certbot のインストールには snap パッケージ管理システムの利用が推薦されているため snapd のインストールを行います。
まず、epel リポジトリが利用できるか確かめます:
リストに含まれていて「有効化」されていれば大丈夫。
「無効化」されているときは「有効化」します:
含まれていない場合はインストールします:
epel リポジトリが利用できるようになったらシステムをアップデートします:
snapd パッケージをインストールします:
snapd.socket サービスを有効にします:
classic snap を有効にするために、シンボリックリンクを張ります:
システムをリブートします:
snap のバージョンが最新になるようにします:
2: Certbot のインストール
Certbot をインストールします:
Certbot コマンドを実行する際に path が通るようにシンボリックリンクを張ります:
Let's Encrypt の証明書の取得
以下のコマンドを実行します:
表示される質問に答えていきます:
この例でいえば、
のように表示されます。
何も入力せずに Enter を押すとすべてを選択したことになります。
今回は、Django アプリと React アプリへのドメインを分け、証明書も別々に取得したいので、まず Django アプリで使用するドメインに関して証明書を取得するため、
と入力します。
これで証明書が発行されますが、警告が表示されます (コンフィギュレーションファイルは前出のものだとします):
1 に関しては無視します。
2 は、Certbot が <VirtualHost *.443> ブロックを自動作成する時点で、該当する <VirtualHost *.80> の内容をコピーするのですが、結果として重複してはいけない WSGIDaemonProcess も含んでしまっているために発生しています。
そこで Certbot が作成した <VirtualHost *:443> ブロックに含まれている WSGIDaemonProcess の行を削除します (Certbot は、'conf_name'-le-ssl.conf というファイルを作成してその中に定義しているようです)。
この時点での conf ファイルの内容:
証明書取得対象としたサーバーの <VirtualHost *:80> ディレクティブ内に rewrite 構文が追加され、80 番ポート宛に送られてきた該当ドメインに対するリクエストが、443 番ポートにリダイレクトされるようになっています。
また、該当ドメインの <VirtualHost *:443> ディレクティブ (この内容は同じフォルダ内に作成された 'conf_name'-le-ssl.conf ファイル内に記述されているものと同じです) には証明書までの path が指定されています。
私はこの <VirtualHost *:443> ... </VirtualHost> ディレクティブの内容を Certbot が作成した 'conf_name'-le-ssl.conf ファイルからこのコンフィギュレーションファイルへコピー&ペーストしましたが、この作業が本当に必要なのか、それとも、Certbot が作成した xxx-le-ssl.conf だけが存在すればよいのか、不明です。
この時点で http://back.example.com、https://back.example.com、http://example.com、https://example.com へアクセスすると正常に読み込まれました。
ただし、Django を利用している場合に static files を集めたフォルダへの Alias を設定している場合、その記述を:
1: conf ファイルのグローバル領域ではなく、該当サーバーの <VirtualHost *:443> ディレクティブ内に記述する
2: Certbot が作成した xxx-le-ssl.conf の該当ディレクティブ内にも記述する
の両方、もしくは 2: のみ、の対応が必要なようです。
気長にお付き合いください。
現状および計画:
・Djangoアプリケーションは以前からこのサーバー上で稼働しており、Let's Encrypt から取得した証明書で SSL 接続が可能となっていました。
・今回、フロントエンド部分を React を利用して構築することを計画し、最終的にはバックエンドの Django は django REST framework を利用した API 提供に特化させようと思っています。
・React アプリケーションを deploy するための新たなサーバーを用意したり、そのための IP アドレスを取得する予定はありません。
・当座は現在のサーバーに Django プロジェクトと React アプリケーションを共存させ、django REST framework と React による開発を進めていく予定です。
・フロントエンドアプリケーションとバックエンドアプリケーションは分離させたいのでそれぞれ別のホスト名でアクセス可能にし、また、それぞれのアクセスを HTTPS スキームで行えるように設定したいと考えています。
・Let's Encrypt を利用する際の ACME クライアントとして Certbot を利用していますが、今までは certbot-auto スクリプトを介して更新等の作業を行っていました。しかし certbot-auto のサポートは終了しているため、これを機会に一度環境をクリアにし、Certbot を一からインストール、それぞれのアプリケーションにアクセスするためのドメインに対する SSL 証明書を取得し直すことにしました。
・Djangoアプリケーションは以前からこのサーバー上で稼働しており、Let's Encrypt から取得した証明書で SSL 接続が可能となっていました。
・今回、フロントエンド部分を React を利用して構築することを計画し、最終的にはバックエンドの Django は django REST framework を利用した API 提供に特化させようと思っています。
・React アプリケーションを deploy するための新たなサーバーを用意したり、そのための IP アドレスを取得する予定はありません。
・当座は現在のサーバーに Django プロジェクトと React アプリケーションを共存させ、django REST framework と React による開発を進めていく予定です。
・フロントエンドアプリケーションとバックエンドアプリケーションは分離させたいのでそれぞれ別のホスト名でアクセス可能にし、また、それぞれのアクセスを HTTPS スキームで行えるように設定したいと考えています。
・Let's Encrypt を利用する際の ACME クライアントとして Certbot を利用していますが、今までは certbot-auto スクリプトを介して更新等の作業を行っていました。しかし certbot-auto のサポートは終了しているため、これを機会に一度環境をクリアにし、Certbot を一からインストール、それぞれのアプリケーションにアクセスするためのドメインに対する SSL 証明書を取得し直すことにしました。
イメージは以下の通りです:
前提:
・AlmaLinux 8 (CentOS 8) 上で web server として apache を動かしています。
・サーバーには1つの IP アドレスが割り当てられています (xxx.xxx.xxx.xxx)。
・Apache の待ち受けポートは 80 番です。
・ドメイン (example.com) も1つだけ取得済みで、DNS の設定で IP アドレスと結びつけています。
・また、DNS の設定で、同じ IP アドレスに対して2つの異なるホスト名も登録してあります (front と back)。
・つまり、xxx.xxx.xxx.xxx には、example.com, front.exmaple.com, back.example.com というドメイン名でアクセス可能です。
・example.com と back.example.com へのアクセスは Django アプリケーションへのアクセスです。
・front.example.com へのアクセスは React アプリケーションへのアクセスです。
・Apache のコンフィギュレーションファイルに2つの <VirtualHost> ブロックを設定し、それぞれの ServerName ディレクティブの値で処理を振り分けています。
・AlmaLinux 8 (CentOS 8) 上で web server として apache を動かしています。
・サーバーには1つの IP アドレスが割り当てられています (xxx.xxx.xxx.xxx)。
・Apache の待ち受けポートは 80 番です。
・ドメイン (example.com) も1つだけ取得済みで、DNS の設定で IP アドレスと結びつけています。
・また、DNS の設定で、同じ IP アドレスに対して2つの異なるホスト名も登録してあります (front と back)。
・つまり、xxx.xxx.xxx.xxx には、example.com, front.exmaple.com, back.example.com というドメイン名でアクセス可能です。
・example.com と back.example.com へのアクセスは Django アプリケーションへのアクセスです。
・front.example.com へのアクセスは React アプリケーションへのアクセスです。
・Apache のコンフィギュレーションファイルに2つの <VirtualHost> ブロックを設定し、それぞれの ServerName ディレクティブの値で処理を振り分けています。
certbot-auto スクリプトのアンインストール:
Certbot を一からインストールし直して Let's Encrypt の証明書を取得し直すために、サポートが終了している certbot-auto をアンインストールしました。
手順は Uninstalling certbot-auto の記事を参照に行いました。
1: cron を利用して証明書の自動更新をスケジュールしていたので、設定を行ったのと同じユーザーで、
crontab -e
コマンドを実行してエディタを開き、該当部分を削除しました。
crontab -r
ですべてのスケジュールを削除することもできます。
2: certbot-auto スクリプトを削除します:
sudo rm /usr/local/bin/certbot-auto
3: certbot-auto でインストールされた Certbot を削除します:
sudo rm -rf /opt/eff.org
Apache コンフィギュレーションファイル:
この時点では以下のようになっていました:
この時点では以下のようになっていました:
LoadModule wsgi_module /path/to/wsgi/module/mod_wsgi.so
NameVirtualHost *:80
WSGIApplicationGroup %{RESOURCE}
WSGIRestrictEmbedded On
<VirtualHost *:80>
ServerName back.example.com
ServerAlias example.com
WSGIDaemonProcess venv python-home=/path/to/virtual/environment/root python-path=/path/to/django/project/root
WSGIProcessGroup venv
WSGIScriptAlias / /path/to/django/project_root/project_name/wsgi.py
<Directory /path/to/django/project_root/project_name>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName front.example.com
DocumentRoot /path/to/document/root
<Directory /path/to/document/root>
Require all granted
</Directory>
</VirtualHost>
NameVirtualHost *:80
WSGIApplicationGroup %{RESOURCE}
WSGIRestrictEmbedded On
<VirtualHost *:80>
ServerName back.example.com
ServerAlias example.com
WSGIDaemonProcess venv python-home=/path/to/virtual/environment/root python-path=/path/to/django/project/root
WSGIProcessGroup venv
WSGIScriptAlias / /path/to/django/project_root/project_name/wsgi.py
<Directory /path/to/django/project_root/project_name>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName front.example.com
DocumentRoot /path/to/document/root
<Directory /path/to/document/root>
Require all granted
</Directory>
</VirtualHost>
Certbot のインストール:
Let's Encrypt の証明書の取得には ACME クライアントが必要ですが、公式 HP では Certbot が推薦されているため改めて Certbot をインストールします。
Certbot のサイト で、自分が使用しているサーバーソフトウェアと OS を入力するとインストール手順書が表示されますので、その通りに進めていきます。
私は AlmaLinux 8 を利用していますが選択項目には含まれていなかったため CentOS 8 を選択しました。
1: snap パッケージ管理システムのインストール:
Certbot のインストールには snap パッケージ管理システムの利用が推薦されているため snapd のインストールを行います。
まず、epel リポジトリが利用できるか確かめます:
sudo dnf repolist --enabled
リストに含まれていて「有効化」されていれば大丈夫。
「無効化」されているときは「有効化」します:
sudo dnf config-manager --enable epel
含まれていない場合はインストールします:
sudo dnf config-manager --add-repo epel
epel リポジトリが利用できるようになったらシステムをアップデートします:
sudo dnf upgrade
snapd パッケージをインストールします:
sudo dnf install snapd
snapd.socket サービスを有効にします:
sudo systemctl enable --now snapd.socket
classic snap を有効にするために、シンボリックリンクを張ります:
sudo ln -s /var/lib/snapd/snap /snap
システムをリブートします:
sudo reboot
snap のバージョンが最新になるようにします:
sudo snap install core
sudo snap refresh core
sudo snap refresh core
2: Certbot のインストール
Certbot をインストールします:
sudo snap install --classic certbot
Certbot コマンドを実行する際に path が通るようにシンボリックリンクを張ります:
sudo ln -s /snap/bin/certbot /usr/bin/certbot
Let's Encrypt の証明書の取得
以下のコマンドを実行します:
sudo certbot --apache
表示される質問に答えていきます:
Enter email address: メールアドレス入力
Please read the Terms of Service ...: 使用許諾書に同意 → Y
Would you be willing , once your ...: Certbot からの連絡を受け取る場合は → Y
Which names would you like to activate HTTPS for?:
Please read the Terms of Service ...: 使用許諾書に同意 → Y
Would you be willing , once your ...: Certbot からの連絡を受け取る場合は → Y
Which names would you like to activate HTTPS for?:
この例でいえば、
1: front.example.com
2: example.com
3: back.example.com
2: example.com
3: back.example.com
のように表示されます。
何も入力せずに Enter を押すとすべてを選択したことになります。
今回は、Django アプリと React アプリへのドメインを分け、証明書も別々に取得したいので、まず Django アプリで使用するドメインに関して証明書を取得するため、
2,3
と入力します。
これで証明書が発行されますが、警告が表示されます (コンフィギュレーションファイルは前出のものだとします):
1: NameVirtualHost has no effect
2: Name duplicates previous WSGI daemondefinition
2: Name duplicates previous WSGI daemondefinition
1 に関しては無視します。
2 は、Certbot が <VirtualHost *.443> ブロックを自動作成する時点で、該当する <VirtualHost *.80> の内容をコピーするのですが、結果として重複してはいけない WSGIDaemonProcess も含んでしまっているために発生しています。
そこで Certbot が作成した <VirtualHost *:443> ブロックに含まれている WSGIDaemonProcess の行を削除します (Certbot は、'conf_name'-le-ssl.conf というファイルを作成してその中に定義しているようです)。
この時点での conf ファイルの内容:
LoadModule wsgi_module /path/to/wsgi/module/mod_wsgi.so
NameVirtualHost *:80
WSGIApplicationGroup %{RESOURCE}
WSGIRestrictEmbedded On
<VirtualHost *:80>
ServerName back.example.com
ServerAlias example.com
WSGIDaemonProcess venv python-home=/path/to/virtual/environment/root python-path=/path/to/django/project/root
WSGIProcessGroup venv
WSGIScriptAlias / /path/to/django/project_root/project_name/wsgi.py
<Directory /path/to/django/project_root/project_name>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
RewriteEngine on
RewriteCond %{SERVER_NAME} =back.example.com [OR]
RewriteCond %{SERVER_NAME} =example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
<VirtualHost *:80>
ServerName front.example.com
DocumentRoot /path/to/document/root
<Directory /path/to/document/root>
Require all granted
</Directory>
</VirtualHost>
<VirtualHost *:443>
ServerName back.example.com
ServerAlias example.com
WSGIProcessGroup venv
WSGIScriptAlias / /path/to/django/project_root/project_name/wsgi.py
<Directory /path/to/django/project_root/project_name>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
</VirtualHost>
NameVirtualHost *:80
WSGIApplicationGroup %{RESOURCE}
WSGIRestrictEmbedded On
<VirtualHost *:80>
ServerName back.example.com
ServerAlias example.com
WSGIDaemonProcess venv python-home=/path/to/virtual/environment/root python-path=/path/to/django/project/root
WSGIProcessGroup venv
WSGIScriptAlias / /path/to/django/project_root/project_name/wsgi.py
<Directory /path/to/django/project_root/project_name>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
RewriteEngine on
RewriteCond %{SERVER_NAME} =back.example.com [OR]
RewriteCond %{SERVER_NAME} =example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
<VirtualHost *:80>
ServerName front.example.com
DocumentRoot /path/to/document/root
<Directory /path/to/document/root>
Require all granted
</Directory>
</VirtualHost>
<VirtualHost *:443>
ServerName back.example.com
ServerAlias example.com
WSGIProcessGroup venv
WSGIScriptAlias / /path/to/django/project_root/project_name/wsgi.py
<Directory /path/to/django/project_root/project_name>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
</VirtualHost>
証明書取得対象としたサーバーの <VirtualHost *:80> ディレクティブ内に rewrite 構文が追加され、80 番ポート宛に送られてきた該当ドメインに対するリクエストが、443 番ポートにリダイレクトされるようになっています。
また、該当ドメインの <VirtualHost *:443> ディレクティブ (この内容は同じフォルダ内に作成された 'conf_name'-le-ssl.conf ファイル内に記述されているものと同じです) には証明書までの path が指定されています。
私はこの <VirtualHost *:443> ... </VirtualHost> ディレクティブの内容を Certbot が作成した 'conf_name'-le-ssl.conf ファイルからこのコンフィギュレーションファイルへコピー&ペーストしましたが、この作業が本当に必要なのか、それとも、Certbot が作成した xxx-le-ssl.conf だけが存在すればよいのか、不明です。
この時点で http://back.example.com、https://back.example.com、http://example.com、https://example.com へアクセスすると正常に読み込まれました。
ただし、Django を利用している場合に static files を集めたフォルダへの Alias を設定している場合、その記述を:
1: conf ファイルのグローバル領域ではなく、該当サーバーの <VirtualHost *:443> ディレクティブ内に記述する
2: Certbot が作成した xxx-le-ssl.conf の該当ディレクティブ内にも記述する
の両方、もしくは 2: のみ、の対応が必要なようです。
この記事に興味のある方は次の記事にも関心を持っているようです...
- People who read this article may also be interested in following articles ... -