NextcloudをSnapで運用したときにLet's Encryptで証明書を発行するんだけど、DNS-01認証で証明書を発行して利用する方法

毎度、ググっても出てこない小ネタを取り扱っております。
本記事は個人的な見解であり、筆者の所属するいかなる団体にも関係ございません。

# 0. はじめに

まあ、アレですね。
誤自宅NextcloudをRaspberry Piで運用していますが、自己証明書じゃなくて、TLS証明書を使いたいよね。
なら、Let's Encryptだけど、誤自宅Nextcloudをインターネットから参照できるようにしていないので、Let's EncryptのHTTP-01認証はできないね。
なら、自分が持っているドメインをCloudflareで運用しているので、DNS-01認証で証明書を発行すればいいじゃない？
でも、SnapでインストールしたNextcloudは、読み込めるディレクトリが以下に制限されてるじゃない？

- /var/snap/nextcloud/current
- /var/snap/nextcloud/common
- /root/snap/nextcloud/45729
- /root/snap/nextcloud/common

でも、certbotが通常、証明書ファイルを保存するのは、以下のディレクトリですよね？

```
/etc/letsencrypt/live/ドメイン/
/etc/letsencrypt/archive/ドメイン/
```

なので、certbotを工夫して、TLS証明書をNextcloudのsnapで利用できるようにした話です。

## 概要

1. **Certbot と certbot-dns-cloudflare のインストール**
2. **Cloudflare API トークンの設定**
3. **Certbot を使用して証明書を取得**
4. **Nextcloud Snap に証明書を適用**
5. **自動更新の設定**

## 詳細な手順

### 1. Certbot と certbot-dns-cloudflare のインストール


#### 1.1 Certbot のインストール

```bash
sudo snap install --classic certbot
```

#### 1.2 Certbot にプラグインの信頼を設定

Certbot Snap にプラグインの使用を許可します。

```bash
sudo snap set certbot trust-plugin-with-root=ok
```

#### 1.3 `certbot-dns-cloudflare` プラグインのインストール

```bash
sudo snap install certbot-dns-cloudflare
```

#### 1.4 シンボリックリンクの作成（必要に応じて）

```bash
sudo ln -s /snap/bin/certbot /usr/bin/certbot
```


### 2. Cloudflare API トークンの設定

Certbot が Cloudflare の DNS を操作できるように、API トークンを設定します。

#### 2.1 Cloudflare ダッシュボードで API トークンを作成

1. **Cloudflare にログイン**
   Cloudflare アカウントにログインし、対象のゾーン（ドメイン）を選択します。

2. **API トークンの作成**
   - 右上のプロフィールアイコンをクリックし、「**My Profile**」に移動します。
   - 左側のメニューから「**API Tokens**」を選択します。
   - 「**Create Token**」をクリックします。
   - テンプレートから「**Edit zone DNS**」を選択するか、カスタムで以下の権限を設定します：
     - **Permissions**:
       - **Zone**: `DNS: Edit`
     - **Zone Resources**:
       - 対象のゾーン（ドメイン）を指定。
   - トークンを生成し、安全な場所にコピーします（後で使用します）。

#### 2.2 認証情報ファイルの作成

Certbot が Cloudflare API を使用できるように認証情報ファイルを作成します。

1. **認証情報ファイルの作成**

   Snap の Certbot は専用のディレクトリを使用します。以下のコマンドで認証情報ファイルを作成します。

   ```bash
   sudo mkdir -p /var/snap/certbot/common/etc/letsencrypt
   sudo nano /var/snap/certbot/common/etc/letsencrypt/cloudflare.ini
   ```

2. **認証情報ファイルの内容**

   ファイルに以下の内容を記述します。`<YOUR_CLOUDFLARE_API_TOKEN>` を実際の API トークンに置き換えてください。

   ```
   dns_cloudflare_api_token = <YOUR_CLOUDFLARE_API_TOKEN>
   ```

3. **ファイルの権限設定**

   セキュリティを確保するため、認証情報ファイルの権限を 600 に設定します。

   ```bash
   sudo chmod 600 /var/snap/certbot/common/etc/letsencrypt/cloudflare.ini
   ```

### 3. Certbot を使用して証明書を取得

DNS-01 認証を使用して証明書を取得します。

```bash
sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /var/snap/certbot/common/etc/letsencrypt/cloudflare.ini \
  -d ＜FQDNドメイン＞ \
  --preferred-challenges dns \
  --agree-tos \
  --no-eff-email \
  --email your-email@example.com
```

- `yourdomain.com` を実際のドメイン名に置き換えてください。
- `your-email@example.com` をあなたのメールアドレスに置き換えてください。

**注意**:
- ワイルドカード証明書（`*.yourdomain.com`）を取得する場合、DNS-01 チャレンジが必須です。

以下のように返ってくればOKです。

```
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Account registered.
Requesting a certificate for ＜FQDNドメイン＞
Waiting 10 seconds for DNS changes to propagate
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/＜FQDNドメイン＞/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/＜FQDNドメイン＞/privkey.pem
This certificate expires on 2025-04-01.
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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
```


### 4. Nextcloud Snap に証明書を適用

取得した証明書を Nextcloud Snap がアクセスできるディレクトリに配置し、設定を変更します。

#### 4.1 証明書用ディレクトリの作成

```bash
sudo mkdir -p /var/snap/nextcloud/common/certs/
```

#### 4.2 証明書と秘密鍵のコピー

```bash
sudo cp /etc/letsencrypt/live/＜FQDNドメイン＞/fullchain.pem /var/snap/nextcloud/common/certs/server.crt
sudo cp /etc/letsencrypt/live/＜FQDNドメイン＞/privkey.pem /var/snap/nextcloud/common/certs/server.key
sudo cp /etc/letsencrypt/live/＜FQDNドメイン＞/chain.pem /var/snap/nextcloud/common/certs/server.chain
```

**注意**:
- `＜FQDNドメイン＞` を実際のドメイン名に置き換えてください。

#### 4.3 ファイルの権限設定

```bash
sudo chmod 600 /var/snap/nextcloud/common/certs/server.key
sudo chmod 644 /var/snap/nextcloud/common/certs/server.crt
sudo chmod 644 /var/snap/nextcloud/common/certs/server.chain
```

#### 4.4 Nextcloud Snap にカスタム証明書を適用

以下のコマンドを実行して、カスタム証明書を有効化します。HSTS（HTTP Strict Transport Security）を有効にする場合は `-s` オプションを追加します。

```bash
sudo nextcloud.enable-https custom /var/snap/nextcloud/common/certs/server.crt /var/snap/nextcloud/common/certs/server.key /var/snap/nextcloud/common/certs/server.chain
```

**HSTS を有効にする場合**:

```bash
sudo nextcloud.enable-https custom -s /var/snap/nextcloud/common/certs/server.crt /var/snap/nextcloud/common/certs/server.key /var/snap/nextcloud/common/certs/server.chain
```

### 5. 自動更新の設定

Let's Encrypt の証明書は 90 日間有効です。Certbot の自動更新と Nextcloud Snap の再起動を自動化するために、以下の手順を実施します。

#### 5.1 更新フックスクリプトの作成

必要なディレクトリの作成

```bash
sudo mkdir -p /var/snap/certbot/common/renewal-hooks/deploy/
```

このコマンドにより、必要なディレクトリ階層が作成されます。

証明書が更新された後に新しい証明書を Nextcloud Snap に適用し、再起動するスクリプトを作成します。

```bash
sudo nano /var/snap/certbot/common/renewal-hooks/deploy/nextcloud-renew.sh
```

スクリプトに以下の内容を記述します。`yourdomain.com` を実際のドメイン名に置き換えてください。

```bash
#!/bin/bash

DOMAIN="＜FQDNドメイン＞"
SNAP_CERT_DIR="/var/snap/nextcloud/common/certs/"

# 証明書のコピー
cp /etc/letsencrypt/live/$DOMAIN/fullchain.pem $SNAP_CERT_DIR/server.crt
cp /etc/letsencrypt/live/$DOMAIN/privkey.pem $SNAP_CERT_DIR/server.key
cp /etc/letsencrypt/live/$DOMAIN/chain.pem $SNAP_CERT_DIR/server.chain

# Nextcloud Snap を再起動
sudo nextcloud.enable-https custom -s /var/snap/nextcloud/common/certs/server.crt /var/snap/nextcloud/common/certs/server.key /var/snap/nextcloud/common/certs/server.chain
snap restart nextcloud
```

#### 5.2 スクリプトに実行権限を付与

```bash
sudo chmod +x /var/snap/certbot/common/renewal-hooks/deploy/nextcloud-renew.sh
```

#### 5.3 Certbot の自動更新が有効か確認

Certbot Snap は通常、自動更新用の systemd タイマーを設定します。以下のコマンドで確認できます。

```bash
sudo systemctl list-timers | grep certbot
```

期待される出力例:

```
Thu 2025-01-02 01:10:00 JST 3h 17min -                                             - snap.certbot.renew.timer       snap.certbot.renew.service
```

#### 5.4 更新プロセスのテスト

手動で更新プロセスをテストして、スクリプトが正しく動作することを確認します。

```bash
sudo certbot renew --dry-run
```

**確認事項**:
- 証明書が更新される。
- スクリプトが実行され、Nextcloud Snap が再起動される。

### 6. 設定の確認

1. **ブラウザで Nextcloud にアクセス**

   `https://yourdomain.com` にアクセスし、ブラウザの証明書情報を確認します。証明書が Let's Encrypt によって発行されていること、有効期限が正しいことを確認してください。

2. **Nextcloud の動作確認**

   HTTPS 経由で正常にアクセスできるか、機能に問題がないか確認します。

### 7. トラブルシューティング

#### 7.1 証明書の適用に失敗する場合

- **ファイルパスの確認**:
  - 証明書ファイルが正しいディレクトリに配置されているか確認してください。
  - Nextcloud Snap が指定されたディレクトリにアクセスできるか確認してください。

- **ファイルの権限**:
  - 証明書ファイルの権限が適切に設定されているか確認してください。

- **Nextcloud のログを確認**:
  ```bash
  sudo snap logs nextcloud
  ```

#### 7.2 Certbot の更新が機能しない場合

- **スクリプトの確認**:
  - `/var/snap/certbot/common/renewal-hooks/deploy/nextcloud-renew.sh` スクリプトが正しく記述されているか確認してください。
  - スクリプトに実行権限が付与されているか確認してください。

- **Certbot タイマーの確認**:
  - Certbot のタイマーが有効になっているか確認してください。

#### 7.3 DNS-01 認証で問題が発生する場合

- **Cloudflare API トークンの権限**:
  - トークンが「Zone: DNS: Edit」権限を持っているか確認してください。

- **認証情報ファイルの内容**:
  - `/var/snap/certbot/common/etc/letsencrypt/cloudflare.ini` ファイルの内容が正しいか確認してください。

- **DNS レコードの更新状況**:
  - Certbot が DNS レコードを正しく更新できているか確認してください。Cloudflare ダッシュボードで TXT レコードが追加されているか確認します。

### 8. セキュリティ考慮事項

- **認証情報ファイルの保護**:
  - Cloudflare API トークンを含む認証情報ファイルは機密情報です。適切に保護されていることを確認してください。
  ```bash
  sudo chmod 600 /var/snap/certbot/common/etc/letsencrypt/cloudflare.ini
  ```

- **証明書ファイルの保護**:
  - Nextcloud Snap の証明書ディレクトリへのアクセスを制限します。
  ```bash
  sudo chmod 700 /var/snap/nextcloud/common/certs/
  ```

- **バックアップ**:
  - 証明書や設定ファイルのバックアップを定期的に行ってください。

### 9. まとめ

以上の手順に従うことで、Snap 経由でインストールした Certbot と `certbot-dns-cloudflare` プラグインを使用して、Nextcloud Snap に Let's Encrypt の TLS 証明書を導入し、安全な HTTPS 通信を確保することができます。自動更新の設定により、証明書の有効期限切れを心配する必要もなくなります。