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 或中繼繞過。與其套用在整個公開頁面,不如只用在登入頁與後台,比較實際。
Nginx GeoIP2 設定流程:註冊 MaxMind、用 geoipupdate 取得資料庫、載入模組、以 geoip2 與 map 判定、在 location 中限制

舊 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 並建立授權金鑰

  1. 從 MaxMind 的 GeoLite2 頁面建立免費帳號。
  2. 登入後,在帳號管理畫面發行 License Key(金鑰只會在發行時顯示一次,請務必記下)。
  3. 要使用的資料庫,只需要國家的話選 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,國別限制只作為與雙重驗證等搭配的輔助措施。

相關文章

參考資料: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 有疑問嗎?本站營運方位於日本,僅以日文回覆。 聯絡我們(日文)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲