博客 / 詳情

返回

粗心大意必釀大禍,記錄nginx配置文件的一次鬧劇

一次域名配置引發的 Nginx 配置問題:HTTPS 與 server_name 的踩坑記錄

在最近的項目維護中,我新增了一個域名 bugfix.wiki,計劃將其解析到現有的網站上,與之前使用的 bugshare.cn 一樣,通過 Nginx 實現完整的 HTTP/HTTPS 跳轉邏輯。

域名備案、DNS、SSL 證書均已配置完畢,本以為只需複製一份現有配置即可。結果上線後卻發現:bugfix.wiki 無法正常訪問,而 bugshare.cn 卻完全正常

問題的根源最終被定位在一個非常細微但關鍵的 Nginx 配置點上。這裏記錄整個過程,供日後參考,也供遇到相同問題的同學排查。


1. 預期目標

對兩個域名(bugshare.cnbugfix.wiki)都希望實現如下行為:

輸入 URL 預期跳轉
http://domain https://www.domain
http://www.domain https://www.domain
https://domain https://www.domain
https://www.domain 內容正常訪問

即:

  • 全站 HTTPS
  • 全站強制“帶 WWW”
  • 所有 HTTP 統一跳轉到 HTTPS

2. 初始配置(bugshare.cn)——正常工作

bugshare.cn 的配置如下,可以正常運行:

server {
    listen 80;
    listen [::]:80;
    server_name bugshare.cn www.bugshare.cn;
    return 301 https://www.bugshare.cn$request_uri;
}

server {
    listen 443 ssl;
    server_name bugshare.cn;

    ssl_certificate     /etc/nginx/conf.d/cert/bugshare.cn.pem;
    ssl_certificate_key /etc/nginx/conf.d/cert/bugshare.cn.key;

    if ($host = 'bugshare.cn') {
        return 301 https://www.bugshare.cn$request_uri;
    }

    location / {
        root /usr/local/nginx/html/dist;
        if ($uri = '/index.html') {
            add_header Cache-Control "no-cache, no-store, must-revalidate";
        }
        try_files $uri $uri/ /index.html;
    }
}

注意:該配置雖然也存在優化空間,但在實際場景中運行完全正常。


3. 為 bugfix.wiki 複製一份配置後 —— 訪問異常

為新域名複製後:

server {
    listen 80;
    listen [::]:80;
    server_name bugfix.wiki www.bugfix.wiki;
    return 301 https://www.bugfix.wiki$request_uri;
}

server {
    listen 443 ssl;
    server_name bugfix.wiki;   # ← 問題所在

    ssl_certificate     /etc/nginx/conf.d/cert/bugfix.wiki.pem;
    ssl_certificate_key /etc/nginx/conf.d/cert/bugfix.wiki.key;

    if ($host = 'bugfix.wiki') {
        return 301 https://www.bugfix.wiki$request_uri;
    }

    location / {
        root /usr/local/nginx/html/dist;
        if ($uri = '/index.html') {
            add_header Cache-Control "no-cache, no-store, must-revalidate";
        }
        try_files $uri $uri/ /index.html;
    }
}

訪問現象:

  • http://bugfix.wiki → 正常跳到 https://www.bugfix.wiki
  • https://bugfix.wiki → 正常跳到 https://www.bugfix.wiki
  • https://www.bugfix.wiki → 報錯「該網頁無法正常運作」

表面上跳轉邏輯沒問題,但最終 HTTPS 訪問失敗。


4. 問題定位:未將 www.bugfix.wiki 寫入 HTTPS server_name

導致報錯的關鍵配置問題:

server_name bugfix.wiki;

缺少了:

www.bugfix.wiki

為什麼這是致命錯誤?

Nginx 在處理 HTTPS 時,會根據 SNI(Server Name Indication) 判斷應該使用哪個 server 塊及對應的 SSL 證書。

當訪問 https://www.bugfix.wiki 時:

  • 瀏覽器會發送 TLS ClientHello,附帶 SNI:www.bugfix.wiki
  • Nginx 根據 server_name 匹配 server 塊
  • 此時配置中沒有匹配 www.bugfix.wiki 的 443 server
  • Nginx fallback 到默認的 443 server(通常是第一個匹配到的)
  • 返回了不匹配的 SSL 證書 → 瀏覽器報錯

現象表現為“網頁無法正常運作”,實際是 SSL 證書不匹配導致連接被拒絕。


5. 修復後的正確配置

server {
    listen 443 ssl;
    server_name bugfix.wiki www.bugfix.wiki;

    ssl_certificate     /etc/nginx/conf.d/cert/bugfix.wiki.pem;
    ssl_certificate_key /etc/nginx/conf.d/cert/bugfix.wiki.key;

    if ($host = 'bugfix.wiki') {
        return 301 https://www.bugfix.wiki$request_uri;
    }

    location / {
        root /usr/local/nginx/html/dist;
        if ($uri = '/index.html') {
            add_header Cache-Control "no-cache, no-store, must-revalidate";
        }
        try_files $uri $uri/ /index.html;
    }
}

重啓 Nginx:

nginx -s reload

問題即刻解決,所有訪問路徑完全正常。


6. 技術總結(關鍵要點)

✔ 1. server_name 必須覆蓋 HTTPS 下的所有訪問域名

尤其是:

  • 主域名(Apex domain)
  • 帶 www
  • 子域名(如有)

否則 SNI 匹配失敗,證書無法正確綁定。


✔ 2. Nginx 的域名匹配與“回源域名”無關

即使使用了 Cloudflare 等代理平台,只要請求最終到達 Nginx,SNI 匹配仍完全依賴 Nginx 的 server_name


✔ 3. HTTPS 的 server 塊一定比 HTTP 更嚴格

HTTP 沒有 SNI,匹配寬鬆得多;
HTTPS 要求精確匹配 server_name,否則證書直接錯亂。


✔ 4. 強烈建議使用統一跳轉邏輯的最佳實踐:

server_name bugfix.wiki www.bugfix.wiki;

避免遺漏。

甚至可以進一步做:

server_name .bugfix.wiki;

但需要根據實際情況決定。


7. 後記

整個問題看似隱蔽,其實本質是:

HTTPS server_name 少寫了一個域名,導致 SNI 匹配失敗。

屬於 Nginx 配置中非常常見但又不容易第一時間想到的坑。

像這種“複製配置”場景,非常容易疏忽,提醒自己與大家:

複製配置永遠不能無腦複製,尤其是 SSL 相關的 server 塊。檢查、檢查、再檢查。
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.