Custom Certificate 無法透過 UI 編輯,需用 Python 直接改 SQLite Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
144 lines
4.0 KiB
Markdown
144 lines
4.0 KiB
Markdown
# SSL 憑證部署 SOP - tpesupporter.tpech.gov.tw
|
||
|
||
## 概述
|
||
|
||
hospital_web (106.105.181.70) 使用 Nginx Proxy Manager 管理 SSL。
|
||
憑證檔案存放於本機 `ssl_certs/` 目錄,部署目標為遠端 `/opt/php/data/custom_ssl/npm-1/`。
|
||
|
||
## 目錄結構
|
||
|
||
```
|
||
ssl_certs/
|
||
├── *.cer # 伺服器憑證(GCA 發給你的 zip 解開後的檔案)
|
||
├── GCA_G3_intermediate.pem # 中繼憑證(已下載好)
|
||
├── privkey.pem # 私鑰(申請憑證時產生,需自行放入)
|
||
└── fullchain.pem # 組合後的完整憑證鏈(SOP 步驟 3 產出)
|
||
```
|
||
|
||
---
|
||
|
||
## SOP 流程
|
||
|
||
### 步驟 1:取得憑證
|
||
|
||
從 GCA 收到的 zip 檔解壓後,將 `.cer` 放入 `ssl_certs/`:
|
||
|
||
```bash
|
||
cd ssl_certs/
|
||
unzip XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.zip
|
||
```
|
||
|
||
### 步驟 2:放入私鑰
|
||
|
||
將申請 GCA 憑證時產生的私鑰放入 `ssl_certs/privkey.pem`。
|
||
|
||
確認金鑰與憑證配對:
|
||
|
||
```bash
|
||
# 兩個 md5 必須一致
|
||
openssl rsa -in privkey.pem -modulus -noout | md5sum
|
||
openssl x509 -in *.cer -modulus -noout | md5sum
|
||
```
|
||
|
||
### 步驟 3:下載中繼憑證(如需更新)
|
||
|
||
中繼憑證已放在 `ssl_certs/GCA_G3_intermediate.pem`。
|
||
若需重新下載(URL 來自憑證 AIA 欄位):
|
||
|
||
```bash
|
||
curl -o IssuedToThisCA.p7b http://gca.nat.gov.tw/repository/Certs/IssuedToThisCA.p7b
|
||
openssl pkcs7 -in IssuedToThisCA.p7b -inform DER -print_certs -outform PEM -out GCA_G3_intermediate.pem
|
||
rm IssuedToThisCA.p7b
|
||
```
|
||
|
||
### 步驟 4:組合 fullchain.pem
|
||
|
||
```bash
|
||
# 憑證轉 PEM(DER 格式自動轉換,PEM 格式直接複製)
|
||
openssl x509 -in *.cer -inform DER -out server.pem 2>/dev/null \
|
||
|| cp *.cer server.pem
|
||
|
||
# 合併:伺服器憑證 → 中繼憑證
|
||
cat server.pem GCA_G3_intermediate.pem > fullchain.pem
|
||
rm server.pem
|
||
```
|
||
|
||
### 步驟 5:備份遠端舊憑證
|
||
|
||
```bash
|
||
ssh hospital_web "sudo cp -r /opt/php/data/custom_ssl/npm-1 /opt/php/data/custom_ssl/npm-1.bak.\$(date +%Y%m%d)"
|
||
```
|
||
|
||
### 步驟 6:上傳並替換
|
||
|
||
```bash
|
||
scp fullchain.pem hospital_web:/tmp/
|
||
scp privkey.pem hospital_web:/tmp/
|
||
|
||
ssh hospital_web "
|
||
sudo cp /tmp/fullchain.pem /opt/php/data/custom_ssl/npm-1/fullchain.pem
|
||
sudo cp /tmp/privkey.pem /opt/php/data/custom_ssl/npm-1/privkey.pem
|
||
rm /tmp/fullchain.pem /tmp/privkey.pem
|
||
"
|
||
```
|
||
|
||
### 步驟 7:重啟 NPM
|
||
|
||
```bash
|
||
ssh hospital_web "cd /opt/php && sudo docker compose restart app"
|
||
```
|
||
|
||
### 步驟 8:驗證
|
||
|
||
```bash
|
||
ssh hospital_web "echo | openssl s_client -connect localhost:443 \
|
||
-servername tpesupporter.tpech.gov.tw 2>/dev/null \
|
||
| openssl x509 -noout -dates -subject -issuer"
|
||
```
|
||
|
||
預期結果:
|
||
- `issuer` → 政府憑證管理中心 - G3
|
||
- `notAfter` → 新憑證到期日
|
||
|
||
檢查憑證鏈是否完整:
|
||
|
||
```bash
|
||
ssh hospital_web "echo | openssl s_client -connect localhost:443 \
|
||
-servername tpesupporter.tpech.gov.tw 2>&1 \
|
||
| grep 'Verify return code'"
|
||
```
|
||
|
||
> 注意:GCA 憑證的根 CA(GRCA G3)不在 Linux 預設信任庫,
|
||
> 伺服器端會顯示 `Verify return code: 20`,這是正常的。
|
||
> 瀏覽器端通常可正常驗證。
|
||
|
||
### 步驟 9:更新 NPM 資料庫顯示
|
||
|
||
直接替換檔案部署時,NPM 後台顯示的到期日不會自動更新(Custom Certificate 無法透過 UI 編輯)。
|
||
需手動更新資料庫:
|
||
|
||
```bash
|
||
ssh hospital_web 'sudo docker exec nginxproxymanager /opt/certbot/bin/python3 -c "
|
||
import sqlite3, datetime
|
||
conn = sqlite3.connect(\"/data/database.sqlite\")
|
||
c = conn.cursor()
|
||
now = datetime.datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\")
|
||
# 將到期日改為新憑證的到期日
|
||
c.execute(\"UPDATE certificate SET expires_on=?, modified_on=? WHERE id=1\", (\"2028-04-01 00:54:36\", now))
|
||
conn.commit()
|
||
print(\"Updated. Rows:\", c.rowcount)
|
||
conn.close()
|
||
"'
|
||
```
|
||
|
||
更新後重新整理 NPM 後台頁面即可看到正確的到期日。
|
||
|
||
---
|
||
|
||
## 憑證歷史紀錄
|
||
|
||
| 期間 | 簽發者 | 到期日 | 備註 |
|
||
|---|---|---|---|
|
||
| 2025-04 ~ 2026-04 | HiPKI OV TLS CA - G1(中華電信) | 2026-04-23 | 已替換 |
|
||
| 2026-04 ~ 2028-04 | 政府憑證管理中心 - G3(GCA) | 2028-04-01 | 2026-04-09 部署完成 |
|