1つのIPアドレス、1つのドメインを割り当てている Apache サーバーで、複数のホスト名へのリクエストを VirtualHost で振り分け、それぞれに異なる Let's Encrypt の SSL 証明書を割り当てて HTTPS アクセスを可能にしてみた 投稿一覧へ戻る

Tags: letsencrypt , certbot , virtualhost , apache

Published 2022年3月14日9:28 by T.Tsuyoshi

この記事は順次更新していきます。
気長にお付き合いください。

現状および計画:

・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 証明書を取得し直すことにしました。


イメージは以下の通りです:

ip_address_domain_routine

前提:

・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>



Certbot のインストール:

Let's Encrypt の証明書の取得には ACME クライアントが必要ですが、公式 HP では Certbot が推薦されているため改めて Certbot をインストールします。

Certbot のサイト で、自分が使用しているサーバーソフトウェアと OS を入力するとインストール手順書が表示されますので、その通りに進めていきます。

certbot_instrall_document

私は 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



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?:


この例でいえば、

1: front.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


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>



証明書取得対象としたサーバーの <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: のみ、の対応が必要なようです。

この投稿をメールでシェアする

こちらの投稿にも興味があるかもしれません...

    ご興味のある同分野を扱った他の投稿は今のところありません

0 comments

コメントはまだありません。

コメントを追加する(不適切と思われるコメントは削除する場合があります)