CentOS8(VPS)立ち上げからマルチドメインのLet's Encrypt設定完了まで
はじめに
Qiitaで書いていた自分自身の記事です。
自分の趣味用に、遊ばせていたドメイン x3 と新たに VPS(Conoha)を契約して
環境構築しようとやってみたメモです。
(どちらかというと全体の流れとポイントのまとめ)
目的にしていたわけではないですが比較的シンプルな設定(※当社比)で
SSL Server Test(SSL暗号化の安全性チェック)が一発 A+ だったので 手間が省けて 結構うれしい。
なにする
VPS で CentOS8 を新規に立ち上げた状態から
- SSH 用一般ユーザーの作成
- Apache のインストール
- Let's encrypt で SSL対応、自動更新設定
までをざっくり流します。
環境
- CentOS 8.1
- Apache 2.4
前提・導入
- ドメイン(は元々持ってた。VPSとは無関係のとこ)
- VPS契約
- CentOS8.1イメージでサーバー追加
最初なので root ログイン(秘密鍵で)
パッケージ更新
[root@(host) ~]# dnf update
※ CentOS8 において yum と dnf はともに dnf-3 のシンボリックリンク
(証明書取得までに)DNS を設定
ドメインを契約しているレジストラ等で
Aレコード
に VPS の グローバル IP を設定しておく。
(証明書の取得時に正引きできる必要がある。
ドメインから IP を引けるようになるまで時間かかるので一応先に書いておいた)
一般ユーザーの作成
ユーザー追加
[root@(host) ~]# useradd user1
[root@(host) ~]# passwd user1
(パスワードを設定)
(比較用)ユーザーの属するグループ
[root@(host) ~]# groups user1
user1 : user1
副グループを追加
[root@(host) ~]# usermod -G wheel user1
[root@(host) ~]# groups user1
user1 : user1 wheel
※ wheel グループ:スーパーユーザー(root)特権を得られる既定のグループ
su 可能なユーザーを wheel グループに限定
[root@(host) ~]# vi /etc/pam.d/su
# ↓ 変更前
#auth required pam_wheel.so use_uid
# ↓ 変更後(コメント外しただけ)
auth required pam_wheel.so use_uid
ssh ログイン用に鍵を生成
teratermで作りました。
▼ 参考
※ 私は「鍵を生成する」の項のみ行った形です
(rootのまま作業した)
私の場合は鍵を生成後
root のまま id_rsa.pub
を放り込んで(scpで送信して)、
(送信先未設定の場合、ssh ログインしたユーザーのホームディレクトリに配置されます。)
[root@(host) ~]# mkdir /home/user1/.ssh
[root@(host) ~]# chown user1:user1 /home/user1/.ssh
[root@(host) ~]# chmod 700 /home/user1/.ssh
[root@(host) ~]# chown user1:user1 id_rsa.pub
[root@(host) ~]# chmod 600 id_rsa.pub
[root@(host) ~]# mv id_rsa.pub /home/miyapei/.ssh/authorized_keys
みたいな感じで
user1にchownしたものを /home/user1/.ssh/ 以下に authorized_keys にリネームして配置。
追加したユーザーでログイン& su できるかを確認
ログインできたら su できるかも確認。
[user1@(host) ~]$ sudo su -
root ログインを禁止
[root@(host) ~]# vi /etc/ssh/sshd_config
### ↓ rootログイン禁止
#PermitRootLogin yes
PermitRootLogin no
### ↓ パスワードログイン禁止
PasswordAuthentication no
### ↓ 反映
[root@(host) ~]# systemctl reload sshd
※ 私の環境では VPS 追加時に root ログインの公開鍵を設定していたため
最初からパスワードログイン不可でした
※ ちなみに Fail2ban もオプションで最初から入れてました
Apache インストール
### ↓ インストール
[root@(host) ~]# dnf install httpd
### ↓ 起動
[root@(host) ~]# systemctl start httpd
### ↓ 自動起動有効化
[root@(host) ~]# systemctl enable httpd
### ↓ 確認
[root@(host) ~]# systemctl status httpd
(雑ぅ)
ファイアウォール
### ↓ 動いてるか確認
[root@(host) ~]# systemctl status firewalld
Active: active (running)
### ↓ 今のzoneを確認
[root@(host) ~]# firewall-cmd --get-default-zone
public
### ↓ publicのzoneにhttpを恒久的に追加
[root@(host) ~]# firewall-cmd --add-service=http --zone=public --permanent
success
### ↓ 反映
[root@(host) ~]# firewall-cmd --reload
success
### ↓ 確認
[root@(host) ~]# firewall-cmd --list-all-zones | less
[root@(host) ~]# systemctl status firewalld
Active: active (running)
ただ
WARNING: AllowZoneDrifting is enabled. This is considered an insecure configuration option. It will be removed in a future release. Please consider disabling it now.
って言われるので無効にして再確認した
[root@(host) ~]# vi /etc/firewalld/firewalld.conf
#AllowZoneDrifting=yes
AllowZoneDrifting=no
[root@(host) ~]# systemctl restart firewalld
[root@(host) ~]# systemctl status firewalld
ここまでで IP 直打ちでテストページは見えるはず
Apache設定
とりあえず ServerName 設定
[root@(host) conf]# cd /etc/httpd/conf/
[root@(host) conf]# cp -a httpd.conf httpd.conf-original
[root@(host) conf]# vi httpd.conf
ServerName domain1.com:80
VirtualHost 設定
[root@(host) conf]# cd ../conf.d/
[root@(host) conf.d]# vi virtualhost.conf
<VirtualHost _default_:80>
ServerName any
<Location />
Require all denied
</Location>
</VirtualHost>
<VirtualHost _default_:*>
ServerName any
<Location />
Require all denied
</Location>
</VirtualHost>
<VirtualHost *:80>
ServerName domain1.com
DocumentRoot /var/www/domain1.com
ErrorLog logs/domain1.com-error_log
CustomLog logs/domain1.com-access_log combined
</VirtualHost>
<VirtualHost *:80>
ServerName domain2.info
DocumentRoot /var/www/domain2.info
ErrorLog logs/domain2.info-error_log
CustomLog logs/domain2.info-access_log combined
</VirtualHost>
<VirtualHost *:80>
ServerName domain3.monster
DocumentRoot /var/www/domain3.monster
ErrorLog logs/domain3.monster-error_log
CustomLog logs/domain3.monster-access_log combined
</VirtualHost>
基本のバーチャルホスト設定は大体こんな感じ。
default:80 は設定外のドメインやIP直打ちのアクセスを禁止するため。
DNS設定済みならアクセスして確認できると思います。
autoindex.conf、welcome.conf は内容を空にする
(ディレクトリ一覧は表示させないのと、ウェルカムページも表示させないので不要)
[root@(host) conf.d]# cp -a autoindex.conf autoindex.conf_original
[root@(host) conf.d]# vi autoindex.conf
[root@(host) conf.d]# cp -a welcome.conf welcome.conf_original
[root@(host) conf.d]# vi welcome.conf
ちなみにディレクトリ一覧を表示させない Options Indexes の設定をしてないけど
初期値は /var/www/html に設定されているため
今回のドキュメントルートでは指定しなくても見えない状態です。
(あとドキュメントルートのディレクトリにはSGID指定した。
コンテンツ更新用にユーザーを別途追加する。つもり。)
### ↓ 設定の確認
[root@(host) conf.d]# apachectl configtest
### ↓ 反映
[root@(host) conf.d]# systemctl reload httpd
security.conf 作成
この項に関しては下記の方の記事を参照頂いたほうが良いと思います。
一部用途の都合で変えていますが、おおよそ倣いました。
SSL対応
mod_ssl インストール
[root@(host) conf.d]# dnf install mod_ssl
ファイアウォール
publicのzoneにhttpsを追加
[root@(host) conf.d]# firewall-cmd --add-service=https --zone=public --permanent
success
[root@(host) conf.d]# firewall-cmd --reload
success
Let's encrypt 証明書を取得
certbot-auto のインストール
EPALリポジトリから取得…と思いきや
CentOS8用にはまだ含まれていないようだったので
certbot-auto をダウンロードして使用します。
[root@(host) conf.d]# cd /tmp
[root@(host) tmp]# wget https://dl.eff.org/certbot-auto
[root@(host) tmp]# chmod 755 certbot-auto
[root@(host) tmp]# mv certbot-auto /usr/local/bin/
証明書の取得
DNSで正引きできている必要があります。
(ドメインでアクセスできてるなら大丈夫)
[root@(host) tmp]# certbot-auto certonly --webroot -w /var/www/domain1.com -d domain1.com -w /var/www/domain2.info -d domain2.info -w /var/www/domain3.monster -d domain3.monster --email user@example.com --server https://acme-v02.api.letsencrypt.org/directory --agree-tos --no-eff-email
マルチドメインの場合
-w ドキュメントルート -d ドメイン
という形で
ドキュメントルートの指定と、その後に指定したドメイン名がひも付きます。
これをドメイン分記載します。
※ ドキュメントルートが同じ場合、-w /path/to -d domain1 -d domain2
という形でOK
※ 作成される証明書は1つです。
最初に指定したものがメインのドメインということになり、
1つ目のドメイン名のみで作成されます。
1つの証明書で複数ドメインを証明する形になります。
※ ちなみにマルチドメインにしない場合は普通に分けて実行すればOKです
- --email メールアドレスです。有効期限のお知らせや緊急の更新およびセキュリティ通知に使用される
- --agree-tos は 規約の同意
- --no-eff-email は
スポンサーのElectronic Frontier Foundation(=EFF)にもメールアドレスを共有していいかという質問で
(EFFのメルマガのようなものが送られるようです。)
拒否する場合のオプションです
(メールや規約等のオプションは書かなくても途中で聞かれます)
実行が完了すると証明書が作成されます。
[root@(host) tmp]# ls -l /etc/letsencrypt/live/domain1.com/
※ マルチドメインの場合でも、
1つ目のドメイン名のみで作成されます。(2回目)
ファイル | 概要 |
---|---|
privkey.pem | 秘密鍵 |
fullchain.pem | SSL証明書&中間証明書 |
cert.pem | SSL証明書 |
chain.pem | 中間証明書 |
バージョン2.4.8以降の場合は、SSLCertificateFile ディレクティブでfullchain.pemが利用できる
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
バージョン2.4.8未満の場合は
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
ssl.conf
最初から記載されている VirtualHost ディレクティブをまるっと削除します。
[root@(host) conf.d]# vi ssl.conf
マルチドメインの証明書の場合は残しておいても大丈夫そうだったのですが
マルチドメイン用でない証明書の場合、
VirtualHost *:443 設定がメイン(=1件目)になっていると証明書エラーになる気がします。
(でも自前で設定する場合はやっぱり要らないので削除しておくのが無難かなと思います。)
VirtualHost 再編集
[root@(host) conf.d]# vi virtualhost.conf
SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLHonorCipherOrder on
SSLCipherSuite PROFILE=SYSTEM
SSLProxyCipherSuite PROFILE=SYSTEM
Header always set Strict-Transport-Security "max-age=63072000;"
<VirtualHost _default_:80>
ServerName any
<Location />
Require all denied
</Location>
</VirtualHost>
<VirtualHost _default_:443>
ServerName any
<Location />
Require all denied
</Location>
SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
</VirtualHost>
<VirtualHost _default_:*>
ServerName any
<Location />
Require all denied
</Location>
</VirtualHost>
<VirtualHost *:80>
ServerName domain1.com
DocumentRoot /var/www/domain1.com
ErrorLog logs/domain1.com-error_log
CustomLog logs/domain1.com-access_log combined
<Directory /var/www/domain1.com>
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://domain1.com/$1 [R=301,L]
</Directory>
</VirtualHost>
<VirtualHost *:443>
SSLEngine on
ServerName domain1.com
DocumentRoot /var/www/domain1.com
ErrorLog logs/domain1.com-ssl-error_log
CustomLog logs/domain1.com-ssl-access_log combined
SSLCertificateFile /etc/letsencrypt/live/domain1.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/domain1.com/privkey.pem
<Directory /var/www/domain1.com>
AllowOverride All
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName domain2.info
DocumentRoot /var/www/domain2.info
ErrorLog logs/domain2.info-error_log
CustomLog logs/domain2.info-access_log combined
<Directory /var/www/domain2.info>
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://domain2.info/$1 [R=301,L]
</Directory>
</VirtualHost>
<VirtualHost *:443>
SSLEngine on
ServerName domain2.info
DocumentRoot /var/www/domain2.info
ErrorLog logs/domain1.com-ssl-error_log
CustomLog logs/domain1.com-ssl-access_log combined
SSLCertificateFile /etc/letsencrypt/live/domain1.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/domain1.com/privkey.pem
<Directory /var/www/domain2.info>
AllowOverride All
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName domain3.monster
DocumentRoot /var/www/domain3.monster
ErrorLog logs/domain3.monster-error_log
CustomLog logs/domain3.monster-access_log combined
<Directory /var/www/domain3.monster>
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://domain3.monster/$1 [R=301,L]
</Directory>
</VirtualHost>
<VirtualHost *:443>
SSLEngine on
ServerName domain3.monster
DocumentRoot /var/www/domain3.monster
ErrorLog logs/domain1.com-ssl-error_log
CustomLog logs/domain1.com-ssl-access_log combined
SSLCertificateFile /etc/letsencrypt/live/domain1.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/domain1.com/privkey.pem
<Directory /var/www/domain3.monster>
AllowOverride All
</Directory>
</VirtualHost>
※ マルチドメインの場合でも
1つの証明書で複数ドメインを証明する形になります。(3回目)
作成された、1つ目のドメイン名のファイルをそれぞれに指定します
SSLCipherSuite
は個別に指定等はせず、
デフォルトで設定されているプロファイルをそのまま使用しています。
OpenSSH は、RHEL のシステム全体の暗号化ポリシーを使用し、
デフォルトのシステム全体の暗号化ポリシーレベルは、現在の脅威モデルに安全な設定を提供します。
暗号化の設定をより厳格にするには、現在のポリシーレベルを変更します。# update-crypto-policies --set FUTURE
### ↓ 確認
[root@(host) conf.d]# apachectl configtest
### ↓ 反映
[root@(host) conf.d]# systemctl restart httpd
実際にアクセスして確認できたら
SSL暗号化の安全性をチェックしよう
▼ SSL Server Test
Let's Encrypt 証明書の更新
まずは --dry-run
(実際には更新せず確認できるオプション)で一応確認
[root@(host) conf.d]# certbot-auto renew --dry-run
Congratulations, all renewals succeeded.
が出たらOK
crontab で更新と再起動を自動化
[root@(host) conf.d]# crontab -e
00 5 * * 5 /usr/local/bin/certbot-auto renew -q --deploy-hook "systemctl restart httpd"
※ root権限
…これでSSL証明書の設定まで完了となります。
お疲れさまでした!!(疲れた)
Discussion