前回DifyをインストールしたEC2にALBを紐づけてSSL化しました。

これでOKなんですけど、まぁALB高いんですよね。個人にとっては。
基本16ドルぐらいかかるので2000円かかってさらにEC2かかって…EBS分もありとなると法人で制御して利用するというケースはばっちりですが。
なので今回はCertbotをつかってSSL化して第4回で接続したドメインにRoute53でつなぐところまでやります。
一応無料SSLと称してますが、ALBと比べてという意味でしかないので、もちろんドメインとそしてElastic IPは多少かかります。完全無料ではないです。EC2停止時にElastic IPは料金は発生しますので。

今回達成できること
Certbotを使ってLet’s EncryptのSSL証明書を発行してSSL化して自分のドメインでSSL接続ができる

はじめに

イメージの確認

まず前回ALBの振り返りです。

アーキを簡易的に一直線にあくまでもイメージとして表すなら

EC2 → ターゲットグループ → ロードバランサー(ALB)→ Route53 (Aレコード)→ ドメイン

こんな感じだったのを

EC2 → ErasticIP → Route53 (Aレコード)→ ドメイン


大まかにこんな感じにします。

前回設定から削除する項目

もしも前回の設定からALBを削除したいとなると削除する項目は

・Route53 (Aレコード)
・ロードバランサー(ALB)
・ターゲットグループ

です。ちなみに削除順番としてはロードバランサー(ALB)を削除してからターゲットグループを削除しないと紐づけられているのでできませんと注意が出ます。
今回は上記3つを削除した前提で進めていきます。

今回の流れ

調べていたら非常に参考になる記事が出てきました。

https://qiita.com/Kobe-dad/items/64a18341b8dc7b35dcac

これでOKなのですが、一応何をしているのかを説明すると、
Github Gistというコードを共有できるサービスを使って、特定の流れのコマンドを共有し、それを短縮URL(https://bit.ly)で共有してくれている感じです。

https://gist.githubusercontent.com/gijigae/ae00c2c61146861f808d6973f329ccb8/raw/e418c14312b6d928e0c922f9c9bb9fe711bfb7d1/install-dify-with-https.sh

こちらのアドレスにコマンドがあり、それを

curl -fsSL https://bit.ly/3YHdSo0 -o install-dify.sh
「install-dify.sh」というスクリプトファイルとして保存をしそれを

sudo sh ./install-dify.sh email domain

で実行している流れです。ただDifyのインストールも含んでいるので今回はそこを省いたものに修正して実行します。

1.Elastic IP アドレスを取得してEC2に関連付ける

EC2が停止した際にもIPアドレスが変わらないようにするためです。

EC2の画面に行きます。トップのリソースのところからElastic IPを選択します。
Elastic IP アドレスを割り当てるを選択してとくに初期設定のまま割り当てをしてください。
そうすると新規でIPアドレスが割り当てられます。

つづいて、これをEC2に関連付けますが、作成すると右上に関連づけると出ますし、そのIPアドレスの画面にはいってElastic IP アドレスの関連付けを押してもOKです。


該当のEC2を選択して関連づけてください。そして関連付けがうまくいくとEC2の画面からもElastic IPが無事選択できていることが確認できると思います。

2.Route53でAレコードにElastic IPを設定する。

今取得したElastic IPを対象ドメインのRoute53に設定します。前回第4回で取得したドメインを使っていきます。ドメイン取得されていない方は第4回をご確認ください。

これは前回ALBで作成したやり方と似ていますが、

Route53→左タブのホストゾーン→該当のドメインを選択→レコードの作成です。
今回はエイリアスをオフのまま以下のように値のところに今回のElastic IPを入力してレコードを作成します。

おそらくでおそらく今の状態だと、SSL化前なので

①Elastic IPでhttp://で接続できる。
②ドメインでhttp://で接続できる。(ただしレコード作成から数分から数十分時間経過後。DNSがなじむまで。)

だと思います。これで準備完了なので続いてSSL化に行きます。
なお、DNS浸透しきってないとCertbotが認識できずエラーが起きることがあるので少し時間をまってからお願いします。

3.EC2にSSLを設定する

では黒い画面に行きます。

1.スクリプトを作るためにテキストを開く

nano ssl-script.sh

これで「ssl-script.sh」という新しいファイルを作成して編集モードに入りました。

2.以下のコードをコピペする。
次のコードをコピペしてください。

※2024/10/25追記
DNS浸透前のエラーのエラーハンドリングを強化しました。
いままでDNSエラーがおきてもHTTPSを有効化してしまったりしてエラー後にhttpで再アクセスするには修正しないといけなかったのでエラーがおきたときは中断するようにしました。これで安全にエラーを起こせます。

#!/bin/bash

# 引数としてメールアドレスとドメインが提供されているか確認
if [ $# -ne 2 ]; then
    echo "Usage: $0 <email> <domain>"
    exit 1
fi

# 引数を変数に格納
EMAIL=$1
DOMAIN=$2

# Difyディレクトリが存在するか確認。存在しない場合はエラーメッセージを出力して終了
if [ ! -d "dify" ]; then
    echo "Difyディレクトリが見つかりません。リポジトリをクローンしてください。"
    exit 1
fi

# Difyリポジトリに移動
cd dify

# .envファイルが存在しない場合、.env.exampleからコピーして.envを作成
if [ ! -f docker/.env ]; then
    cp docker/.env.example docker/.env
fi

# .envファイル内のSSL証明書関連の設定を更新
sed -i 's/^NGINX_SSL_CERT_FILENAME=.*/NGINX_SSL_CERT_FILENAME=fullchain.pem/' docker/.env
sed -i 's/^NGINX_SSL_CERT_KEY_FILENAME=.*/NGINX_SSL_CERT_KEY_FILENAME=privkey.pem/' docker/.env
sed -i 's/^NGINX_ENABLE_CERTBOT_CHALLENGE=.*/NGINX_ENABLE_CERTBOT_CHALLENGE=true/' docker/.env
sed -i "s/^CERTBOT_DOMAIN=.*/CERTBOT_DOMAIN=$DOMAIN/" docker/.env
sed -i "s/^CERTBOT_EMAIL=.*/CERTBOT_EMAIL=$EMAIL/" docker/.env

# DifyのAPI URLとWeb URLをドメイン名に基づいて更新
sed -i "s|^SERVICE_API_URL=.*|SERVICE_API_URL=https://$DOMAIN|" docker/.env
sed -i "s|^APP_WEB_URL=.*|APP_WEB_URL=https://$DOMAIN|" docker/.env

# Dockerネットワークを再作成(古いネットワークを削除)
sudo docker network prune -f

# certbotプロファイルを使ってコンテナを強制再作成し、バックグラウンドで起動
sudo /home/ec2-user/.docker/cli-plugins/docker-compose -f docker/docker-compose.yaml --profile certbot up --force-recreate -d

# certbotコンテナが正常に起動しているか確認。起動していなければエラーメッセージを出力して終了
if ! sudo docker ps | grep certbot; then
    echo "Certbotコンテナが実行されていません。Dockerのログを確認してください。"
    exit 1
fi

# certbotのスクリプトを実行してSSL証明書を更新
CERTBOT_OUTPUT=$(/home/ec2-user/.docker/cli-plugins/docker-compose -f /home/ec2-user/dify/docker/docker-compose.yaml exec -T certbot /bin/sh /update-cert.sh 2>&1)

# certbotの出力にDNSエラーが含まれているかチェック
if echo "$CERTBOT_OUTPUT" | grep -q "SERVFAIL"; then
    echo "エラー: DNS問題が発生しました。ドメインのネームサーバーを確認してください。"
    exit 1
fi

# .envファイルでHTTPSを有効化する設定に変更
sed -i 's/^NGINX_HTTPS_ENABLED=.*/NGINX_HTTPS_ENABLED=true/' docker/.env

# nginxコンテナを再作成して、更新したHTTPS設定を適用
/home/ec2-user/.docker/cli-plugins/docker-compose -f /home/ec2-user/dify/docker/docker-compose.yaml --profile certbot up -d --no-deps --force-recreate nginx

# 完了メッセージを表示
echo "DifyのインストールとSSL設定が完了しました。https://$DOMAIN を確認してください。"

4.このスクリプトの実行許可を出します。

chmod +x ssl-script.sh

作成したばかりのスクリプトは実行できないように設定されています。
そのためこのスクリプトを実行してもよいように設定をかけました。

5.メルアドとドメインを指定して実行する。

sudo sh ./ssl-script.sh your-email@example.com your-domain.com

スクリプト内でメールアドレスとドメインを変数として設定することで、スクリプト実行時に一度だけ入力すれば、自動的にスクリプト全体にその値が反映されます。
これにより、スクリプト内の複数箇所に手動で同じ情報を繰り返し入力する手間が省けるという感じです。

your-email@example.com your-domain.comのところをあなたのメルアドとドメインにして下さい。
例えばこんな感じです。

例)

sudo sh ./ssl-script.sh test@ids.co.jp test.click

なお、このメールアドレスは、Certbotの利用規約に同意するために必要です。また、SSL証明書の更新通知もこのアドレスに送られます。

SSL証明書は、通常90日間有効です。Certbotを使用することで、有効期限の30日前に自動で更新が行われるため、基本的には手動で更新する必要はありません。ただし、Certbotが自動更新に失敗した場合、メールで通知が送られるので、その場合は手動で更新するなどの対応が必要です。

つまり自動更新が正常に行われれば、実質的に約60日ごとにCertbotが証明書を更新することになります。

(補足)手動更新手順

で一応手動手順ですが

1.Certbotで証明書を手動更新する
まずディレクトリに移動します。設定ファイルの場所に移動します。
cd dify/docker
そして更新します。–force-renewalをつけることで更新期限が近くなくても強制更新できます。

cd /home/ec2-user/dify/docker
sudo /home/ec2-user/.docker/cli-plugins/docker-compose -f /home/ec2-user/dify/docker/docker-compose.yaml exec certbot certbot renew --force-renewal

2.Nginxを再起動する

sudo /home/ec2-user/.docker/cli-plugins/docker-compose -f /home/ec2-user/dify/docker/docker-compose.yaml restart nginx

ちなみに確認方法は

sudo /home/ec2-user/.docker/cli-plugins/docker-compose -f /home/ec2-user/dify/docker/docker-compose.yaml exec certbot certbot certificates

で確認できます。

次回予告

できました!いい感じです。
そしたら次回はさらにコストを意識して時間外停止をLambdaで試みてみましょう。

この記事を書いた人

スムーズロゴ
SMOOZ
enterprise-smooz

資料
ダウンロード

マスターデータのメンテナンスに関わる機能をまとめたSaaS「SMOOZ
SMOOZはリレーショナルデータベースの課題を解決するサービスです。
ご興味ございましたら資料をダウンロードください。