自宅サーバーのSSL証明書を無料取得する!Let’s Encrypt&CertbotでDDNSドメインをHTTPS化する完全ガイド

未分類

自宅サーバーをインターネットに公開する際、HTTPSに対応していないと「このサイトは安全ではありません」という警告がブラウザに表示され、実用的に使えません。Flask APIやLINEミニアプリ、Grafanaダッシュボードをhttps://xxxx.tplinkdns.com で公開するためには、SSL/TLS証明書が必要です。
本記事では、無料でSSL証明書を発行できる「Let’s Encrypt」と、証明書取得・管理を自動化する「Certbot」を使って、自宅サーバーのDDNSドメインをHTTPS化する手順を解説します。
本記事は「自宅サーバーをSSL化する!NginxリバースプロキシとLet’s Encrypt設定ガイド」の前編として、Nginx設定の前に必要なSSL証明書の取得と自動更新設定に特化して解説します。

なぜこの機能を作ったのか?

自宅サーバーをインターネットに公開した際、最初はHTTP(80番ポート)だけで運用していました。しかしLINEミニアプリ(LIFF)はHTTPSが必須要件であり、外部APIもHTTPSでなければブラウザのセキュリティポリシーにより呼び出せません。
SSL証明書の取得というと「費用がかかる」「難しい」というイメージがありますが、Let’s Encryptを使えば完全無料で、コマンド数行で取得できます。また取得した証明書は90日で期限が切れますが、Certbotのsystemdタイマーが自動的に更新してくれるため、一度設定すれば管理の手間はほぼゼロです。
本記事の環境ではTP-Link DDNS(xxxx.tplinkdns.com)のドメインを使用しており、DDNSドメインでもLet’s Encryptの証明書を問題なく取得できることを確認しています。

費用ゼロ・自動更新で自宅サーバーをHTTPS対応にして、LINEミニアプリも外部APIも安全に使えるようにしたい!

実現したいこと

  • Let’s EncryptのSSL証明書をDDNSドメイン(xxxx.tplinkdns.com)で無料取得する
  • Certbotを使って証明書取得と自動更新をコマンドで完結させる
  • 90日の有効期限を気にせず、自動更新で常に有効な証明書を維持する
  • 証明書更新時にNginxを自動リロードして、サービスを停止しない

この記事でわかること

  • Let’s EncryptとACMEプロトコル・HTTP-01チャレンジの仕組み
  • CertbotのNginxプラグインを使った証明書取得コマンドと手順
  • 取得した証明書ファイル(fullchain.pem, privkey.pem)の構成と役割
  • systemd certbot.timerによる自動更新の仕組みと確認方法
  • certbot renew --dry-run で更新をシミュレーションする方法
  • 証明書の有効期限や状態を確認するコマンド

必要な準備と用意するもの

ハードウェア
  • 自宅サーバー(本記事はNUCBox G3 Plus、Ubuntu/Debian系Linux)
  • 外部公開済みのネットワーク環境(ポート80・443がインターネットから到達可能)
ソフトウェア/サービス
  • Ubuntu / Raspberry Pi OS(Debian系Linux)
  • Nginx(インストール済み・起動中)
  • DDNSドメイン(本記事はTP-Link DDNS: xxxx.tplinkdns.com)
    • 一般的なDDNSドメインでも同じ手順で取得できます
  • HGW&Decoのポート転送設定が完了していること(ポート80・443が外部から到達可能)

完成イメージ

証明書取得後は、以下のパスに証明書ファイルが配置され、Nginxから参照できる状態になります。


$ sudo certbot certificates

Found the following certs:
  Certificate Name: xxxx.tplinkdns.com
    Serial Number: ...
    Key Type: ECDSA
    Domains: xxxx.tplinkdns.com
    Expiry Date: 2026-08-XX (VALID: 89 days)
    Certificate Path: /etc/letsencrypt/live/xxxx.tplinkdns.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/xxxx.tplinkdns.com/privkey.pem

/etc/letsencrypt/
├── live/
│   └── xxxx.tplinkdns.com/
│       ├── cert.pem       ← サーバー証明書
│       ├── chain.pem      ← 中間証明書
│       ├── fullchain.pem  ← cert.pem + chain.pem(Nginxで使用)
│       └── privkey.pem    ← 秘密鍵(Nginxで使用)
├── renewal/
│   └── xxxx.tplinkdns.com.conf  ← 自動更新設定
└── renewal-hooks/
    └── deploy/            ← 更新後に実行するスクリプト置き場

システムの仕組み

Let’s Encrypt と ACME プロトコル

Let’s Encrypt とは
非営利団体 ISRG(Internet Security Research Group)が運営する、無料のSSL/TLS証明書認証局(CA)です。2016年から正式運用されており、全世界で数億ドメイン以上の証明書を発行しています。有効期限は90日間で、自動更新が前提の設計です。

証明書を取得する際、Let’s Encryptは「このドメインを本当に管理しているか」を確認するためにACME(Automated Certificate Management Environment)プロトコルによる認証チャレンジを行います。

HTTP-01チャレンジの仕組み

本記事で使用するHTTP-01チャレンジは最もシンプルな認証方式です。


① Certbot が Let's Encrypt サーバーに証明書発行を要求
② Let's Encrypt がランダムなトークンを生成して Certbot に通知
③ Certbot がそのトークンをサーバーの特定URLに配置
   http://xxxx.tplinkdns.com/.well-known/acme-challenge/{token}
④ Let's Encrypt が外部から上記URLにアクセスしてトークンを確認
⑤ 確認成功 → 証明書を発行

HTTP-01チャレンジにはポート80(HTTP)の外部公開が必要
Let’s Encryptのサーバーが外部から http://xxxx.tplinkdns.com/.well-known/acme-challenge/ にアクセスできる必要があります。HGWとDecoでポート80の転送設定が完了していることを確認してください。

証明書の有効期限と自動更新の仕組み

Let’s Encryptの証明書は有効期限90日です。短いように感じますが、これは自動更新を前提とした設計です。Certbotは有効期限まで30日を切ったタイミングで自動更新を試みます。

systemd certbot.timerの動作
Certbotをaptでインストールすると certbot.timer が自動的に登録されます。このタイマーは1日2回(午前0時・正午)、最大12時間のランダム遅延を加えて certbot renew を実行します。ランダム遅延はLet’s Encryptサーバーへの一時集中を避けるための設計です。有効期限まで30日以上あれば何もせず終了するため、サーバーへの負荷はほぼゼロです。

実装のポイント

Nginxプラグイン(–nginx)を使うのが最も簡単
Certbotには複数の認証方式(プラグイン)があります。Nginxがすでにインストールされている環境なら --nginx プラグインを使うと、証明書取得・Nginx設定の自動書き換え・証明書更新時のNginx自動リロードがすべて自動で行われます。

ECDSA鍵で取得するとパフォーマンスが向上する
Certbotのデフォルト鍵タイプはRSAですが、--key-type ecdsa を指定するとECDSA(楕円曲線暗号)鍵で証明書を取得できます。RSAより鍵長が短く、TLSハンドシェイクが高速になります。本記事の環境でも ECDSA を採用しています。

Certbotの証明書取得レート制限に注意
Let’s Encryptには同一ドメインで週5件までという証明書発行の制限(レートリミット)があります。テストや設定ミスで何度も実行すると制限に達することがあります。設定をテストする際は --dry-run フラグを使い、実際の発行は最小限に抑えましょう。

事前準備

ポート80・443が外部から到達可能か確認する

Let’s EncryptのHTTP-01チャレンジにはポート80の外部公開が必須です。CMANでポート80・443の開放状況を確認します。

確認するポート
・ポート 80(HTTP)→「開いています」であること(チャレンジに必須)
・ポート 443(HTTPS)→「開いています」であること(証明書取得後に使用)

Nginxが起動しているか確認する


# Nginx が起動中であることを確認
$ sudo systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
   Active: active (running)   ← これが表示されればOK

# ポート80でListenしているか確認
$ sudo ss -tlnp | grep :80
LISTEN  0  511  0.0.0.0:80  0.0.0.0:*  users:(("nginx",...))

実装方法

① Certbot と Nginx プラグインをインストールする


$ sudo apt update
$ sudo apt install certbot python3-certbot-nginx

# インストール確認
$ certbot --version
certbot 2.9.0

snap版 vs apt版
Certbot公式サイトではsnap版をすすめていますが、Ubuntu/Debianではapt版も十分に機能します。本記事ではaptでインストールしたバージョン(2.9.0)を使用しています。snap版を使う場合は sudo snap install --classic certbot でインストールします。

② SSL証明書を取得する(Nginx プラグイン)

Nginxプラグインを使って証明書を取得します。--nginx を指定することで、Certbotが自動的にNginxの設定を確認しながら認証を行います。


# ECDSA鍵でSSL証明書を取得する(推奨)
$ sudo certbot --nginx -d xxxx.tplinkdns.com --key-type ecdsa

# RSA鍵でよい場合(--key-type を省略するとRSAになる)
# $ sudo certbot --nginx -d xxxx.tplinkdns.com

実行すると対話形式でいくつかの質問が表示されます。


Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel): yourmail@example.com   ← メールアドレスを入力(更新通知に使用)

- - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf
Do you agree? (Y)es/(N)o: Y   ← 利用規約に同意

- - - - - - - - - - - - - - - - - - - - - - - - - -
Would you like to share your email address with the Electronic Frontier Foundation,
a founding partner of the Let's Encrypt project? (Y)es/(N)o: N   ← EFFへのメール共有(任意)

- - - - - - - - - - - - - - - - - - - - - - - - - -
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/xxxx.tplinkdns.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/xxxx.tplinkdns.com/privkey.pem

「チャレンジに失敗しました」と表示される場合
HTTP-01チャレンジが失敗する原因のほとんどは、外部からポート80に到達できないことです。
① HGW のポートマッピング(80番 → Deco)が設定されているか確認
② Deco のポート転送(80番 → サーバー:80)が設定されているか確認
③ UFW でポート80が許可されているか確認(sudo ufw status
④ Nginx が起動しているか確認

③ 取得した証明書ファイルを確認する


# 取得した証明書の一覧を確認
$ sudo certbot certificates

Found the following certs:
  Certificate Name: xxxx.tplinkdns.com
    Serial Number: xxxxxxxxxxxxxxxx
    Key Type: ECDSA
    Domains: xxxx.tplinkdns.com
    Expiry Date: 2026-08-XX (VALID: 89 days)
    Certificate Path: /etc/letsencrypt/live/xxxx.tplinkdns.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/xxxx.tplinkdns.com/privkey.pem

# 証明書の詳細情報(有効期限・発行者・ドメイン)
$ openssl x509 -in /etc/letsencrypt/live/xxxx.tplinkdns.com/fullchain.pem -noout -dates -subject
notBefore=May 30 ...
notAfter=Aug 28 ...    ← 有効期限
subject=CN = xxxx.tplinkdns.com

証明書ファイルの役割を整理します。

ファイル名内容Nginxでの使用
cert.pemサーバー証明書のみ通常は使用しない
chain.pem中間証明書チェーンのみ通常は使用しない
fullchain.pemcert.pem + chain.pem(連結)ssl_certificate に指定
privkey.pem秘密鍵ssl_certificate_key に指定

秘密鍵(privkey.pem)の取り扱いに注意
/etc/letsencrypt/live/ ディレクトリはrootのみが読み取れるパーミッションになっています。Nginxはroot権限で起動するため問題ありませんが、秘密鍵を他のプロセスやユーザーが読み取れないようにしてください。

④ Nginx の設定ファイルに証明書パスを記述する

--nginx プラグインで取得した場合、Certbotが自動的にNginxの設定ファイルを書き換えてくれますが、本記事では手動で設定する方法も合わせて解説します。Nginxの設定ファイル(/etc/nginx/sites-available/default 等)に以下を記述します。


server {
    listen 443 ssl;
    server_name xxxx.tplinkdns.com;

    # Let's Encrypt が発行した証明書(Certbot管理)
    ssl_certificate     /etc/letsencrypt/live/xxxx.tplinkdns.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/xxxx.tplinkdns.com/privkey.pem;

    # Certbot が自動生成した推奨SSL設定
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    # ...(その他の設定)
}

# HTTP → HTTPS リダイレクト
server {
    listen 80;
    server_name xxxx.tplinkdns.com;
    return 301 https://$host$request_uri;
}

options-ssl-nginx.conf について
/etc/letsencrypt/options-ssl-nginx.conf は Certbot が自動生成する推奨SSL設定ファイルです。TLSバージョンの制限(TLS 1.2以上)や推奨暗号スイートなどが含まれており、include で読み込むことでセキュリティの高いSSL設定が簡単に適用できます。

⑤ 自動更新の動作を確認する

Certbotをaptでインストールすると、certbot.timer(systemdタイマー)が自動的に設定されます。


# certbot.timer の状態確認
$ systemctl status certbot.timer

● certbot.timer - Run certbot twice daily
     Loaded: loaded (/lib/systemd/system/certbot.timer; enabled; ...)
     Active: active (waiting) since ...
    Trigger: ... (次回の実行予定日時)
   Triggers: ● certbot.service

# タイマーが有効になっているか確認
$ systemctl is-enabled certbot.timer
enabled   ← enabled であればOK

# タイマーの設定内容確認
$ cat /lib/systemd/system/certbot.timer
[Timer]
OnCalendar=*-*-* 00,12:00:00    ← 0時と12時に実行
RandomizedDelaySec=43200         ← 最大12時間のランダム遅延
Persistent=true

certbot.timer が enabled なら自動更新は完了している
systemctl is-enabled certbot.timerenabled を返し、systemctl status certbot.timeractive (waiting) であれば、自動更新の設定は完了しています。追加の設定は不要です。

⑥ 更新のシミュレーションを実行する

--dry-run オプションを使うと、実際には証明書を発行・更新せずに更新プロセスをシミュレーションできます。自動更新が正しく動作するかを確認するために実行します。


$ sudo certbot renew --dry-run

Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/xxxx.tplinkdns.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - -
Account registered.
Simulating renewal of an existing certificate for xxxx.tplinkdns.com

- - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/xxxx.tplinkdns.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - -

「all simulated renewals succeeded」と表示されればOK
シミュレーション成功は、自動更新の設定が正しく機能していることを意味します。

⑦ (オプション)デプロイフックでNginxを確実にリロードする

Nginxプラグイン(--nginx)で取得した証明書は、更新時にCertbotが自動的にNginxをリロードします。しかし、万が一に備えてデプロイフック(証明書更新成功後に実行されるスクリプト)を設定しておくとより確実です。


# デプロイフックスクリプトを作成
$ sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

#!/bin/bash
# 証明書更新成功後にNginxをリロードする
systemctl reload nginx

# 実行権限を付与
$ sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

動作確認

ブラウザでHTTPS接続を確認する

ブラウザで https://xxxx.tplinkdns.com にアクセスし、アドレスバーに鍵マークが表示されることを確認します。鍵マークをクリックすると証明書の詳細が確認できます。

確認ポイント
・鍵マークが表示される(「この接続は安全です」と表示)
・証明書の発行者が「Let’s Encrypt」
・コモンネームが自分のDDNSドメイン(xxxx.tplinkdns.com)

openssl コマンドで証明書を確認する


# 外部からSSL証明書の詳細を確認する
$ openssl s_client -connect xxxx.tplinkdns.com:443 -servername xxxx.tplinkdns.com < /dev/null 2>/dev/null | openssl x509 -noout -text | grep -E "Issuer|Subject|Not Before|Not After"

Issuer: C=US, O=Let's Encrypt, CN=R11
Subject: CN=xxxx.tplinkdns.com
Not Before: May 30 XX:XX:XX 2026 GMT
Not After : Aug 28 XX:XX:XX 2026 GMT  ← 有効期限を確認

証明書の有効期限を定期確認する


# すべての証明書の状態と有効期限を一覧表示
$ sudo certbot certificates

# 有効期限の残り日数のみ確認
$ echo | openssl s_client -servername xxxx.tplinkdns.com -connect xxxx.tplinkdns.com:443 2>/dev/null | openssl x509 -noout -enddate
notAfter=Aug 28 XX:XX:XX 2026 GMT

# certbot renew のログを確認
$ sudo journalctl -u certbot.service --since "7 days ago"

トラブルシューティング

Q: Connection refused / Timeout でチャレンジが失敗する
A: Let’s Encryptのサーバーが http://xxxx.tplinkdns.com/.well-known/acme-challenge/ にアクセスできていません。
① HGWのポートマッピング(80番 → Deco)を確認
② DecoのNAT転送(80番 → サーバー:80)を確認
③ CMMANでポート80が開放されているか確認
④ Nginxが起動して80番でListenしているか確認(sudo ss -tlnp | grep :80

Q: too many certificates already issued for exact set of domains
A: 週5件のレートリミットに達しています。同じドメインで5件以上発行しようとするとこのエラーになります。1週間待つか、--dry-run でテストして本番実行を最小限にしてください。

Q: certbot.timer が inactive になっている
A: タイマーが停止しています。以下で再起動・有効化してください。
sudo systemctl enable --now certbot.timer

Q: DDNSドメインで証明書は取得できるか?
A: TP-Link DDNS(tplinkdns.com)を含む一般的なDDNSドメインは、Let’s Encryptでの証明書取得が可能です。Let’s EncryptはDNSの所有権ではなく「そのドメインへのHTTP到達性」を確認するため、DDNSドメインでも問題ありません。

まとめ

本記事では、Let’s Encrypt と Certbot を使って自宅サーバーのDDNSドメインに無料でSSL証明書を取得し、自動更新を設定する方法を解説しました。

  • Let’s Encrypt は無料・自動更新前提の証明書認証局。DDNSドメインでも利用可能
  • sudo apt install certbot python3-certbot-nginx でインストール
  • sudo certbot --nginx -d xxxx.tplinkdns.com --key-type ecdsa で証明書取得(ECDSA推奨)
  • 証明書は /etc/letsencrypt/live/xxxx.tplinkdns.com/ に配置される
  • Nginxの設定では fullchain.pemprivkey.pem を参照する
  • certbot.timer(systemd)が1日2回自動的に更新を試み、手動管理は不要
  • sudo certbot renew --dry-run で自動更新の動作をシミュレーション確認できる

証明書の取得が完了したら、次は「自宅サーバーをSSL化する!NginxリバースプロキシとLet’s Encrypt設定ガイド」でNginxのHTTPS設定・リバースプロキシ設定・セキュリティヘッダー設定を行いましょう。

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