文章目錄
- 說明
- 示例(公網上的公開web)
- 安裝SSL證書
- Certbot 的 Webroot 模式 和 Standalone 模式的區別
- **Webroot 模式**
- **Standalone 模式**
- 技術對比表
- Node.js 場景下的最佳實踐
- 推薦方案:**Webroot 模式**
- Standalone 模式應急使用:
- 為什么 Standalone 不需要路徑?深層解釋
- 實際應用建議
- 修改web應用的代碼
- 啟動web應用
- 示例(內網中的web)
- 建立證書配置文件。
- SSL/TLS證書配置文件
- **1. 基礎字段模塊 `[req]`**
- **2. 專有名稱模塊 `[dn]` 或 `[req_dn]`**
- **字段說明**
- **3. X.509擴展模塊**
- **(1) 基本擴展 `[v3_ca]`**
- **(2) 服務器證書擴展 `[v3_req]`**
- **(3) 客戶端證書擴展 `[v3_client]`**
- **4. 擴展字段詳解**
- **(1) `keyUsage`(密鑰用途)**
- **(2) `extendedKeyUsage`(擴展密鑰用途)**
- **(3) `subjectAltName`(主題備用名稱)**
- **(4) `basicConstraints`(基本約束)**
- **5. 高級擴展**
- **(1) CRL與OCSP配置**
- **(2) 證書策略(Certificate Policies)**
- **(3) 增強密鑰用法(自定義OID)**
- **6. 完整配置文件示例**
- **7. 注意事項**
- 生成證書。
- 客戶端安裝證書
- 無證書配置文件,直接生成證書
說明
日期:2025年5月30日
與以純文本形式發送和接收消息的標準 HTTP 不同,HTTPS 使用SSL/TLS等協議對服務器進行身份驗證、加密通信內容和檢測篡改。 這樣可以防止欺騙、中間人攻擊和竊聽等攻擊。
SSL/TLS證書(以下簡稱證書)很重要,如果用戶主動信任了偽造證書,那https的優勢就蕩然無存了,所以不要自己添加證書。
示例(公網上的公開web)
日期:2025年5月30日。
操作系統:Alibaba Cloud Linux 3.2104 LTS 64位。
應用:
- node.js v22.15.1
- npm v11.4.1
- Certbot
安裝SSL證書
公開的證書必須使用固定域名或固定公網ip。
示例中使用域名fxxkrock.top
。
修改時區,有的linux時區不是中國,SSL證書含有證書起止時間,所以申請SLL證書后修改時間可能導致證書失效。
sudo timedatectl set-timezone Asia/Shanghai
添加 EPEL 倉庫(Certbot 依賴)
sudo yum install -y epel-release
報錯
[ecs-user@iZbp18zmckjuyndr4e25koZ server_crystalsearch]$ sudo yum install -y epel-release
Last metadata expiration check: 15:18:43 ago on Thu 29 May 2025 08:17:50 PM CST.
Error:Problem: problem with installed package epel-aliyuncs-release-8-15.1.al8.noarch- package epel-aliyuncs-release-8-15.1.al8.noarch from @System conflicts with epel-release provided by epel-release-8-22.el8.noarch from epel- package epel-aliyuncs-release-8-15.1.al8.noarch from alinux3-updates conflicts with epel-release provided by epel-release-8-22.el8.noarch from epel- conflicting requests
(try to add '--allowerasing' to command line to replace conflicting packages or '--skip-broken' to skip uninstallable packages or '--nobest' to use not only best candidate packages)
這個錯誤是因為系統中已經存在名為 epel-aliyuncs-release
的包,與標準的 epel-release
包沖突。
從包的名稱來看,是阿里云自己兼容的epel,所以直接進行下一步。
安裝certbot。
[ecs-user@iZbp18zmckjuyndr4e25koZ server_crystalsearch]$ sudo yum install -y certbot
使用 Standalone 模式(需臨時停止占用 80/443 端口的服務),獲取SSL證書。
[ecs-user@iZbp18zmckjuyndr4e25koZ ~]$ sudo certbot certonly --standalone -d fxxkrock.top
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices)(Enter 'c' to cancel): 18015262576@189.cn- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.5-February-24-2025.pdf. You must
agree in order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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: n
Account registered.
Requesting a certificate for fxxkrock.topCertbot failed to authenticate some domains (authenticator: standalone). The Certificate Authority reported these problems:Domain: fxxkrock.topType: connectionDetail: 47.97.27.78: Fetching http://fxxkrock.top/.well-known/acme-challenge/DqitmUHBr-4eEkBcNWoEZWzAf10C8Gwpm5ipvFxoY1U: Timeout during connect (likely firewall problem)Hint: The Certificate Authority failed to download the challenge files from the temporary standalone webserver started by Certbot on port 80. Ensure that the listed domains point to this machine and that it can accept inbound connections from the internet.Some challenges have failed.
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.
報錯了。從提示看,也就是網不通,要從80端口訪問。
Certbot 的 Webroot 模式 和 Standalone 模式的區別
Webroot 模式
工作原理:
- 在您的網站根目錄創建臨時驗證文件(
/.well-known/acme-challenge/
)- Let’s Encrypt 服務器通過 HTTP 訪問這些文件驗證域名所有權
- 需要指定網站根目錄路徑(如
-w /var/www/your-site
)為什么需要路徑:
- Certbot 需要將驗證文件寫入指定目錄
- Web 服務器(Nginx/Apache/Node.js)必須能通過 HTTP 80 端口訪問這些文件
- 例如:
http://your-domain.com/.well-known/acme-challenge/xxxxx
優勢:
- 無需停止正在運行的 Web 服務
- 適合生產環境(服務持續可用)
- 可與現有 Web 服務器配合使用
適用場景:
- 已有 Web 服務器運行中
- 無法臨時停止服務
- 可訪問網站根目錄
Standalone 模式
工作原理:
- Certbot 自己啟動臨時 Web 服務器(監聽 80/443 端口)
- 直接響應 Let’s Encrypt 的驗證請求
- 無需指定路徑
為什么不需要路徑:
- Certbot 完全自己處理驗證請求
- 不依賴現有 Web 服務器或文件系統
- 驗證過程在內存中完成,不寫入文件
優勢:
- 簡單快速,無需配置 Web 服務器
- 不依賴現有網站目錄結構
- 適合無 Web 服務器的環境
代價:
- 需臨時停止占用 80/443 端口的服務
- 獲取證書期間服務短暫中斷
- 不適合 7x24 小時運行的關鍵服務
技術對比表
特性 Webroot 模式 Standalone 模式 需要路徑 ? (必須指定網站根目錄) ? (完全自包含) 需停止服務 ? ? (釋放80/443端口) 驗證方式 通過現有Web服務器訪問文件 自建臨時Web服務器響應請求 適合場景 生產環境/服務不可中斷 測試環境/簡單快速獲取證書 依賴Web服務器 ? (需配置訪問.well-known目錄) ? 證書續期影響 零中斷 短暫中斷(約10-30秒)
Node.js 場景下的最佳實踐
推薦方案:Webroot 模式
# 1. 創建驗證目錄 sudo mkdir -p /var/www/ssl_validation/.well-known/acme-challenge# 2. 在Node.js中添加路由處理驗證 const app = express(); app.get('/.well-known/acme-challenge/:token', (req, res) => {res.sendFile(`/var/www/ssl_validation/.well-known/acme-challenge/${req.params.token}`); });# 3. 獲取證書 sudo certbot certonly --webroot -w /var/www/ssl_validation -d your-domain.com
Standalone 模式應急使用:
# 1. 停止Node.js服務 sudo systemctl stop node-app# 2. 獲取證書(Standalone模式) sudo certbot certonly --standalone -d your-domain.com --preferred-challenges http# 3. 重啟服務 sudo systemctl start node-app
為什么 Standalone 不需要路徑?深層解釋
Standalone 模式的工作流程:
Certbot 啟動內置的微型 HTTP 服務器(Python實現)
監聽 80 端口(HTTP驗證)或 443 端口(TLS-ALPN驗證)
當 Let’s Encrypt 發送驗證請求時:
驗證通過后立即銷毀臨時服務器
全程不涉及文件系統操作,所有驗證內容在內存中動態生成
這種設計使得 Standalone 模式:
- 完全獨立于現有 Web 基礎設施
- 不需要配置任何文件路徑
- 但要求獨占端口(需臨時停止其他服務)
實際應用建議
對于 Node.js 項目,推薦組合方案:
首次獲取證書:使用 Standalone 模式(簡單快速)
sudo systemctl stop node-app sudo certbot certonly --standalone -d your-domain.com sudo systemctl start node-app
證書續期:改用 Webroot 模式(無中斷)
// 在Express中添加驗證路由 app.use('/.well-known/acme-challenge', express.static('/etc/letsencrypt/webrootauth'));
# 續期配置 sudo certbot renew --webroot -w /etc/letsencrypt/webrootauth
終極方案:用 Nginx 處理驗證(最佳實踐)
server {listen 80;server_name your-domain.com;location /.well-known/acme-challenge {root /var/www/certbot;}location / {return 301 https://$host$request_uri;} }
這樣 Node.js 只需專注 443 端口 HTTPS 服務,完全解耦證書管理。
從資料看,在過程中,80/443 端口都要使用。
安全設備進出都開啟80/443。
[ecs-user@iZbp18zmckjuyndr4e25koZ ~]$ sudo certbot certonly --standalone -d fxxkrock.top
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for fxxkrock.topSuccessfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/fxxkrock.top/fullchain.pem
Key is saved at: /etc/letsencrypt/live/fxxkrock.top/privkey.pem
This certificate expires on 2025-08-28.
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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
需要記錄其中 Certificate 和 Key 的保存位置,web應用需要加載這兩個文件。
修改web應用的代碼
// 添加https模塊
const https = require('https');// 讀取SSL證書文件
const credentials = {key: fs.readFileSync('/etc/letsencrypt/live/fxxkrock.top/privkey.pem'),cert: fs.readFileSync('/etc/letsencrypt/live/fxxkrock.top/fullchain.pem')
};
// 設置端口號
const port = 3080;// 創建HTTPS服務器
const server = https.createServer(credentials, app).listen(port, () => {console.log(`HTTPS server successfully launched: https://localhost:${port}`);
});
啟動web應用
權限不夠,無法讀取SSL證書
[ecs-user@iZbp18zmckjuyndr4e25koZ server_crystalsearch]$ node server.js
node:fs:562return binding.open(^Error: EACCES: permission denied, open '/etc/letsencrypt/live/fxxkrock.top/privkey.pem'at Object.openSync (node:fs:562:18)at Object.readFileSync (node:fs:446:35)at Object.<anonymous> (/home/ecs-user/server_crystalsearch/server.js:103:13)at Module._compile (node:internal/modules/cjs/loader:1730:14)at Object..js (node:internal/modules/cjs/loader:1895:10)at Module.load (node:internal/modules/cjs/loader:1465:32)at Function._load (node:internal/modules/cjs/loader:1282:12)at TracingChannel.traceSync (node:diagnostics_channel:322:14)at wrapModuleLoad (node:internal/modules/cjs/loader:235:24)at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:170:5) {errno: -13,code: 'EACCES',syscall: 'open',path: '/etc/letsencrypt/live/fxxkrock.top/privkey.pem'
}Node.js v22.15.1
復制這兩證書到網站目錄,并修改js代碼,把文件路徑改為新路徑。
[ecs-user@iZbp18zmckjuyndr4e25koZ server_crystalsearch]$ sudo cp /etc/letsencrypt/live/fxxkrock.top/privkey.pem /home/ec
s-user/server_crystalsearch/privkey.pem
[ecs-user@iZbp18zmckjuyndr4e25koZ server_crystalsearch]$ sudo cp /etc/letsencrypt/live/fxxkrock.top/fullchain.pem /home/
ecs-user/server_crystalsearch/fullchain.pem
啟動過程無報錯
[ecs-user@iZbp18zmckjuyndr4e25koZ server_crystalsearch]$ node server.js
Web folder: /home/ecs-user/server_crystalsearch/crystalsearch
HTTPS server successfully launched: https://localhost:3060
瀏覽器訪問http://fxxkrock.top:3060/
,瀏覽器顯示“響應時間過長”。
訪問https://fxxkrock.top:3060/
,瀏覽器顯示“響應時間過長”。
忘記在安全設備打開3060端口了。
打開后,https正常,控制臺無報錯。
訪問http會自動跳轉到https。
示例(內網中的web)
日期:2025年5月30日。
操作系統:ubuntu server v24.04.2 amd64。
ip:192.168.3.10。
在內網中自己生成證書,先要給服務器固定ip,因為整數中含有ip地址,生成要比后,需要在客戶端中導入書證。
建立證書配置文件。
新建文件ssl.conf
,輸入以下內容。
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
x509_extensions = v3_req[dn]
CN = 192.168.3.71[v3_req]
keyUsage = keyEncipherment, dataEncipherment, digitalSignature
extendedKeyUsage = serverAuth
subjectAltName = @alt_names[alt_names]
IP.1 = 192.168.3.10
SSL/TLS證書配置文件
在SSL/TLS證書配置文件(如OpenSSL的
.conf
文件)中,可以定義大量字段和擴展參數來精確控制證書的屬性和行為。以下是SSL配置文件的核心模塊及其詳細說明,涵蓋基本字段、X.509擴展和高級選項。
1. 基礎字段模塊
[req]
定義證書請求(CSR)的全局參數:
[req] default_bits = 2048 # 密鑰長度(2048/4096) default_md = sha256 # 哈希算法(sha256/sha384) prompt = no # 是否交互式輸入(no表示自動填充) distinguished_name = req_dn # 關聯的DN(專有名稱)配置塊 req_extensions = v3_req # 使用的擴展模塊 encrypt_key = no # 是否加密私鑰(no表示不加密)
2. 專有名稱模塊
[dn]
或[req_dn]
定義證書的**主題(Subject)**信息,通常用于標識實體:
[dn] countryName = CN # 國家代碼(2字母,如CN/US) stateOrProvinceName = Guangdong # 省份/州 localityName = Shenzhen # 城市 organizationName = My Company # 組織名稱 organizationalUnitName = IT Department # 部門名稱 commonName = 192.168.3.71 # 通用名(域名或IP) emailAddress = admin@example.com# 聯系郵箱(可選)
字段說明
字段名 用途 countryName
國家代碼(ISO 3166-1標準,如CN/US/JP) stateOrProvinceName
省份或州(需與注冊實體一致) localityName
城市或地區名稱 organizationName
組織全稱(如公司名) organizationalUnitName
部門名稱(如IT/Sales) commonName
證書主體標識(對服務器證書為域名或IP地址) emailAddress
管理員郵箱(通常用于客戶端證書或代碼簽名證書)
3. X.509擴展模塊
(1) 基本擴展
[v3_ca]
用于定義證書頒發機構(CA)證書的屬性:
[v3_ca] subjectKeyIdentifier = hash # 標識證書公鑰的哈希值 authorityKeyIdentifier= keyid:always,issuer:always # 關聯上級CA的公鑰標識 basicConstraints = CA:TRUE # 標記此證書為CA證書 keyUsage = critical, cRLSign, keyCertSign # 密鑰用途(僅CA)
(2) 服務器證書擴展
[v3_req]
用于普通服務器或終端實體證書:
[v3_req] subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer basicConstraints = CA:FALSE # 非CA證書 keyUsage = digitalSignature, keyEncipherment # 密鑰用途 extendedKeyUsage = serverAuth, clientAuth # 擴展用途(服務器/客戶端) subjectAltName = @alt_names # 主題備用名(SAN)
(3) 客戶端證書擴展
[v3_client]
用于客戶端身份驗證:
[v3_client] extendedKeyUsage = clientAuth # 限制證書僅用于客戶端認證
4. 擴展字段詳解
(1)
keyUsage
(密鑰用途)定義證書密鑰允許的操作,需標記為
critical
時表示強制遵守:keyUsage = digitalSignature, keyEncipherment, dataEncipherment
值 用途 digitalSignature
允許用于數字簽名(如TLS握手) keyEncipherment
允許加密傳輸的對稱密鑰(用于RSA密鑰交換) dataEncipherment
允許直接加密數據(極少使用) keyAgreement
允許密鑰協商(如ECDH密鑰交換) crlSign
允許簽發CRL(證書吊銷列表) keyCertSign
允許簽發下級證書(僅CA證書) (2)
extendedKeyUsage
(擴展密鑰用途)限制證書的具體應用場景:
extendedKeyUsage = serverAuth, codeSigning, emailProtection
值 用途 serverAuth
用于服務器身份驗證(HTTPS) clientAuth
用于客戶端身份驗證(雙向TLS) codeSigning
用于代碼簽名(如軟件發布) emailProtection
用于郵件加密或簽名(S/MIME) timeStamping
用于時間戳服務 (3)
subjectAltName
(主題備用名稱)定義證書支持的域名、IP或URI列表:
[alt_names] DNS.1 = example.com DNS.2 = *.example.com IP.1 = 192.168.3.71 email.1 = user@example.com URI.1 = http://example.com/resource
(4)
basicConstraints
(基本約束)控制證書是否可作為CA證書:
basicConstraints = critical, CA:TRUE, pathlen:0
CA:TRUE
:允許簽發下級證書。pathlen:0
:下級CA最多只能簽發終端實體證書(不能有孫級CA)。
5. 高級擴展
(1) CRL與OCSP配置
定義證書吊銷信息分發點:
crlDistributionPoints = URI:http://crl.example.com/root.crl authorityInfoAccess = caIssuers;URI:http://certs.example.com/ca.crt, OCSP;URI:http://ocsp.example.com
(2) 證書策略(Certificate Policies)
聲明證書的使用策略(通常用于EV證書):
certificatePolicies = 1.3.6.1.4.1.12345.1.2.3
(3) 增強密鑰用法(自定義OID)
支持自定義擴展:
1.3.6.1.4.1.311.20.2 = ASN1:UTF8String:Microsoft Individual Code Signing
6. 完整配置文件示例
[req] default_bits = 2048 default_md = sha256 prompt = no distinguished_name = req_dn req_extensions = v3_req[req_dn] countryName = CN stateOrProvinceName = Guangdong localityName = Shenzhen organizationName = My Corp commonName = 192.168.3.71[v3_req] basicConstraints = CA:FALSE keyUsage = digitalSignature, keyEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names[alt_names] IP.1 = 192.168.3.71 DNS.1 = internal-server
7. 注意事項
- 兼容性:舊版瀏覽器(如IE6)可能不支持SHA-256或SAN擴展。
- 安全性:優先使用
sha256
及以上算法,密鑰長度≥2048位。- 強制標記:若擴展字段標記為
critical
,客戶端必須理解該擴展否則拒絕證書。- 私有IP限制:公共CA不會為私有IP簽發證書,需自簽名或使用內部CA。
通過靈活組合這些字段和擴展,可以生成符合特定場景需求的安全證書。
生成證書。
zzs@testser:~$ zzs@testser:~$ openssl req -x509 -newkey rsa:2048 -nodes -keyout server.key -out server.crt -days 3650 -config ssl.conf -extensions v3_req
..+....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*..............+.+.....+......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*....+......+...............+..+.......+...+.....+...+.........+.+......+.....+...+.......+.....+.+............................................+...+......+.+......+.........+.....+...+.+...........+...+.+..+...+....+...+........+...................+.....+..........+.....+......+............+....+.....+.+..+.+.....+.........+.......+.....+.+...............+...+..+.........+.+...+...........+...+.+.........+.....+.+..+...+....+..................+...+.....+......+...+...+....+.....+......+.........+...............+...+.+.....+.+.........+.....+.......+.........+......+............+.....+...+....+.....+....+.....+....+..+.+..+...+....+...+.....+..................+...+....+..+.+...+......+...........+.........+...+.......+......+...+.....+.........+.+......+.....+...+.+.....+....+.....+..........+.....+.+.....+.+......+.....+..................+..........+..+.............+..+....+...+........+.......+......+......+...+.....+............+.+.....+..........+..+..........+..+....+.........+......+......+...+.....+...+.......+..................+..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.+.+..+...+.+..............+.+...+.....+......+.+......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*..+....+..+.........+.......+..+.+.....+....+...+.....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.+.+.....+.+.........+..+.......+...+........+.+...+...............+.....+............+......+...+............+...+.+.....+...+.+.....+.......+............+..+.+.....+..........+..............+..........+.....+..........+......+...+..+...+.......+.........+......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
zzs@testser:~$ dir
server.crt server.key ssl.conf
會多出兩個文件:
server.key
: 私鑰文件server.crt
: 證書文件
客戶端安裝證書
以windows為例,把server.crt
發送到客戶端→ 雙擊 server.crt
→ 選擇“安裝證書” → 存儲位置為“本地計算機” → 選擇“受信任的根證書頒發機構”。
無證書配置文件,直接生成證書
如果對證書內容無要求,可以不使用證書配置文件,直接在命令中指定ip,即可生成證書。
zzs@testser:~/aaa$ openssl req -x509 -newkey rsa:2048 -nodes -keyout server.key -out server.crt -days 3650 -subj "/CN=192.168.3.10" -addext "subjectAltName=IP:192.168.3.10"
..+...+....+..+...+.+.........+........+...............+....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*....+.+.....+.......+..+......+....+........+...+.........+...+....+.....+.........+....+......+......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...........+.....+...+.......+..+....+.....+.......+...+....................+....+......+..+.........+....+......+......+............+...+........+...............+.........+...+............+.+..............+..........+..+...............+.+.....+....+...+...+.....+...+....+........+.........+...+.......+...+..+....+..............+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
..+.....+......+......+.+.....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.........+...........+....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*..........+.+........+.......+...........+...+......+.+..+.......+...+.....+.+..+..........+..+.......+...+..+...............+.+...+.....+......+..........+...+..+................+...+...........+......+............+......+......+.+..+.............+..+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
zzs@testser:~/aaa$ dir
server.crt server.key