2026年11月12日
2026年11月12日
Nginx GeoIP2 依國家限制存取|ngx_http_geoip2_module、GeoLite2 更新與 WordPress 後台國別限制
本文是日文原文的在地化版本。 閱讀日文原文
要在 Nginx 依國家限制存取,做法是使用 GeoIP2 模組(ngx_http_geoip2_module)搭配 MaxMind 的 GeoLite2 資料庫,用 geoip2 區塊把國家代碼放進變數,再以 map 決定允許或拒絕,這是 2026 年 11 月目前的做法。舊文章裡「用 wget 下載 GeoLite 的 .dat」的步驟,因為資料已停止發布,現在行不通了。
先整理結論。
- 舊的
ngx_http_geoip_module(GeoIP Legacy)因 MaxMind 已停止發布舊格式資料,新環境無法再使用。請改用 GeoIP2(.mmdb格式)。 - GeoLite2 雖然免費,但需要註冊 MaxMind 帳號並取得授權金鑰(License Key),下載與更新用
geoipupdate進行。 - Nginx 端用
geoip2區塊建立$geoip2_country_code這類變數,用map決定相當於allow/deny的 0 / 1,再在location中return 403。 - 有經過 Cloudflare 等 CDN 的網站,必須先用
real_ip_header還原訪客的真實 IP,否則所有請求都會被判定為 CDN 所在的國家。 - 依國家限制只是「減少攻擊的輔助手段」,可以用 VPN 或中繼繞過。與其套用在整個公開頁面,不如只用在登入頁與後台,比較實際。
舊 geoip 與 GeoIP2 的差異
| 項目 | ngx_http_geoip_module(舊) | ngx_http_geoip2_module(GeoIP2) |
|---|---|---|
| 資料格式 | GeoIP Legacy(.dat) |
GeoIP2(.mmdb) |
| 免費資料的提供 | 已結束(2019 年停止發布) | GeoLite2(需要註冊帳號與授權金鑰) |
| 所需函式庫 | libGeoIP | libmaxminddb |
| 模組的取得方式 | Nginx 內建(--with-http_geoip_module) |
第三方模組 leev/ngx_http_geoip2_module。Debian / Ubuntu 有現成套件 |
| 變數 | $geoip_country_code 等固定名稱 |
在 geoip2 區塊中自行命名 |
如果現有設定還在使用 geoip_country,由於資料庫已停止更新,判定結果也已經過時。請趁這個機會改用 GeoIP2。
步驟 1:註冊 MaxMind 並建立授權金鑰
- 從 MaxMind 的 GeoLite2 頁面建立免費帳號。
- 登入後,在帳號管理畫面發行 License Key(金鑰只會在發行時顯示一次,請務必記下)。
- 要使用的資料庫,只需要國家的話選
GeoLite2-Country,需要城市層級則選GeoLite2-City。依國家限制的話,Country 就夠了。
使用條款(GeoLite2 End User License Agreement)中有關於資料轉散布與顯示的規定。如果只是在自家伺服器上做判定,通常不會有問題,但請在註冊時確認條款內容。
步驟 2:用 geoipupdate 取得並更新資料庫
GeoLite2 會定期更新,所以不要手動下載,而是使用 geoipupdate(geoipupdate 文件)。
# Debian / Ubuntu
sudo apt install geoipupdate
# RHEL 系(AlmaLinux / Rocky Linux)從 EPEL 安裝
sudo dnf install geoipupdate
在設定檔 /etc/GeoIP.conf 中寫入帳號 ID 與授權金鑰。
AccountID 123456
LicenseKey 這裡填入你發行的金鑰
EditionIDs GeoLite2-Country
# 儲存位置為發行版的預設值(Debian / Ubuntu 為 /var/lib/GeoIP,其他多為 /usr/share/GeoIP)。
# 要變更時請設定 DatabaseDirectory /var/lib/GeoIP
sudo geoipupdate -v
ls -l /var/lib/GeoIP/ # 看到 GeoLite2-Country.mmdb 就代表成功
套件版的 geoipupdate 已設定好透過 systemd timer 或 cron 定期執行(可用 systemctl list-timers | grep geoip 確認)。如果沒有,請新增大約每週一次的 cron。
步驟 3:在 Nginx 安裝 GeoIP2 模組
Debian / Ubuntu(apt 安裝的 Nginx)
sudo apt install libnginx-mod-http-geoip2
ls /etc/nginx/modules-enabled/ # 會放入 50-mod-http-geoip2.conf
nginx -t
nginx.org 的套件或從原始碼編譯的 Nginx
先安裝 libmaxminddb,再用與正在執行的 Nginx 相同版本的原始碼編譯動態模組。
sudo apt install libmaxminddb-dev # RHEL 系為 libmaxminddb-devel
cd /usr/local/src
git clone https://github.com/leev/ngx_http_geoip2_module
curl -LO https://nginx.org/download/nginx-1.26.3.tar.gz # 版本請配合 nginx -v
tar xzf nginx-1.26.3.tar.gz && cd nginx-1.26.3
./configure --with-compat --add-dynamic-module=../ngx_http_geoip2_module
make modules
sudo cp objs/ngx_http_geoip2_module.so /etc/nginx/modules/
在 nginx.conf 的開頭載入(套件版會自動放好)。
load_module modules/ngx_http_geoip2_module.so;
步驟 4:將國家代碼放入變數並決定允許或拒絕
寫在 http 區塊中。用 geoip2 區塊把國家代碼放進變數,再用 map 將允許的國家設為 1,其他設為 0。
http {
geoip2 /var/lib/GeoIP/GeoLite2-Country.mmdb {
auto_reload 60m;
$geoip2_country_code country iso_code;
}
# 允許進入後台的國家(ISO 3166-1 的 2 個字元代碼)
map $geoip2_country_code $admin_allowed {
default 0;
JP 1;
"" 1; # 無法判定(私有 IP 等)者允許。若要拒絕請改為 0
}
}
auto_reload 是在不重新啟動的情況下,重新讀取被 geoipupdate 替換掉的資料庫的間隔。
步驟 5:只限制 WordPress 的登入頁與後台
這個範例不限制公開頁面,只依國家限制 wp-login.php 與 /wp-admin/。寫在 server 區塊中。
server {
# ... 既有的設定 ...
location = /wp-login.php {
if ($admin_allowed = 0) { return 403; }
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location ^~ /wp-admin/ {
if ($admin_allowed = 0) { return 403; }
# 若外部外掛會使用 admin-ajax.php,請用另一個 location 放行
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
}
}
if 搭配 return 是 Nginx 可以安全處理的寫法。/wp-admin/admin-ajax.php 有時會被公開頁面的功能(表單或無限捲動等)在未登入狀態下呼叫,是否將它排除在限制之外,請依網站的功能決定。
套用與確認:
sudo nginx -t && sudo systemctl reload nginx
# 從自己所在的國家:會回傳 200 或 302
curl -sI https://example.com/wp-login.php | head -1
# 確認判定結果(在記錄中輸出國家代碼的範例)
# log_format geo '$remote_addr $geoip2_country_code "$request" $status';
想確認海外的連線結果,可以透過海外據點的 VPN,或國外的監控服務存取 wp-login.php,確認會得到 403。
有經過 CDN(Cloudflare 等)時
經過 CDN 時,$remote_addr 會變成 CDN 的 IP,所有人都會被判定為 CDN 所在的國家。請先用 ngx_http_realip_module 還原訪客的真實 IP(realip 模組)。
# Cloudflare 的範例。IP 清單請定期依 Cloudflare 官方的 IP Ranges 更新
set_real_ip_from 173.245.48.0/20;
# ... 列出 Cloudflare 的所有範圍 ...
real_ip_header CF-Connecting-IP;
geoip2 預設會參照 $remote_addr,所以會以 realip 替換後的真實 IP 來判定。Cloudflare 本身也有依國家控管存取的功能(WAF 自訂規則),因此如果你使用 Cloudflare,在 Cloudflare 端限制會比在 Nginx 上設定更簡單。也請參考在 WordPress 中設定 Cloudflare。
依國家限制的侷限
- GeoIP 的判定是依據 IP 位址登記資訊所做的推估,可以透過 VPN、代理伺服器、經由海外雲端的中繼來繞過。
- 在行動網路或企業網路中,可能會被判定為與實際所在地不同的國家。出國出差的管理員被擋在外面,也是營運上會遇到的問題。
- 因此,依國家限制應該作為減少登入暴力破解的輔助手段,與雙重驗證、登入次數限制、以 Basic 驗證保護 wp-admin搭配使用。
常見問題
Nginx 的 geoip 模組與 geoip2 模組有什麼不同?
舊的 geoip 模組讀取 GeoIP Legacy 格式(.dat)的資料,但 MaxMind 已停止發布這種格式。geoip2 模組(ngx_http_geoip2_module)讀取現行的 .mmdb 格式,可以使用 GeoLite2 的免費資料。新的設定請使用 geoip2。
GeoLite2 是免費的嗎?需要註冊嗎?
是免費的,但需要註冊 MaxMind 帳號並發行授權金鑰。下載與定期更新請用 geoipupdate。不使用金鑰、直接下載的舊做法已經行不通。
依國家限制就能防止 WordPress 的非法登入嗎?
有減少暴力破解嘗試的效果,但可以透過 VPN 或海外伺服器的中繼繞過,所以不能說能夠防止。請與登入次數限制、雙重驗證、Basic 驗證等搭配使用。
使用 Cloudflare 時,所有人都被判定為同一個國家
這是因為經過 CDN 時,連線來源會變成 CDN 的 IP。請先用 set_real_ip_from 與 real_ip_header CF-Connecting-IP 還原真實 IP,再進行判定。也可以用 Cloudflare 的 WAF 依國家限制。
使用 GeoLite2-City 可以限制到城市層級嗎?
城市與地區的代碼也可以放進變數,但城市層級的精確度比國家低,誤判時很容易把正當的使用者擋在外面。用於存取控制時,建議只做到國家層級比較保險。
總結
- 目前 Nginx 的國別限制使用 GeoIP2(ngx_http_geoip2_module + GeoLite2
.mmdb)進行,資料以geoipupdate更新。 - 用
geoip2把國家代碼放進變數,以map決定允許或拒絕,在wp-login.php與/wp-admin/的location中return 403。 - 經過 CDN 時要先還原真實 IP,國別限制只作為與雙重驗證等搭配的輔助措施。
相關文章
- 限制對 WordPress REST API 存取的方法
- 用 htpasswd 建立 Apache Basic 驗證密碼的方法|保護 wp-admin
- WordPress 設定 Cloudflare 完整指南
參考資料:ngx_http_geoip2_module(GitHub)、MaxMind GeoLite2 Free Geolocation Data、MaxMind – Updating Databases(geoipupdate)、Nginx ngx_http_realip_module
更新紀錄:2026-11-09 全面改版(將已停止發布的舊 GeoLite 步驟改為 GeoIP2 與 geoipupdate 的步驟,並新增 WordPress 後台的限制範例與 CDN 的注意事項)。本文由 WordPress Hakase(ライトセンド株式会社)營運。
對 WordPress 有疑問嗎?本站營運方位於日本,僅以日文回覆。 聯絡我們(日文)