INDEX
OpenBSD Webサーバ の SSL(TSL) 接続 (httpd on OpenBSD 7.7)
OpenBSD の Webサーバ httpd(relayd) で、SSL(TSL) 接続する。
自己証明書(オレオレ証明書) と ACME client を用いての Let's Encrypt の証明書の取得と更新をする。
httpd 自体を動かす設定は、OpenBSD/httpd/77(relayd) を参照。
- 関連 man → httpd(8), httpd.conf(5), openssl(1), acme-client(1)
自己証明書で SSL(TSL) 接続
秘密鍵と証明書の作成
LibreSSL の openssl コマンドを使って、サーバの秘密鍵と証明書(自己署名証明書)を作成する。
秘密鍵の作成
bbb# openssl genrsa -out /etc/ssl/private/server.key 2048 Generating RSA private key, 2048 bit long modulus ......................... ................................ e is 65537 (0x010001)
証明書署名要求(CSR)の作成
-subj オプションの内容は、対象のサーバに合わせて変える。指定しなければ、対話形式で入力となる。特に CN については、実際のホスト名(URL の FDQN)に合わせる。
bbb# openssl req -new -key /etc/ssl/private/server.key -out /etc/ssl/private/server.csr -subj "/C=JP/ST=Tokyo/L=Chuo-Ku/CN=example.com"
証明書(CRT)の作成
bbb# openssl x509 -days 3650 -req -signkey /etc/ssl/private/server.key -in /etc/ssl/private/server.csr -out /etc/ssl/server.crt Signature ok subject=/C=JP/ST=Tokyo/L=Chuo-Ku/CN=example.com
秘密鍵ファイルの内容を確認
bbb# openssl rsa -text -noout -in /etc/ssl/private/server.key RSA Private-Key: (2048 bit) modulus: :以下略
証明書署名要求の内容を確認
bbb# openssl req -text -noout -in /etc/ssl/private/server.csr
Certificate Request:
Data:
Version: 1 (0x0)
Subject: C=JP, ST=Tokyo, L=Chuo-Ku, CN=example.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
:以下略
証明書ファイルの内容を確認
bbb# openssl x509 -text -noout -in /etc/ssl/server.crt
Certificate:
Data:
Version: 1 (0x0)
Serial Number:
xx:xx:xx:xx:xx:xx:xx:xx
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=JP, ST=Tokyo, L=Chuo-Ku, CN=example.com
Validity
Not Before: Jul 8 12:58:32 2025 GMT
Not After : Jul 6 12:58:32 2035 GMT
Subject: C=JP, ST=Tokyo, L=Chuo-Ku, CN=example.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
:以下略
Webサーバ(httpd) の設定
/etc/httpd.conf に設定する。
TSL(HTTP over SSL/TLS)接続で待つポート番号と、作成したキーファイル /etc/ssl/private/server.key 、証明書 /etc/ssl/server.crt を指定する。
server "default" {
listen on * port 80
listen on * tls port 443
tls {
certificate "/etc/ssl/server.crt"
key "/etc/ssl/private/server.key"
}
# :中略
}
HTTPS通信の疎通確認
まぁ、ブラウザでアクセスして、期待するページが表示されれば OK なんだけど。
curl
curl コマンドでアクセスして確認する。自己証明書なので -k (--insecure) オプションをつけて、安全でないSSL接続も許可するようにする。
bbb# curl -svk https://localhost:443/ 1> /dev/null
* Host localhost:443 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:443...
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [304 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* TLSv1.3 (IN), TLS handshake, Unknown (8):
{ [10 bytes data]
* TLSv1.3 (IN), TLS handshake, Certificate (11):
{ [795 bytes data]
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
{ [264 bytes data]
* TLSv1.3 (IN), TLS handshake, Finished (20):
{ [36 bytes data]
* TLSv1.3 (OUT), TLS handshake, Finished (20):
} [36 bytes data]
* SSL connection using TLSv1.3 / TLS_CHACHA20_POLY1305_SHA256 / [blank] / UNDEF
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
* subject: C=JP; ST=Tokyo; L=Chuo-Ku; CN=example.com
* start date: Jul 8 12:58:32 2025 GMT
* expire date: Jul 6 12:58:32 2035 GMT
* issuer: C=JP; ST=Tokyo; L=Chuo-Ku; CN=example.com
* SSL certificate verify result: self signed certificate (18), continuing anyway.
* Certificate level 0: Public key type ? (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* Connected to localhost (::1) port 443
* using HTTP/1.x
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/8.13.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Connection: keep-alive
< Content-Length: 170
< Content-Type: text/html
< Date: Tue, 08 Jul 2025 13:03:41 GMT
< Last-Modified: Wed, 13 Jan 2021 15:54:49 GMT
< Server: OpenBSD httpd
<
{ [170 bytes data]
* Connection #0 to host localhost left intact
また、--tlsv1(-1) または、--sslv2(-2)、--sslv3(-3) を指定することで、TLSv1.0 以上 または、SSLv2、SSLv3 で接続する。もっとも、LibreSSL は SSLv2 および SSLv3 をサポートしない。さらに、--tlsv1.0 や --tlsv1.1、--tlsv1.2、--tlsv1.3 で、TLSv1.0 以上、TLSv1.1 以上… となる。curl 8.13.0 では、 --sslv2 や --sslv3 を指定しても TLSv1.3 で接続されてしまう。
openssl s_client
LibreSSL の openssl コマンドの s_client を利用して、TSL接続を確認する。
-connect localhost:443 で接続先のホストとポート番号を指定し、-showcerts でサーバ証明書を表示する。また、SNI(Server Name Indication) の場合、-servername localhost でサーバ名も指定する。
s_client は、SSL/TSL通信クライアントなので、サーバにコマンドを送るために標準入力の入力待ちとなる。エンターキーを押すか、nullディバイスを標準入力に渡す(< /dev/null)。
bbb# openssl s_client -showcerts -connect localhost:443 -servername localhost < /dev/null
CONNECTED(00000003)
depth=0 C = JP, ST = Tokyo, L = Chuo-Ku, CN = example.com
verify error:num=18:self signed certificate
verify return:1
---
Certificate chain
0 s:/C=JP/ST=Tokyo/L=Chuo-Ku/CN=example.com
i:/C=JP/ST=Tokyo/L=Chuo-Ku/CN=example.com
-----BEGIN CERTIFICATE-----
:中略
-----END CERTIFICATE-----
---
Server certificate
subject=/C=JP/ST=Tokyo/L=Chuo-Ku/CN=example.com
issuer=/C=JP/ST=Tokyo/L=Chuo-Ku/CN=example.com
---
No client certificate CA names sent
Server Temp Key: ECDH, X25519, 253 bits
---
SSL handshake has read 1326 bytes and written 359 bytes
---
New, TLSv1/SSLv3, Cipher is TLS_CHACHA20_POLY1305_SHA256
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.3
Cipher : TLS_CHACHA20_POLY1305_SHA256
Session-ID:
Session-ID-ctx:
Master-Key:
Start Time: 1751980299
Timeout : 7200 (sec)
Verify return code: 18 (self signed certificate)
---
DONE
bbb#
使用するTLSのバージョン指定(-tls1 | -tls1_1 | -tls1_2 | -tls1_3)、制限(-no_tls1 | -no_tls1_1 | -no_tls1_2 | -no_tls1_3)、使用する暗号スイートを指定(-cipher cipherlist)(リストは ciphers コマンドで確認)ができる。
bbb$ openssl ciphers -v
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=TLSv1.3 Au=TLSv1.3 Enc=ChaCha20-Poly1305 Mac=AEAD
:中略
AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256
:中略
AES128-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA256
:中略
bbb$
bbb$ openssl s_client -showcerts -connect localhost:443 -servername localhost -tls1_2 -cipher AES128-SHA256 < /dev/null
CONNECTED(00000003)
depth=0 C = JP, ST = Tokyo, L = Chuo-Ku, CN = example.com
verify error:num=18:self signed certificate
verify return:1
---
:中略
---
New, TLSv1/SSLv3, Cipher is AES128-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : AES128-SHA256
Session-ID:
Session-ID-ctx:
Master-Key: 797EB977E812761F0BD926078C332CEB7D9DFC1CF495FC9299DEECB58DD5E3DF39CA557D7A622B9BC54C725425F4946F
Start Time: 1751980581
Timeout : 7200 (sec)
Verify return code: 18 (self signed certificate)
---
DONE
bbb$
Let's Encrypt の証明書で SSL(TSL) 接続
OpenBSD 6.1 から追加された ACME クライアントを利用して、Let's Encrypt の取得・更新を行い、SSL(TSL) 接続する。
acme-client の設定
/etc/acme-client.conf に設定する。サンプルが /etc/examples/acme-client.conf にある。
bbb# cp -p /etc/examples/acme-client.conf /etc/
サンプルをコピーして、末尾の domain 部分の example.com 等を自分のドメインに変更する。複数のドメイン名に対応する Subject Alternative Names(SANs) を利用する場合は、alternative names にカンマまたはスペース区切りで列挙する。
domain example.com {
#alternative names { secure.example.com }
domain key "/etc/ssl/private/example.com.key"
domain full chain certificate "/etc/ssl/example.com.fullchain.pem"
sign with letsencrypt
}
Webサーバ(httpd) の設定
/etc/httpd.conf に設定する。サンプルが /etc/examples/httpd.conf にある。
必要になるのは、ドメイン名の検証を行う HTTP-01 チャレンジ の応答を返すための設定と、取得した証明書(とその秘密鍵)ファイルを参照するようにする。
server "default" {
listen on * port 80
listen on * tls port 443
tls {
certificate "/etc/ssl/example.com.fullchain.pem"
key "/etc/ssl/private/example.com.key"
}
location "/.well-known/acme-challenge/*" {
root "/acme"
request strip 2
}
}
証明書の取得
acme-client を実行して、証明書が取得できたら、httpd を再起動して、秘密鍵と証明書を読み込み直す。
bbb# rcctl restart httpd httpd(ok) httpd(ok) bbb# acme-client -v example.com acme-client: /etc/ssl/private/example.com.key: generated RSA domain key acme-client: /etc/acme/letsencrypt-privkey.pem: generated RSA account key acme-client: https://acme-v02.api.letsencrypt.org/directory: directories acme-client: acme-v02.api.letsencrypt.org: DNS: 172.65.32.248 acme-client: acme-v02.api.letsencrypt.org: DNS: 2606:4700:60:0:f53d:5624:85c7:3a2c account key: https://acme-v02.api.letsencrypt.org/acme/acct/2515807891 acme-client: account key: https://acme-v02.api.letsencrypt.org/acme/acct/2515807891 acme-client: dochngreq: https://acme-v02.api.letsencrypt.org/acme/authz/2515807891/549382395411 acme-client: challenge, token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, uri: https://acme-v02.api.letsencrypt.org/acme/chall/2515807891/549382395411/0Ld-_w, status: 0 acme-client: /var/www/acme/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: created acme-client: https://acme-v02.api.letsencrypt.org/acme/chall/2515807891/549382395411/0Ld-_w: challenge acme-client: order.status 0 acme-client: dochngreq: https://acme-v02.api.letsencrypt.org/acme/authz/2515807891/549382395411 acme-client: challenge, token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, uri: https://acme-v02.api.letsencrypt.org/acme/chall/2515807891/549382395411/0Ld-_w, status: 0 acme-client: /var/www/acme/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: created acme-client: https://acme-v02.api.letsencrypt.org/acme/chall/2515807891/549382395411/0Ld-_w: challenge acme-client: order.status 0 acme-client: dochngreq: https://acme-v02.api.letsencrypt.org/acme/authz/2515807891/549382395411 acme-client: challenge, token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, uri: https://acme-v02.api.letsencrypt.org/acme/chall/2515807891/549382395411/0Ld-_w, status: 0 acme-client: /var/www/acme/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: created acme-client: https://acme-v02.api.letsencrypt.org/acme/chall/2515807891/549382395411/0Ld-_w: challenge acme-client: order.status 0 acme-client: dochngreq: https://acme-v02.api.letsencrypt.org/acme/authz/2515807891/549382395411 acme-client: challenge, token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, uri: https://acme-v02.api.letsencrypt.org/acme/chall/2515807891/549382395411/0Ld-_w, status: 2 acme-client: order.status 1 acme-client: https://acme-v02.api.letsencrypt.org/acme/finalize/2515807891/404143812031: certificate acme-client: order.status 3 acme-client: https://acme-v02.api.letsencrypt.org/acme/cert/zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz: certificate acme-client: /etc/ssl/example.com.crt: created bbb# bbb# rcctl restart httpd httpd(ok) httpd(ok) bbb#
証明書の自動更新
Let's Encrypt の証明書の有効期限は 90日 で作成される。このため、証明書を維持するには、定期的に更新が必要となる。
acme-client は、有効期限が30日を切ると更新を行うようになるので、 acme-client example.com && rcctl reload httpd とコマンドをつなげて、証明書の更新と再起動を行うように、cron に設定するか、/etc/daily.local や /etc/weekly.local にコマンドを記載して実行させる。
bbb# cat /etc/daily.local # update Let's Encrypt certificate. acme-client example.com && rcctl reload httpd bbb#
最終更新時間:2025年07月08日 22時45分49秒 指摘や意見などあればSandBoxのBBSへ。