👋
CentOS 7.9でApache 2.4のHTTP/2対応
CentOS 7.9でApache 2.4のHTTP/2対応の設定手順を説明します。
本番環境でDocker導入済みの場合は、Apache 2.4のDockerイメージをpullしてきてHTTP/2を有効化した方が簡単だと思います。
本手順は、Docker未導入のCentOS 7.9サーバでのApache 2.4導入例として捉えてください。
DockerでCentOS 7.9を起動
説明のため、CentOS 7.9のDockerイメージを使用します。
docker run --name http2 -d centos:7.9.2009 /bin/sh -c "while :; do sleep 10; done"
# systemctlコマンドを使用できるようにしたい場合は、
# 上記のコマンドではなく、以下のコメントアウトしているコマンドを使用する。
# docker run --privileged --name http2 -d centos:7.9.2009 /sbin/init
# ただし、本番環境では--privilegedオプションは権限が強く危険なので注意が必要とのこと。
docker exec -it http2 /bin/bash
yum update -y
自己署名サーバ証明書の生成
yum install -y openssl
yum install -y vim
touch ./generate-cert.sh
chmod 770 ./generate-cert.sh
vim ./generate-cert.sh
自己署名サーバ証明書の作成手順は、以下のサイトをほぼそのまま参考にしました。
./generate-cert.sh
CA_DIR=./pki/CA
CA_NAME="local-CA"
mkdir -p "${CA_DIR}/private/"
mkdir -p "${CA_DIR}/certs/"
# CA
echo ''
echo '-----'
echo '[[[ CA ]]]'
echo '-----'
# CAの秘密鍵(RSA 2048 bit)の生成
openssl genrsa 2048 > "${CA_DIR}/private/${CA_NAME}.key"
# CAのCSR(署名アルゴリズムsha256)の生成
openssl req -new -key "${CA_DIR}/private/${CA_NAME}.key" -sha256 -out "${CA_DIR}/${CA_NAME}.csr"
# CAのCSR, CAの秘密鍵 からCAのCA証明書生成
openssl x509 -days 1095 -in "${CA_DIR}/${CA_NAME}.csr" -req -signkey "${CA_DIR}/private/${CA_NAME}.key" -out "${CA_DIR}/certs/${CA_NAME}.pem"
TLS_DIR=./pki/tls
SERVER_NAME="local-server"
mkdir -p "${TLS_DIR}/private/"
mkdir -p "${TLS_DIR}/certs/"
# サーバ
echo ''
echo '-----'
echo '[[[ Server ]]]'
echo '-----'
# サーバの秘密鍵(RSA 2048 bit)の生成
openssl genrsa 2048 > "${TLS_DIR}/private/${SERVER_NAME}.key"
# サーバのCSR(署名アルゴリズムsha256)の生成
openssl req -new -key "${TLS_DIR}/private/${SERVER_NAME}.key" -sha256 -out "${TLS_DIR}/${SERVER_NAME}.csr"
# サーバのCSR, CAの秘密鍵, CAのCA証明書 からサーバのサーバ証明書生成
## openssl caコマンド実行時に
## - CAデータベースのディレクトリとしてCA_DIRを使用する
## - CAの署名policyとしてpolicy_anythingを使用する
## ように設定ファイルを作成。
## 設定ファイルはCentOS 7.9.2009 (Core)のOpenSSL 1.0.2k-fipsの/etc/pki/tls/openssl.cnfファイルを元にした。
cat > ./ca.conf <<'EOF'
####################################################################
[ ca ]
default_ca = CA_default # The default ca section
####################################################################
[ CA_default ]
EOF
echo dir = "'${CA_DIR}'" >> ./ca.conf
cat >> ./ca.conf <<'EOF'
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index.txt # database index file.
#unique_subject = no # Set to 'no' to allow creation of
# several ctificates with same subject.
new_certs_dir = $dir/newcerts # default place for new certs.
certificate = $dir/cacert.pem # The CA certificate
serial = $dir/serial # The current serial number
crlnumber = $dir/crlnumber # the current crl number
# must be commented out to leave a V1 CRL
crl = $dir/crl.pem # The current CRL
private_key = $dir/private/cakey.pem# The private key
RANDFILE = $dir/private/.rand # private random number file
x509_extensions = usr_cert # The extentions to add to the cert
# Comment out the following two lines for the "traditional"
# (and highly broken) format.
name_opt = ca_default # Subject Name options
cert_opt = ca_default # Certificate field options
# Extension copying option: use with caution.
# copy_extensions = copy
# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
# so this is commented out by default to leave a V1 CRL.
# crlnumber must also be commented out to leave a V1 CRL.
# crl_extensions = crl_ext
default_days = 365 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = sha256 # use SHA-256 by default
preserve = no # keep passed DN ordering
# A few difference way of specifying how similar the request should look
# For type CA, the listed attributes must be the same, and the optional
# and supplied fields are just that :-)
EOF
echo policy = policy_anything >> ./ca.conf
cat >> ./ca.conf <<'EOF'
# For the 'anything' policy
# At this point in time, you must list all acceptable 'object'
# types.
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ usr_cert ]
# These extensions are added when 'ca' signs a request.
# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.
basicConstraints=CA:FALSE
# Here are some examples of the usage of nsCertType. If it is omitted
# the certificate can be used for anything *except* object signing.
# This is OK for an SSL server.
# nsCertType = server
# For an object signing certificate this would be used.
# nsCertType = objsign
# For normal client use this is typical
# nsCertType = client, email
# and for everything including object signing:
# nsCertType = client, email, objsign
# This is typical in keyUsage for a client certificate.
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
# This will be displayed in Netscape's comment listbox.
nsComment = "OpenSSL Generated Certificate"
# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
# This stuff is for subjectAltName and issuerAltname.
# Import the email address.
# subjectAltName=email:copy
# An alternative to produce certificates that aren't
# deprecated according to PKIX.
# subjectAltName=email:move
# Copy subject details
# issuerAltName=issuer:copy
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
#nsBaseUrl
#nsRevocationUrl
#nsRenewalUrl
#nsCaPolicyUrl
#nsSslServerName
# This is required for TSA certificates.
# extendedKeyUsage = critical,timeStamping
EOF
## CAデータベースの中身を作成
touch "${CA_DIR}/index.txt"
echo 01 > "${CA_DIR}/serial"
mkdir -p "${CA_DIR}/newcerts"
## サーバのCSR, CAの秘密鍵, CAのCA証明書 からサーバのサーバ証明書生成
openssl ca -config "./ca.conf" -days 1095 -in "${TLS_DIR}/${SERVER_NAME}.csr" -out "${TLS_DIR}/certs/${SERVER_NAME}.pem" -keyfile "${CA_DIR}/private/${CA_NAME}.key" -cert "${CA_DIR}/certs/${CA_NAME}.pem"
./generate-cert.sh
# [[[ CA ]]]
# [[Server]]
# のそれぞれでCA、サーバそれぞれの証明書作成用のCSRの情報を聞かれるので、適当に入力。
# ただし、サーバのSCRについての以下の質問:
# Common Name (eg, your name or your server's hostname) []:
# に対しては、「localhost」と正しくドメイン名を入力しておく必要あり。
# (このドメイン名でサーバ証明書が生成されるため。)
# 生成したキーや証明書をApacheで使用するためにコピー
cp /pki/tls/certs/local-server.pem /etc/pki/tls/certs/localhost.crt
cp /pki/tls/private/local-server.key /etc/pki/tls/private/localhost.key
cp /pki/CA/certs/local-CA.pem /etc/pki/CA/certs/ca.crt
Apacheのインストール
次にApacheをインストールします。
yum install -y wget
# Apacheの最新版をyumで取得できるよう設定
yum install -y epel-release
pushd /etc/yum.repos.d && wget https://repo.codeit.guru/codeit.el$(rpm -q --qf "%{VERSION}" $(rpm -q --whatprovides redhat-release)).repo && popd
# 最新版になっていることを確認(私が実行した時点ではVersion:2.4.57)
yum info httpd
# インストール
yum install -y httpd
yum install -y mod_http2 mod_ssl
httpd -v
結果は以下のとおり。
Server version: Apache/2.4.57 (codeit)
Server built: Apr 6 2023 17:31:51
# 設定ファイルをコピーしてバックアップをとっておく。
cp /etc/httpd/conf.d/ssl.conf /etc/httpd/conf.d/ssl.conf.bak
vim /etc/httpd/conf.d/ssl.conf
以下のディレクティブの行を確認して、設定値の場所に、
サーバ証明書と秘密鍵のファイルが存在していることを確認。
/etc/httpd/conf.d/ssl.conf
SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
ファイルの末尾の方の<VirtualHost *:443>セクションに以下のとおり追記。
/etc/httpd/conf.d/ssl.conf
<VirtualHost *:443>
# (省略)
# <VirtualHost>セクション内の末尾に以下を追記
# HTTP2
Protocols h2 http/1.1
# LogLevel debug
</VirtualHost>
本来は、以下の設定も有効にする必要があります。
しかし、既にファイル
- /etc/httpd/conf.modules.d/00-ssl.conf
- /etc/httpd/conf.d/ssl.conf
- /etc/httpd/conf.modules.d/10-h2.conf
の中で設定が有効になっているので、省略します。
/etc/httpd/conf/httpd.conf
# Listenの設定は他の箇所でデフォルトで設定済みなので省略
Listen 443
# SSLの有効化設定は他の箇所でデフォルトで設定済みなので省略
SSLEngine on
# Moduleの読み込みも他の箇所で実行済みなので省略
# SSL
LoadModule ssl_module modules/mod_ssl.so
# HTTP2
LoadModule http2_module modules/mod_http2.so
curlで動作確認
最後に、curlでApacheとHTTP/2で通信できることを確認します。
# curl最新版をインストールするためにyumのリポジトリを設定
vim /etc/yum.repos.d/city-fan.repo
/etc/yum.repos.d/city-fan.repo
[CityFan]
name=City Fan Repo
baseurl=http://www.city-fan.org/ftp/contrib/yum-repo/rhel$releasever/$basearch/
enabled=1
gpgcheck=0
yum update -y
yum install -y curl
curl --version
結果は以下のとおり。
curl 8.2.1 (x86_64-redhat-linux-gnu) libcurl/8.2.1 NSS/3.79 zlib/1.2.7 libpsl/0.20.2 (+libidn2/2.3.2) libssh2/1.11.0 nghttp2/1.56.0 OpenLDAP/2.4.44
Release-Date: 2023-07-26
Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps mqtt pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS GSS-API HSTS HTTP2 HTTPS-proxy IPv6 Kerberos Largefile libz NTLM NTLM_WB PSL SPNEGO SSL UnixSockets
通信確認用のHTMLファイルを作成します。
vim /var/www/html/index.html
/var/www/html/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>title</title>
<!-- <link rel="stylesheet" href="style.css">
<script src="script.js"></script> -->
</head>
<body>
Hello, World!
</body>
</html>
# Apacheサーバの起動
httpd
# curlでApacheとHTTP/2通信が可能か確認
curl --http2-prior-knowledge --cacert /etc/pki/CA/certs/ca.crt -v https://localhost/ -o "tmp.txt"
出力結果に以下の行が出力されていれば、
HTTP/2で通信成功です。
< HTTP/2 200
Discussion