前回の記事では LINE Messaging API を利用して、コマンドラインからプッシュメッセージを送信するツールを作成しました。
その発展形として Webhook を利用して bot サーバを作ろうとしたのですが、Webhook を利用するにはサーバの SSL/TLS 証明書が必要です。
というわけで、今回は自宅サーバに向けて SSL/TLS を無料で発行する手順についてメモっておきます。
※ 今回は LINE Messaging API シリーズに関連しているといえばしているのですが、独立した話題になりますので別記事として書きました。
この記事の想定
- 最終目標:自宅サーバに SSL/TLS 証明書を登録し、HTTPS で通信できるようにする
- 対象:HTTPS 用の自宅サーバを立てたい人、Messaging API の Webhook を利用して bot サーバを立てたい人
サーバの概要
- Raspberry Pi 5
- OS : Ubuntu 23.10 (Linux kernel ver.6.5.0, 64bit)
- CPU : BCM2835
- RAM : 8GB
Let’s Encrypt を使う
SSL/TLS 証明書を手に入れるには認証局での認証処理が必要です。認証には手数料が有料の場合が多いですが、Let’s Encrypt であれば無料で発行できます。
ドメインの入手
認証したいドメインを予め取得しておきます(サブドメインも可)。以降、[YOUR DOMAIN HERE]
と示します。
手順
前準備:ポートを開放しておく
サーバ側で 80番ポートを開放し、ルータ側でポートマッピングを設定しておきます。
$ sudo ufw allow 80
前準備:サーバアプリケーション(apache2 など)を停止しておく
後ほど使う certbot
は TCP 80 番ポートを認証時に利用します。
もしサーバ側で既に apache2(または nginx)などのサーバアプリケーションが実行されている場合は、予め停止しておいてください。
$ sudo systemctl stop apache2
certbot のインストール&認証
まずは証明書生成ツールである certbot
をインストール。
$ sudo apt install certbot
インストールが完了したらツールを起動します。
$ sudo certbot certonly --standalone -d [YOUR DOMAIN HERE]
初回起動時はメールアドレスの入力、同意書への同意を求められます。
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices)
(Enter 'c' to cancel): [YOUR E-MAIL ADDRESS HERE]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.pdf. You must agree in
order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o:
次に証明書の発行完了後にメールアドレスの共有をしても良いか?と聞かれます。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o:
これにて初期設定は完了です。続いてドメインの認証処理が開始されます。
Account registered.
Requesting a certificate for [YOUR DOMAIN]
ここで DNS のチェック等が入ります。もしドメインからサーバまで 80 番ポートでアクセスできない場合、ここで失敗します。
Certbot failed to authenticate some domains (authenticator: standalone). The Certificate Authority reported these problems:
Domain: [YOUR DOMAIN]
Type: connection
Detail: xxx.xxx.xxx.xxx: Fetching http://[YOUR DOMAIN]/.well-known/acme-challenge/...: Timeout during connect (likely firewall problem)
成功したら証明書のファイルパスが表示されます。
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/[YOUR DOMAIN]/fullchain.pem
Key is saved at: /etc/letsencrypt/live/[YOUR DOMAIN]/privkey.pem
This certificate expires on 2025-01-14.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
以降、この証明書を使って SSL/TLS 通信が可能です。
例えば、Rust の Actix web の場合:
#[post("/")]
async fn index() -> impl Responder {
...
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
rustls::crypto::aws_lc_rs::default_provider()
.install_default()
.unwrap();
// 証明書を読み込み(ここ!)
let mut certs_file = BufReader::new(File::open("fullchain.pem").unwrap());
let mut key_file = BufReader::new(File::open("privkey.pem").unwrap());
// load TLS certs and key
// to create a self-signed temporary cert for testing:
// `openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost'`
let tls_certs = rustls_pemfile::certs(&mut certs_file)
.collect::<Result<Vec<_>, _>>()
.unwrap();
let tls_key = rustls_pemfile::pkcs8_private_keys(&mut key_file)
.next()
.unwrap()
.unwrap();
// set up TLS config options
let tls_config = rustls::ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(tls_certs, rustls::pki_types::PrivateKeyDer::Pkcs8(tls_key))
.unwrap();
HttpServer::new(|| {
App::new()
.service(index)
})
.bind_rustls_0_23(("0.0.0.0", 443), tls_config)?
.run()
.await
}
証明書の有効期限は3ヶ月間です。自動更新をさせたい場合はこちら ↓ の記事が参考になるかと思います。
おわりに
次回はこれを利用して、Rust で LINE Messaging API の Webhook サーバを作っていきます。