
網站平常是用網域(例如 www.example.com)開啟的,但網域背後其實對應到一台主機的 IP 位址。如果在瀏覽器直接輸入這個 IP,有時候也能看到你的網站。
這篇說明為什麼要擋掉這種連線,以及 Apache(.htaccess)與 Nginx 的設定方法。
為什麼要擋掉 IP 直接連線?
- 避免重複內容:同一個網站用網域、用 IP 都能開啟,搜尋引擎有機會把 IP 版本也收錄進去,變成兩個重複的網站。
- 避免憑證警告:SSL 憑證是發給網域的,用
https://加 IP 連線一定會出現「不安全」的警告。 - 減少掃描流量:很多自動掃描程式是直接一個一個 IP 掃過去,而不是用網域連線。擋掉之後可以少掉不少無意義的請求。
- 網站前面有 Cloudflare 等 CDN 時:有人直接用主機 IP 連線,就等於繞過了 CDN 的防火牆與快取。
先確認:你的主機需要處理嗎?
- 共用虛擬主機:一個 IP 上通常放了很多網站,直接輸入 IP 看到的是主機商的預設頁面,不是你的網站。這種情況不需要處理,連線根本不會進到你的網站資料夾,
.htaccess也不會被執行。 - VPS、雲端主機、獨立主機:一個 IP 只有你的網站時,直接輸入 IP 很可能就會開到你的網站,這時才需要處理。虛擬主機如果有另外購買獨立 IP,情況也一樣。
最簡單的確認方法:在瀏覽器輸入 http://你的主機IP/,看看開出來的是什麼。主機 IP 可以在主機控制台查到。
方法一:用 .htaccess 把 IP 連線轉回網域
適用 Apache、LiteSpeed 主機。放在網站根目錄 .htaccess 的最上面(WordPress 的 # BEGIN WordPress 上面),把 www.example.com 換成你的網域:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^[0-9.]+(:[0-9]+)?$ [OR]
RewriteCond %{HTTP_HOST} ^\[
RewriteRule ^ https://www.example.com%{REQUEST_URI} [L,R=301]- 第一個條件:連線用的是 IPv4 位址(例如
203.0.113.10,後面加了連接埠也算)。 - 第二個條件:連線用的是 IPv6 位址(IPv6 在網址裡會用中括號包起來)。
- 符合其中一個,就用 301 轉到正式網域。
%{REQUEST_URI} 會帶上完整的路徑,網址參數也會保留,所以 http://203.0.113.10/about/ 會轉到 https://www.example.com/about/。
想直接拒絕,而不是轉址
不想讓 IP 連線看到任何東西,可以直接回應 403 禁止存取:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^[0-9.]+(:[0-9]+)?$ [OR]
RewriteCond %{HTTP_HOST} ^\[
RewriteRule ^ - [F]舊寫法的問題
這篇文章舊版的寫法是:
RewriteEngine on
RewriteCond %{HTTP_HOST} !^www.example.com
RewriteRule (.*) https://www.example.com$1 [R=301,L]意思是「只要網址不是 www.example.com,就轉到 www.example.com」,概念沒錯,但有兩個問題:
- 少了斜線:放在
.htaccess裡時,(.*)抓到的路徑開頭沒有斜線,/about/會被轉成https://www.example.comabout/這種錯誤網址。要寫成https://www.example.com/$1,或改用%{REQUEST_URI}。 - 沒有處理 https:網址已經是
www.example.com時不會轉,所以 http 的連線還是停在 http。
如果你的目的就是「不管用什麼網址連進來,一律統一成同一個網址」,可以用這個修正後的版本,同時處理 IP、沒有 www 的網址與 https:
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteRule ^ https://www.example.com%{REQUEST_URI} [L,R=301]要注意,同一個資料夾如果還有其他網域或測試用的子網域指過來,也會全部被轉走。網站前面有 Cloudflare 等 CDN 時,判斷 https 的方式不同,請看.htaccess 強制 HTTPS 寫法。
已經用了自動抓網域的寫法?
.htaccess 用法大全裡「統一網址」的寫法會自動抓網域名稱,不用改成自己的網址,但遇到 IP 連線時,會轉到 https://www.203.0.113.10/ 或 https://203.0.113.10/ 這類不存在、或會出現憑證警告的網址。
解決方法是把本篇方法一的 IP 規則放在它的前面。IP 連線會先被轉走(或拒絕),就不會跑到後面的規則。
方法二:Apache 設定預設虛擬主機(VPS)
有權限修改 Apache 設定檔的話,比較乾淨的做法是設一個「預設虛擬主機」,專門接收網域對不上的連線。
Apache 收到的網址如果沒有對應到任何網站的 ServerName 或 ServerAlias,會交給第一個載入的虛擬主機處理,所以這段設定要排在所有網站的前面(Ubuntu、Debian 上可以放在檔名排序最前面的 000-default.conf):
<VirtualHost *:80>
ServerName default.invalid
<Location "/">
Require all denied
</Location>
</VirtualHost>修改後先檢查語法,再重新載入 Apache:
sudo apachectl configtest
sudo systemctl reload apache2CentOS、Rocky Linux 等系統的服務名稱是 httpd。HTTPS(443 埠)的預設虛擬主機也需要一張憑證才能設定,比較複雜,不熟悉的話請主機商或系統管理員協助。
方法三:Nginx 主機
Nginx 不讀 .htaccess。在 Nginx 設定裡加一個 default_server,網域對不上的連線一律直接關閉:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}444 是 Nginx 專用的代碼,意思是不回應任何內容、直接關閉連線。
HTTPS 的部分,較新版本的 Nginx 可以用 ssl_reject_handshake 在加密連線建立時就直接拒絕,不需要另外準備憑證:
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name _;
ssl_reject_handshake on;
}同一個連接埠只能有一個 default_server。如果其他設定檔(例如系統內建的 default)已經有 default_server,要先拿掉,不然會出現重複的錯誤。修改後先執行 sudo nginx -t 檢查語法,再執行 sudo systemctl reload nginx。
設好之後怎麼測試?
- 瀏覽器輸入
http://你的主機IP/:應該轉到正式網域,或出現禁止存取、無法連線。 - 正式網域要照常能開,網站裡的頁面也多點幾頁確認。
- 有終端機的話,可以用 curl 看主機的回應:
curl -I http://203.0.113.10/設定成轉址的話,會看到 301 以及 Location: https://www.example.com/。
延伸閱讀
- .htaccess 用法大全:轉址、HTTPS、安全防護、壓縮與快取常用設定(WordPress 適用)
- .htaccess 強制 HTTPS 寫法:http 自動轉 https(WordPress、Joomla 適用)
- 網頁轉址與自動重新整理語法整理:301 轉址、meta refresh、JavaScript(WordPress 適用)
主機設定改錯一行,整個網站就可能打不開,動手前一定要先備份。正威網路行銷是 25 年經驗的基隆網頁設計工作室,也提供網站維護託管,主機與網址設定的問題歡迎來聊聊。







發表留言
還沒有人留言,歡迎第一個分享你的想法或問題。留言經審核後才會顯示,Email 不會公開。