お名前ドットコムVPSへ移行への道4-SSL/TLS化

※ 当サイトではアフィリエイト広告を利用しています。リンクは広告リンクも含みます。

この記事は約20分で読めます。
広告

お名前.com VPS 今、httpなのでhttps(SSL/TLS化)にします。
Docker+Nginxにcerbotのコンテナを作ってLet’s Encryptの無料SSLを取得してhttps対応します。
あくまでも私は、こうやってみたということで動作やセキュリティの保証はできません。
ここで紹介している私のサブドメインのリンクは記事を書いている段階の話で
リンクが切れたり別の表示になっているかもしれません。
環境
パソコン Windows11
VPS OS Ubuntu 20.04.3 LTS
こちらの続きです。

広告

SSL/TLS

まずSSLの勉強をYoutubeでしました。
SSLの基本的なこと【#60 応用情報 基本情報 高度共通試験午前1対策】SSL TLS
ubuntuとNginxではないけど雰囲気が分かります。Let’s Encryptを使ったSSL証明書の導入手順(CentOS7)【実践】【プログラミング】
具体的な手順は以下を参考にさせていただきました。
https://qiita.com/akko_merry/items/d92f7f3fa6db00220b6f
https://qiita.com/mttt/items/aa2ba3a0677a803d0436
https://dokuwiki.fl8.jp/06_virtualization/05_container/10_docker_let_s_encrypt
まずサブドメインをSSL化することにしました。
サブドメインだと失敗しても新しくつくれるからメインドメインで実験するよりいいと思います。
確認したいのは1回やればIPアドレスに割り振ったドメインとサブドメインが全部SSL化できるのか?
別々にSSL化するのか?です。

SSL証明書を取得

いきなりDjangoではなく、サブドメインにアクセスしたらWelcome to nginx!を表示する状態に変更しました。
conf.d/default.confのserviceのrootに設定してあるディレクトリ(ドキュメントルート、私の場合/usr/share/nginx/html)が人によって違います。
取り合えずcertbotが確認するときだけ80番にアクセスしたら何か表示すればいいのかなという推測のもと、こうしてます。
更新、するときも表示する状態にするように気を付けようと思う。
前回作ったsharedのファイルを変更します。

version: '3.9'
services:

  proxy_prod:
    image: nginx:latest
    container_name: 'proxy'

    ports:
      - "80:80"
      - "443:443"
    restart: always
    environment:
      TZ: Asia/Tokyo

    volumes: # 追記
      - ./conf.d/:/etc/nginx/conf.d
      - /etc/letsencrypt:/etc/letsencrypt # 追記
      - /usr/share/nginx/html:/usr/share/nginx/html # 追記
### certbot ################################################
  certbot:
    image: certbot/certbot:latest
    volumes:
      - /etc/letsencrypt:/etc/letsencrypt
      - /usr/share/nginx/html:/usr/share/nginx/html
    command: ["--version"]
networks:
  default:
    name: shared
    external: true

変更点は443の開放、と参考にしたサイトをもとに修正して付け加えました。

server {
    listen       80;
    listen  [::]:80;

    server_name  "django2.kikuichigevps.com";

    location / {
        root /usr/share/nginx/html;
        index  index.html index.htm;
    }

    # 以下はSSL化のチャレンジという工程で必要
    location /.well-known/acme-challenge/ {
        root /usr/share/nginx/html;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /var/www/htdocs;
    }
}

conf.d/default.confはdjango2.kikuichigevps.comの80番だけにして
cerbotが確認のために使うlocationを追加。

コンテナを更新
sudo docker-compose up -d 
SSL証明書を取得するコマンド実行
sudo docker-compose run --rm certbot certonly --webroot -w ドキュメントルート -d SSL化するドメイン
具体的には
sudo docker-compose run --rm certbot certonly --webroot -w /usr/share/nginx/html -d django2.kikuichigevps.com

メールアドレス、質問2問に答える。
特にエラーはなかった。

確認でhttpでサブドメインにアクセスしたら404 Not Found。
この時点では証明書の発行は成功している状態だと思う。
調べたら/usr/share/nginx/html/index.htmlがなくなっていた。

独り言:(インテンドがおかしかったり、1つのサービスのvolume行が2つに分かれてて下のvolumeしか実行されていなかったのに気づかなかったり、いろいろやったのですんなりいけば消えてないかも。
あとcerbotの動作を推測するとcerbotのコンテナでvolumeにドキュメントルートを設定しているので、ここにcerbotが何か書き込んで、外部のLet's Encrypt?が、それを見れたらOKにしてcerbotが/etc/letsencryptに証明書とか鍵を書き込んでるのかも?またパーミッション設定とか権限も気になっていたが、cerbotのコンテナのvolumeなんだからcerbotが自由に読み書きできるので関係なさそう。)

取り合えずドキュメントルートに何か表示させておこうということで
docker container exec -it コンテナ名 bash
でコンテナの中に入って/usr/share/nginx/html/に移動して
index.html(元のカッコいいWelcome to nginx!のindex.htmlはないので1言だけ)を作った
echo "Hellow World!" > index.html

「それとsudo docker volume lsで コマンド実行後のボーリュームの名前(番号)を記録しておかないと 今後やっているうちに、どれが消していいボリュームか分からなくなりそうです。 Nginxのコンテナとこのボリュームを消したら、SSL認証に必要なデータがなくなるはずです。」
と思ったが、ホストの/etc/letsencryptにあった。
Volumeにはバインドマウントとボリュームマウントとがあって、
service内で書いた- /etc/letsencrypt:/etc/letsencryptはバインドマウントにあたり
ホストとコンテナの/etc/letsencryptに同じものが作られるようです。
ボリュームマウントの場合は/var/lib/docker/volumesに作られるようです。
rootユーザーなら中身が見れるのもあれば空っぽのもありました。
WordPressのコンテナのデータベースでは、
以下の記述で、こちらのタイプのボリュームを使ってるみたいです。
serviceの外で
volumes: db_data:と定義して
serviceの中で
volumes: – db_data:/var/lib/mysqlと書かれている。
sudo docker volume lsで表示されるVolumeはこちらのタイプみたいです。
なのでSSLの証明書をこっちに作ってしまうと指定するのが大変だと思います。できないかも。
ただsudo docker volume lsで表示される数字の名前のボリューム(名無しのボリューム)は、
どこでできたのかなぞです。
もしかしたらバインドマウントとと関係あるかもしれないので消さないでおこうと思います。

またcertbotのコンテナはsudo docker psでは表示されず-aのオプションを付けると出てくる。
つまり普段は停止している。
というかこれはdocker-compose up -dで、できたやつでいらないかも、
普段はdocker-compose run --rm~でrmついてるから
毎回別名で起動して停止したら削除されてるかも。
かも、かも、ばかりですが、確証がないので残しておきます。
後日、certbotのコンテナ削除して
sudo docker-compose run --rm certbot renew --dry-run
を実行したらできました。
目次へ

Modesecurityのコンテナを使っている場合は以下の対策が必要

SSL化

conf.d/default.confを修正。赤い部分はSSL化に申請したドメイン

server {
    listen       443 ssl http2;
    listen  [::]:443 ssl http2;

    server_name  "django2.kikuichigevps.com";
    ssl_certificate      /etc/letsencrypt/live/django2.kikuichigevps.com/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/django2.kikuichigevps.com/privkey.pem;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;

    ssl_protocols TLSv1.3 TLSv1.2;
    ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256';
    ssl_prefer_server_ciphers off;

    add_header Strict-Transport-Security "max-age=2592000" always;

    location / {
        root /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /var/www/htdocs;
    }
}
設定更新
sudo docker restart proxy
でhttps://django2.kikuichigevps.comにアクセスできました。
SSL化してないkikuichigevps.comはhttps://では「接続がプライベートではありません」になり
http://ならつながります。
またlisten80にリダイレクトの記述は入れていないが
 http://django2.kikuichigevps.comにアクセスすると307 Internal Redirectでhttps://にいく。
でもこれだとcerbotの更新チェックでhttpsになってもいいのかな?
ブラウザedgeでアクセスしてるからか?(要注意)

ということでサブドメインやドメインごとにSSL化しなければならないことが分かりました。
目次へ

Djangoに変更してみる

この状態でドキュメントルートの静的ファイルではなくDjangoのコンテナに行くようにconf.d/default.confを変えます。

    # location / {
    #     root /usr/share/nginx/html;
    #     index  index.html index.htm;
    # }
    location / {
        proxy_pass   http://django2_web_run_9ea11b0af0c7:8000;
        proxy_set_header Host $host;
    }

https://django2.kikuichigevps.comにアクセスするとつながりました。

no configuration file provided: not found

メインドメインもSSL化するために
シリアルコンソールでrootでログイン直後のディレクトリで
sudo docker-compose run –rm certbot certonly –webroot -w /usr/share/nginx/html -d kikuichigevps.comを実行したら
no configuration file provided: not foundになった。
cerbotのymlを実行したディレクトリで上記コマンドを実行するとうまくいきました。
目次へ

証明書の更新

この状態で証明書の更新のシミュレーションコマンドをしてみる
sudo docker-compose run --rm certbot renew --dry-run
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Congratulations, all simulated renewals succeeded: 
  /etc/letsencrypt/live/django2.kikuichigevps.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
ということなのでうまくいった。
目次へ

有効期限確認

sudo docker-compose run --rm certbot certificates
で確認できた。
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
  Certificate Name: django2.kikuichigevps.com
    Serial Number: *********
    Key Type: ****
    Domains: django2.kikuichigevps.com
    Expiry Date: 2024-06-10 00:27:37+00:00 (VALID: 89 days)
    Certificate Path: /etc/letsencrypt/live/django2.kikuichigevps.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/django2.kikuichigevps.com/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
今日が2024/3/10なので3か月後が期限でした。
自動更新はCronを使った自動更新は当面はやらず手動でやろうと思います。
sudo docker-compose run --rm certbot renew 
シミュレーションで付けた--dry-runオプションはつけないで実行すればいいはず。

目次へ

自動更新

自動更新する場合は、こちら↓の方法で
 https://qiita.com/akko_merry/items/d92f7f3fa6db00220b6f#3-2-cron%E3%82%92%E8%A8%AD%E5%AE%9A

/home/user/docker/wafvpsにcerbotのymlがあるので、
そこでwafvpsrenew_ssl_certificate.shを実行するようにする。

cron設定方法はターミナルで
crontab -e
1. /bin/nano        <---- easiest
30 3 1,17 * * bash /home/user/docker/wafvps/renew_ssl_certificate.sh
をコピーして右クリックするだけで貼りついた。
CTRL+O(ゼロではなくオー)
Enter
CTRL+X
nanoの使い方は、参考:https://minoru.okinawa/archives/2247

wafvpsrenew_ssl_certificate.shの中身は
cd /home/user/docker/wafvps
sudo docker-compose run --rm certbot renew
sudo docker restart コンテナ名

そのままでは失敗した。原因はパスワード認証されて、そこでエラーになっている。
対策はこちら↓を実施したが、うまくいかなかった。なのでここの対策は戻した。
 cronにpamのエラーが出た際の回避方法
systemctl status cronで確認すると以下エラー発生。
pam_unix(sudo:auth): conversation failed
pam_unix(sudo:auth): auth could not identify password for [username]
パスワードを聞かれてるのに入力してないためにエラーが発生してると思われる。
私の場合rootで実行してないのが原因かも。

対策として以下を参考にしたが、多分、usernameでパスワードを聞かれなくなる設定だと思う。
参考:pam_unix(sudo:auth): conversation failed, auth could not identify password for [username]
/etc/pam.d/sudoに以下追加
#%PAM-1.0
# Fixing ssh "auth could not identify password for [username]"
auth       sufficient   pam_permit.so←追加した。(認証関係なので、やっていいものなのか自己判断してください。)

systemctl status cronにエラーは出ていない。また
sudo cat /var/log/cron.log
では実行されたログが残っているので一応実行されたみたい。
cerbotが何かやったかの履歴の確認はどこにあるか分からないので確認できていない。
なので更新可能期間に入ってから、ちゃんと動作したかの確認をします。

suでrootユーザにならなくてもcrontabを編集する方法
参考:https://qiita.com/ntkgcj/items/71778e1ec8b27ea03ce5
# 実行ユーザーを指定して実行
crontab -u user1 -e

ログも出力するようにした。
参考:https://qiita.com/MatchaDev/items/a2d824fa8fb921341f8a
上記対策後sudo cat /var/log/cron.logで確認できる。

目次へ

2個目のサブドメインをSSL化してみる

サブドメインdjango3.kikuichigevps.comを追加で登録します。
やり方はこちら↓

server {
    listen       80;
    listen  [::]:80;

    server_name  "django3.kikuichigevps.com";

    location / {
        root /usr/share/nginx/html;
        index  index.html index.htm;
    }
    # 以下はSSL化のチャレンジという工程で必要
    location /.well-known/acme-challenge/ {
        root /usr/share/nginx/html;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /var/www/htdocs;
    }
}
設定を反映させる
sudo docker restart proxy
新しく取ったサブドメインにアクセスするとHellow World!と表示することを確認。
 http://django3.kikuichigevps.com/
SSL証明書を取得するコマンド実行
sudo docker-compose run --rm certbot certonly --webroot -w /usr/share/nginx/html -d django3.kikuichigevps.com

Successfully received certificate.と出たので成功しました。
conf.d/default.confに新しいサブドメインの443の処理を書いたらhppsでアクセスできました。
目次へ
コンテナの中にファイルをコピー

おまけで試しました。
Nginxのコンテナのドキュメントルートにファイルをコピーしてみます。

コンテナの中に入る
docker container exec -it コンテナ名 bash
移動して
cd /usr/share/nginx/html/
ディレクトリ作って
mkdir portfolio
コンテナから出る
exit
コピーコマンド
sudo docker cp ichigeportfolio.html <コンテナID>:/usr/share/nginx/html/portfolio/ichigeportfolio.html

個人メモ(ディスク容量変更)

ここでサーバーの電源をOFFしディスク構成を変更20-80から80-20に変更した。30分ぐるぐる回ったままだったけど、サーバー一覧押してログインしたら終わっていた。起動。

df -h --total
Filesystem      Size  Used Avail Use% Mounted on
udev            466M     0  466M   0% /dev
tmpfs            97M  1.1M   96M   2% /run
/dev/vda1        78G  4.5G   73G   6% /
tmpfs           483M     0  483M   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           483M     0  483M   0% /sys/fs/cgroup
/dev/loop0       56M   56M     0 100% /snap/core18/2812
/dev/loop1       64M   64M     0 100% /snap/core20/2182
/dev/loop2       56M   56M     0 100% /snap/core18/2128
/dev/loop3       40M   40M     0 100% /snap/snapd/21184
/dev/loop5       92M   92M     0 100% /snap/lxd/24061
/dev/loop4       71M   71M     0 100% /snap/lxd/21029
/dev/vda15      105M  6.1M   99M   6% /boot/efi
tmpfs            97M     0   97M   0% /run/user/1001
total            80G  4.8G   75G   7% -

VsコードでSSH接続してると結構メモリ使う

しかし次の日、コンテナが停止してた。
その後も何回かやったけどfreeで見て
メモリ使用量が800超えると重くなるので多分メモリ不足だろう。
VsコードをSSH接続する前シリアルコンソールでfreeしたら556504
Vsコードつないだ後、freeしたら729540
こちら↓で対策できた。

再起動

早速、この状態↓になっていた。記録しておいてよかった。

アパッチを止めて
sudo systemctl stop apache2.service
コンテナが停止してるのでstart
sudo docker start コンテナ名
Djangoのコンテナはコンテナの中に入って
python manage.py runserver 0.0.0.0:8000

所感

cerbotのコンテナを使えば、スムーズにいきました。
目次へ

イチゲをOFUSEで応援する(御質問でもOKです)Vプリカでのお支払いがおすすめです。
MENTAやってます(ichige)

コメント

タイトルとURLをコピーしました