【常見問題】https 使用domain 與 ip 差異
好的,以下補上:
✅ 比較 https://a.b.com
與 https://168.23.1.1
的差異
這兩者協定一樣(都是 HTTPS),但主機名稱(Host)差異會影響 SSL 憑證驗證、DNS 解析、與 Nginx 的設定行為。
差異對照表
項目 | https://a.b.com |
https://168.23.1.1 |
---|---|---|
協定 | HTTPS(加密) | HTTPS(加密) |
主機名稱 | 網域名稱(FQDN) | IP 位址 |
DNS 解析 | 會經過 DNS 解析 → IP | 不經 DNS |
SSL 憑證驗證 | 通常需要憑證中的 CN/SAN 包含 a.b.com | 需要憑證中包含 IP 位址(不常見) |
Nginx server_name 配置 |
server_name a.b.com; |
server_name 168.23.1.1; (不建議)或 _ |
常見用法 | 公網、正式站、內部網域皆可 | 測試、開發、內網 IP 使用 |
風險與限制 | SSL 憑證驗證容易通過 | 一般憑證不支援 IP → 會出現 TLS 錯誤 |
信任憑證 | 可用 Let's Encrypt、商業憑證 | 除非特別申請 IP 憑證,否則會有警告 |
SSL 憑證驗證差異舉例
https://a.b.com
-
若你使用 Let's Encrypt 為
a.b.com
建立憑證:
✅curl https://a.b.com
➜ 成功(CN/SAN 包含a.b.com
)
https://168.23.1.1
-
若你拿
a.b.com
憑證套用到 IP 上:
❌curl https://168.23.1.1
➜ 失敗,出現SSL: certificate subject name does not match
解法(不建議用於正式環境):
-
為 IP 簽發 SSL 憑證(需自簽或企業憑證)
-
用
curl -k
忽略憑證錯誤
curl -k https://168.23.1.1 # 跳過憑證驗證(不安全)
✅ Nginx 設定差異
a.b.com
對應設定:
server {
listen 443 ssl;
server_name a.b.com;
ssl_certificate /etc/nginx/certs/a.b.com.crt;
ssl_certificate_key /etc/nginx/certs/a.b.com.key;
location / {
proxy_pass http://localhost:3000;
}
}
IP 直接連線時,通常會用:
server {
listen 443 ssl;
server_name _; # 匹配所有 hostname(或不設定)
ssl_certificate /etc/nginx/certs/selfsigned.crt;
ssl_certificate_key /etc/nginx/certs/selfsigned.key;
location / {
proxy_pass http://localhost:3000;
}
}
🧨 若直接用 IP,也許不會觸發
server_name
對應,取決於 Nginx 設定順序與 SNI。
✅ 小結
URL | 適用時機 | 憑證需求 | 風險 |
---|---|---|---|
https://a.b.com |
公網、正常使用 | CN/SAN 需含 a.b.com |
正常通過憑證驗證 |
https://168.23.1.1 |
內部測試或特例 | 憑證需含 IP 或自簽 | 容易驗證失敗、跳警告 |
✅Curl Domain 與 ip 的 差異
這是一個非常關鍵的細節問題,涉及到 HTTPS、Host Header、SNI(Server Name Indication),我們來完整拆解:
你提供的兩個請求:
curl https://a.b.com
curl https://168.23.1.1 -H 'Host: a.b.com'
看起來類似,實際上在底層行為非常不同:
核心差異一覽
項目 | curl https://a.b.com |
curl https://168.23.1.1 -H 'Host: a.b.com' |
---|---|---|
連線 IP | DNS 解析 a.b.com → IP |
直接指定 IP 168.23.1.1 |
TLS SNI 傳送內容 | a.b.com (🔑 用來選擇憑證) |
168.23.1.1 (🚨 TLS 層不包含 a.b.com ) |
Host Header(HTTP 層) | Host: a.b.com (由 curl 自動加) |
Host: a.b.com (你手動加) |
SSL 憑證是否驗證成功? | ✅ 通常會成功 | ❌ 若憑證是發給 a.b.com 則會 mismatch |
Nginx 是否能進到正確的 server | ✅ 通常會進到 server_name a.b.com |
❌ 取決於 SNI,可能進入 default server |
為何 TLS 憑證驗證會失敗?
SNI 是什麼?
-
TLS 層在握手階段會送出
Server Name
(來自curl
的--resolve
或 URL)。 -
用來讓伺服器知道要回哪一張憑證。
在兩種情況下比較:
✅ curl https://a.b.com
:
-
DNS → 168.23.1.1
-
SNI:
a.b.com
-
Host header:
a.b.com
-
Nginx 匹配成功,憑證也是給
a.b.com
,一切正常
❌ curl https://168.23.1.1 -H 'Host: a.b.com'
:
-
SNI:
168.23.1.1
(預設值,非 a.b.com) -
Host header:
a.b.com
(只有 HTTP 層有用) -
若 Nginx 用
server_name a.b.com
並綁定憑證,那會 因為 SNI 不符無法選中正確的憑證 → TLS 握手失敗
Nginx 對這兩種請求的反應
server {
listen 443 ssl;
server_name a.b.com;
ssl_certificate /etc/nginx/certs/a.b.com.crt;
ssl_certificate_key /etc/nginx/certs/a.b.com.key;
location / {
return 200 "hello a.b.com\n";
}
}
server {
listen 443 ssl default_server;
server_name _;
ssl_certificate /etc/nginx/certs/default.crt;
ssl_certificate_key /etc/nginx/certs/default.key;
location / {
return 200 "default server\n";
}
}
測試結果:
測試指令 | 伺服器 block 命中 | 回傳內容 | 是否 SSL 通過 |
---|---|---|---|
curl https://a.b.com |
server_name a.b.com |
hello a.b.com | ✅ 是 |
curl https://168.23.1.1 -H 'Host: a.b.com' |
server_name _ (default) |
default server | ⚠️ 通常憑證不符(或需 -k ) |
✅ 解法:讓 IP 請求也能通過 SSL
方法一:用自簽或專門支援 IP 的憑證
但大多數公開 CA(如 Let's Encrypt)不發給 IP 憑證。
方法二:用 curl 忽略 TLS 驗證
curl -k https://168.23.1.1 -H 'Host: a.b.com'
方法三:讓 curl 傳送正確的 SNI(推薦)
curl --resolve a.b.com:443:168.23.1.1 https://a.b.com
-
這會讓 curl:
-
SNI 傳
a.b.com
-
Host header 是
a.b.com
-
實際連到 IP
168.23.1.1
-
-
✅ 完整模擬瀏覽器行為
✅ 總結
比較項目 | curl https://a.b.com |
curl https://168.23.1.1 -H 'Host: a.b.com' |
---|---|---|
DNS 解析 | ✅ 有 | ❌ 無 |
TLS SNI | a.b.com |
168.23.1.1 |
Host Header | a.b.com |
a.b.com |
SSL 憑證驗證 | ✅ 通常成功 | ❌ 會失敗(除非用 -k ) |
建議用法 | ✅ 正常連線方式 | ⚠️ 用於測試或模擬 |
如果你需要模擬真實請求又繞過 DNS,可使用:
curl --resolve a.b.com:443:168.23.1.1 https://a.b.com
這是最穩定且最貼近瀏覽器 SNI 行為的方式。