2026年11月12日
2026年11月12日
Giới hạn truy cập theo quốc gia trong Nginx bằng GeoIP2 (GeoLite2)
Đây là phiên bản được bản địa hóa từ bài viết gốc tiếng Nhật. Đọc bài gốc tiếng Nhật
Để giới hạn truy cập theo quốc gia trong Nginx, cách làm hiện nay (tính đến tháng 11/2026) là dùng module GeoIP2 (ngx_http_geoip2_module) cùng cơ sở dữ liệu GeoLite2 của MaxMind, đưa mã quốc gia vào một biến bằng khối geoip2, rồi quyết định cho phép hay chặn bằng map. Cách trong các bài viết cũ là tải tệp .dat của GeoLite bằng wget hiện không còn chạy được vì dữ liệu đó đã ngừng phát hành.
Tóm tắt trước các điểm chính.
- Module cũ
ngx_http_geoip_module(GeoIP Legacy) không còn dùng được cho cấu hình mới vì MaxMind đã ngừng phát hành dữ liệu định dạng cũ. Hãy chuyển sang GeoIP2 (định dạng.mmdb). - GeoLite2 miễn phí nhưng cần đăng ký tài khoản MaxMind và có khóa cấp phép (license key); việc tải và cập nhật được thực hiện bằng
geoipupdate. - Phía Nginx, bạn tạo biến như
$geoip2_country_codebằng khốigeoip2, dùngmapđể đặt giá trị 0 / 1 tương ứng vớiallow/deny, rồireturn 403tronglocation. - Với site đi qua CDN như Cloudflare, nếu không khôi phục IP thật của người truy cập bằng
real_ip_headertrước, mọi truy cập sẽ bị xác định là thuộc quốc gia của CDN. - Giới hạn theo quốc gia chỉ là biện pháp hỗ trợ giảm tấn công, vì có thể bị vượt qua bằng VPN hoặc máy chủ trung gian. Cách thực tế là chỉ áp dụng cho trang đăng nhập và trang quản trị, không áp dụng cho toàn bộ trang công khai.
Khác biệt giữa geoip cũ và GeoIP2
| Hạng mục | ngx_http_geoip_module (cũ) | ngx_http_geoip2_module (GeoIP2) |
|---|---|---|
| Định dạng dữ liệu | GeoIP Legacy (.dat) |
GeoIP2 (.mmdb) |
| Dữ liệu miễn phí | Đã ngừng (ngừng phát hành từ năm 2019) | GeoLite2 (cần đăng ký tài khoản và có khóa cấp phép) |
| Thư viện cần thiết | libGeoIP | libmaxminddb |
| Cách có được module | Đi kèm Nginx (--with-http_geoip_module) |
Module bên thứ ba leev/ngx_http_geoip2_module. Debian / Ubuntu có sẵn gói |
| Biến | Cố định, như $geoip_country_code |
Tự đặt tên trong khối geoip2 |
Nếu cấu hình hiện tại đang dùng geoip_country, cơ sở dữ liệu đã không còn được cập nhật nên kết quả xác định đã cũ. Nhân dịp này hãy chuyển sang GeoIP2.
Bước 1: Đăng ký MaxMind và tạo khóa cấp phép
- Tạo tài khoản miễn phí từ trang GeoLite2 của MaxMind.
- Sau khi đăng nhập, hãy cấp License Key trong trang quản lý tài khoản (khóa chỉ hiển thị lúc cấp nên hãy ghi lại).
- Cơ sở dữ liệu cần dùng là
GeoLite2-Countrynếu chỉ cần quốc gia, hoặcGeoLite2-Citynếu cần đến cấp thành phố. Với giới hạn theo quốc gia thì Country là đủ.
Điều khoản sử dụng (GeoLite2 End User License Agreement) có quy định về việc phân phối lại và hiển thị dữ liệu. Nếu chỉ dùng để xác định trên máy chủ nội bộ thì thường nằm trong phạm vi cho phép, nhưng hãy xem lại điều khoản khi đăng ký.
Bước 2: Tải và cập nhật cơ sở dữ liệu bằng geoipupdate
GeoLite2 được cập nhật định kỳ, nên đừng tải thủ công mà hãy dùng geoipupdate (tài liệu geoipupdate).
# Debian / Ubuntu
sudo apt install geoipupdate
# Họ RHEL (AlmaLinux / Rocky Linux) lấy từ EPEL
sudo dnf install geoipupdate
Ghi ID tài khoản và khóa cấp phép vào tệp cấu hình /etc/GeoIP.conf.
AccountID 123456
LicenseKey khóa bạn đã cấp ở bước trên
EditionIDs GeoLite2-Country
# Nơi lưu là mặc định của bản phân phối (Debian / Ubuntu dùng /var/lib/GeoIP, các bản khác thường là /usr/share/GeoIP).
# Khi muốn đổi: DatabaseDirectory /var/lib/GeoIP
sudo geoipupdate -v
ls -l /var/lib/GeoIP/ # Có GeoLite2-Country.mmdb là thành công
Gói geoipupdate cài từ kho thường đã có sẵn thiết lập chạy định kỳ bằng timer của systemd hoặc cron (kiểm tra bằng systemctl list-timers | grep geoip). Nếu chưa có, hãy thêm một cron chạy khoảng mỗi tuần một lần.
Bước 3: Cài module GeoIP2 cho Nginx
Debian / Ubuntu (Nginx từ apt)
sudo apt install libnginx-mod-http-geoip2
ls /etc/nginx/modules-enabled/ # Tệp 50-mod-http-geoip2.conf sẽ được đặt vào đây
nginx -t
Nginx từ gói nginx.org hoặc tự biên dịch từ mã nguồn
Sau khi cài libmaxminddb, hãy biên dịch module động từ mã nguồn cùng phiên bản với Nginx đang chạy.
sudo apt install libmaxminddb-dev # Họ RHEL dùng 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 # Chọn phiên bản khớp với kết quả của 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/
Nạp module ở đầu nginx.conf (với gói cài từ kho, việc này được thực hiện tự động).
load_module modules/ngx_http_geoip2_module.so;
Bước 4: Đưa mã quốc gia vào biến và quyết định cho phép hay chặn
Viết trong khối http. Khối geoip2 đưa mã quốc gia vào biến, còn map đặt quốc gia được phép là 1 và các quốc gia còn lại là 0.
http {
geoip2 /var/lib/GeoIP/GeoLite2-Country.mmdb {
auto_reload 60m;
$geoip2_country_code country iso_code;
}
# Quốc gia được phép vào trang quản trị (mã 2 ký tự theo ISO 3166-1)
map $geoip2_country_code $admin_allowed {
default 0;
JP 1;
"" 1; # Không xác định được (IP riêng, v.v.) thì cho phép. Muốn chặn thì đặt 0
}
}
auto_reload là khoảng thời gian để Nginx đọc lại cơ sở dữ liệu mà geoipupdate đã thay thế mà không cần khởi động lại.
Bước 5: Chỉ giới hạn trang đăng nhập và trang quản trị của WordPress
Đây là ví dụ không giới hạn các trang công khai, chỉ lọc theo quốc gia với wp-login.php và /wp-admin/. Viết trong khối server.
server {
# ... cấu hình hiện có ...
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; }
# Nếu plugin bên ngoài dùng admin-ajax.php, hãy cho phép riêng bằng một location khác
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
}
}
Cách kết hợp if với return là dạng mà Nginx xử lý an toàn. /wp-admin/admin-ajax.php có thể được các chức năng của trang công khai (biểu mẫu, cuộn vô hạn, v.v.) gọi khi chưa đăng nhập, nên hãy quyết định có loại nó khỏi phần giới hạn hay không tùy theo chức năng của site.
Áp dụng và kiểm tra:
sudo nginx -t && sudo systemctl reload nginx
# Từ chính quốc gia của bạn: nhận được 200 hoặc 302
curl -sI https://example.com/wp-login.php | head -1
# Kiểm tra kết quả xác định (ví dụ ghi mã quốc gia vào log)
# log_format geo '$remote_addr $geoip2_country_code "$request" $status';
Để kiểm tra cách site hiển thị từ nước ngoài, hãy truy cập wp-login.php qua VPN có điểm đặt ở nước ngoài hoặc từ một dịch vụ giám sát ngoài nước, và xác nhận nhận được 403.
Trường hợp đi qua CDN (như Cloudflare)
Khi đi qua CDN, $remote_addr trở thành IP của CDN và mọi người đều bị xác định là thuộc quốc gia của CDN. Trước tiên hãy khôi phục IP thật của người truy cập bằng ngx_http_realip_module (module realip).
# Ví dụ với Cloudflare. Hãy cập nhật danh sách IP định kỳ từ IP Ranges chính thức của Cloudflare
set_real_ip_from 173.245.48.0/20;
# ... liệt kê toàn bộ dải IP của Cloudflare ...
real_ip_header CF-Connecting-IP;
geoip2 mặc định xem $remote_addr, nên việc xác định sẽ dựa trên IP thật sau khi realip đã thay thế. Bản thân Cloudflare cũng có kiểm soát truy cập theo quốc gia (quy tắc tùy chỉnh của WAF), vì vậy nếu bạn đang dùng Cloudflare thì giới hạn ở phía Cloudflare sẽ đơn giản hơn là làm bằng Nginx. Xem thêm Cách thiết lập Cloudflare cho WordPress.
Giới hạn của việc chặn theo quốc gia
- Kết quả xác định của GeoIP chỉ là suy đoán dựa trên thông tin đăng ký của địa chỉ IP, nên có thể bị vượt qua bằng VPN, proxy hoặc máy chủ trung gian đặt trên đám mây ở nước ngoài.
- Với mạng di động hoặc mạng doanh nghiệp, đôi khi IP bị xác định thuộc một quốc gia khác với vị trí thực tế. Cũng có thể xảy ra vấn đề vận hành là quản trị viên đang đi công tác nước ngoài bị chặn không vào được.
- Do đó, hãy dùng giới hạn theo quốc gia như một biện pháp hỗ trợ để giảm các lượt thử đăng nhập dò mật khẩu, kết hợp với xác thực hai yếu tố, giới hạn số lần đăng nhập và bảo vệ wp-admin bằng xác thực Basic.
Câu hỏi thường gặp
Module geoip và module geoip2 của Nginx khác nhau thế nào?
Module geoip cũ đọc dữ liệu định dạng GeoIP Legacy (.dat), nhưng MaxMind đã ngừng phát hành định dạng này. Module geoip2 (ngx_http_geoip2_module) đọc định dạng .mmdb hiện nay và dùng được dữ liệu miễn phí GeoLite2. Cấu hình mới nên dùng geoip2.
GeoLite2 có miễn phí không? Có cần đăng ký không?
Miễn phí, nhưng cần đăng ký tài khoản MaxMind và cấp khóa cấp phép. Việc tải và cập nhật định kỳ được thực hiện bằng geoipupdate. Cách cũ là tải trực tiếp mà không cần khóa hiện không còn chạy được.
Giới hạn theo quốc gia có ngăn được đăng nhập trái phép vào WordPress không?
Cách này có tác dụng giảm các lượt thử dò mật khẩu, nhưng vì có thể bị vượt qua bằng VPN hoặc máy chủ trung gian ở nước ngoài nên không thể nói là ngăn chặn được. Hãy kết hợp với giới hạn số lần đăng nhập, xác thực hai yếu tố, xác thực Basic, v.v.
Khi dùng Cloudflare thì mọi người đều thuộc cùng một quốc gia
Đó là vì khi đi qua CDN, nguồn kết nối trở thành IP của CDN. Hãy khôi phục IP thật bằng set_real_ip_from và real_ip_header CF-Connecting-IP rồi mới xác định. Cũng có cách giới hạn theo quốc gia bằng WAF của Cloudflare.
Dùng GeoLite2-City thì có giới hạn đến cấp thành phố được không?
Có thể đưa cả mã thành phố và khu vực vào biến, nhưng độ chính xác ở cấp thành phố thấp hơn cấp quốc gia, dễ xác định sai và chặn nhầm người dùng hợp lệ. Với kiểm soát truy cập, nên dừng ở cấp quốc gia.
Tổng kết
- Giới hạn theo quốc gia trong Nginx hiện nay được thực hiện bằng GeoIP2 (ngx_http_geoip2_module + GeoLite2
.mmdb), và dữ liệu được cập nhật bằnggeoipupdate. - Đưa mã quốc gia vào biến bằng
geoip2, quyết định cho phép hay chặn bằngmap, rồireturn 403tronglocationcủawp-login.phpvà/wp-admin/. - Nếu đi qua CDN thì khôi phục IP thật trước; hãy dùng giới hạn theo quốc gia như biện pháp hỗ trợ, kết hợp với xác thực hai yếu tố, v.v.
Bài viết liên quan
- Cách giới hạn truy cập vào REST API của WordPress
- Cách tạo mật khẩu xác thực Basic của Apache bằng htpasswd | Bảo vệ wp-admin
- Hướng dẫn đầy đủ thiết lập Cloudflare cho WordPress
Tham khảo: ngx_http_geoip2_module (GitHub), MaxMind GeoLite2 Free Geolocation Data, MaxMind – Updating Databases (geoipupdate), Nginx ngx_http_realip_module
Lịch sử cập nhật: 2026-11-09 viết lại toàn bộ (thay cách làm cũ với GeoLite đã ngừng phát hành bằng cách dùng GeoIP2 và geoipupdate, bổ sung ví dụ giới hạn trang quản trị WordPress và lưu ý về CDN). Bài viết này do WordPress Hakase (Lightscend Co., Ltd.) vận hành.
Có câu hỏi về WordPress? Đơn vị xuất bản trang này ở Nhật Bản và trả lời bằng tiếng Nhật. Liên hệ (tiếng Nhật)