2026年11月12日
2026年11月12日
จำกัดการเข้าถึงตามประเทศด้วย Nginx GeoIP2 และ GeoLite2
บทความนี้เป็นฉบับปรับให้เหมาะกับท้องถิ่นจากต้นฉบับภาษาญี่ปุ่น อ่านต้นฉบับภาษาญี่ปุ่น
การจำกัดการเข้าถึงตามประเทศบน Nginx ในขั้นตอนปัจจุบัน (ณ พฤศจิกายน 2026) ทำได้โดยใช้โมดูล GeoIP2 (ngx_http_geoip2_module) ร่วมกับฐานข้อมูล GeoLite2 ของ MaxMind แล้วเก็บรหัสประเทศลงตัวแปรด้วยบล็อก geoip2 จากนั้นใช้ map ตัดสินว่าจะอนุญาตหรือปฏิเสธ ส่วนวิธีเก่าในบทความรุ่นก่อนที่สั่ง wget ไฟล์ .dat ของ GeoLite นั้นใช้ไม่ได้แล้ว เพราะยุติการแจกจ่ายข้อมูลรูปแบบดังกล่าวไปแล้ว
สรุปประเด็นสำคัญไว้ก่อน
- โมดูลเก่า
ngx_http_geoip_module(GeoIP Legacy) ใช้เริ่มต้นใหม่ไม่ได้ เพราะ MaxMind เลิกแจกจ่ายข้อมูลรูปแบบเก่าแล้ว ให้ย้ายไปใช้ GeoIP2 (รูปแบบ.mmdb) - GeoLite2 ใช้ฟรี แต่ต้องสมัครบัญชี MaxMind และมี License Key โดยดาวน์โหลดและอัปเดตผ่าน
geoipupdate - ฝั่ง Nginx ให้สร้างตัวแปรอย่าง
$geoip2_country_codeด้วยบล็อกgeoip2ใช้mapกำหนดค่า 0 / 1 ที่เทียบเท่าallow/denyแล้วสั่งreturn 403ในlocation - หากเว็บไซต์อยู่หลัง CDN เช่น Cloudflare ต้องกู้คืน IP จริงของผู้เข้าชมด้วย
real_ip_headerก่อน ไม่เช่นนั้นทุกคำขอจะถูกตัดสินเป็นประเทศของ CDN - การจำกัดตามประเทศเป็นเพียงมาตรการเสริมเพื่อลดการโจมตี และหลบเลี่ยงได้ด้วย VPN หรือตัวกลาง จึงควรใช้เฉพาะหน้าล็อกอินและหน้าผู้ดูแล ไม่ใช่ทั้งหน้าสาธารณะ
ความต่างระหว่าง geoip แบบเก่ากับ GeoIP2
| หัวข้อ | ngx_http_geoip_module (เก่า) | ngx_http_geoip2_module (GeoIP2) |
|---|---|---|
| รูปแบบข้อมูล | GeoIP Legacy (.dat) |
GeoIP2 (.mmdb) |
| การแจกจ่ายข้อมูลฟรี | สิ้นสุดแล้ว (ยุติการแจกจ่ายในปี 2019) | GeoLite2 (ต้องสมัครบัญชีและมี License Key) |
| ไลบรารีที่ต้องใช้ | libGeoIP | libmaxminddb |
| การติดตั้งโมดูล | มากับ Nginx มาตรฐาน (--with-http_geoip_module) |
โมดูลของบุคคลที่สาม leev/ngx_http_geoip2_module ส่วน Debian / Ubuntu มีแพ็กเกจให้ |
| ตัวแปร | กำหนดตายตัว เช่น $geoip_country_code |
ตั้งชื่อเองในบล็อก geoip2 |
หากการตั้งค่าเดิมยังใช้ geoip_country อยู่ ฐานข้อมูลจะไม่ได้รับการอัปเดตแล้ว ผลการตัดสินจึงล้าสมัย ควรถือโอกาสนี้ย้ายไปใช้ GeoIP2
ขั้นตอนที่ 1: สมัคร MaxMind และสร้าง License Key
- สร้างบัญชีฟรีจากหน้า GeoLite2 ของ MaxMind
- หลังล็อกอิน ให้ออก 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
ระบุ Account ID และ License Key ในไฟล์ตั้งค่า /etc/GeoIP.conf
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: ติดตั้งโมดูล GeoIP2 ให้ Nginx
Debian / Ubuntu (Nginx จาก apt)
sudo apt install libnginx-mod-http-geoip2
ls /etc/nginx/modules-enabled/ # จะมีไฟล์ 50-mod-http-geoip2.conf วางอยู่
nginx -t
Nginx จากแพ็กเกจของ nginx.org หรือที่คอมไพล์จากซอร์ส
ติดตั้ง libmaxminddb ก่อน แล้วคอมไพล์ dynamic module จากซอร์สของ 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;
}
# ประเทศที่อนุญาตให้เข้าหน้าผู้ดูแล (รหัส 2 ตัวอักษรตาม ISO 3166-1)
map $geoip2_country_code $admin_allowed {
default 0;
JP 1;
"" 1; # กรณีตัดสินไม่ได้ (เช่น IP ส่วนตัว) ให้อนุญาต หากต้องการปฏิเสธให้ใช้ 0
}
}
auto_reload คือช่วงเวลาที่ Nginx จะโหลดฐานข้อมูลที่ 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';
หากต้องการดูว่าจากต่างประเทศเห็นเป็นอย่างไร ให้เข้า wp-login.php ผ่าน VPN ที่มีจุดเชื่อมต่อในต่างประเทศ หรือบริการเฝ้าระวังจากนอกประเทศ แล้วตรวจว่าได้ 403
กรณีใช้ CDN (เช่น Cloudflare)
เมื่อผ่าน CDN ค่า $remote_addr จะเป็น IP ของ CDN ทำให้ทุกคนถูกตัดสินเป็นประเทศของ CDN จึงต้องกู้คืน IP จริงของผู้เข้าชมด้วย ngx_http_realip_module ก่อน (โมดูล realip)
# ตัวอย่างสำหรับ Cloudflare ให้อัปเดตรายการ IP จาก IP Ranges ทางการของ Cloudflare เป็นระยะ
set_real_ip_from 173.245.48.0/20;
# ... ระบุช่วง IP ของ Cloudflare ให้ครบทั้งหมด ...
real_ip_header CF-Connecting-IP;
โดยค่าเริ่มต้น geoip2 จะดู $remote_addr จึงตัดสินจาก IP จริงหลังจาก realip แทนที่ค่าแล้ว นอกจากนี้ Cloudflare เองก็มีการควบคุมการเข้าถึงตามประเทศ (WAF custom rules) หากใช้ Cloudflare อยู่แล้ว การจำกัดที่ฝั่ง Cloudflare จะตั้งค่าง่ายกว่าทำบน Nginx ดูเพิ่มเติมที่ การตั้งค่า Cloudflare กับ WordPress
ข้อจำกัดของการจำกัดตามประเทศ
- การตัดสินด้วย GeoIP เป็นการประมาณจากข้อมูลที่ลงทะเบียนไว้ของ IP address และหลบเลี่ยงได้ด้วย VPN พร็อกซี หรือการส่งต่อผ่านคลาวด์ในต่างประเทศ
- บนเครือข่ายมือถือหรือเครือข่ายองค์กร อาจถูกตัดสินเป็นประเทศอื่นที่ไม่ตรงกับที่ตั้งจริง และอาจเกิดปัญหาในการใช้งาน เช่น ผู้ดูแลที่เดินทางไปต่างประเทศถูกบล็อก
- ดังนั้นควรใช้การจำกัดตามประเทศเป็นมาตรการเสริมเพื่อลดการเดารหัสผ่านแบบ brute force ร่วมกับการยืนยันตัวตนสองขั้นตอน การจำกัดจำนวนครั้งที่ล็อกอิน และการป้องกัน wp-admin ด้วย Basic Authentication
คำถามที่พบบ่อย
โมดูล geoip กับ geoip2 ของ Nginx ต่างกันอย่างไร
โมดูล geoip แบบเก่าอ่านข้อมูลรูปแบบ GeoIP Legacy (.dat) แต่ MaxMind เลิกแจกจ่ายรูปแบบนี้แล้ว ส่วนโมดูล geoip2 (ngx_http_geoip2_module) อ่านรูปแบบ .mmdb ปัจจุบันและใช้ข้อมูลฟรีของ GeoLite2 ได้ การตั้งค่าใหม่ให้ใช้ geoip2
GeoLite2 ใช้ฟรีหรือไม่ ต้องสมัครหรือเปล่า
ใช้ฟรี แต่ต้องสมัครบัญชี MaxMind และออก License Key ส่วนการดาวน์โหลดและอัปเดตเป็นระยะทำผ่าน geoipupdate วิธีเก่าที่ดาวน์โหลดตรงโดยไม่ใช้คีย์ใช้ไม่ได้แล้ว
จำกัดตามประเทศแล้วจะป้องกันการล็อกอินที่ไม่ชอบมาพากลของ WordPress ได้หรือไม่
ช่วยลดจำนวนการเดารหัสผ่านได้ แต่หลบเลี่ยงได้ด้วย VPN หรือการส่งต่อผ่านเซิร์ฟเวอร์ต่างประเทศ จึงไม่อาจบอกได้ว่าป้องกันได้ ควรใช้ร่วมกับการจำกัดจำนวนครั้งที่ล็อกอิน การยืนยันตัวตนสองขั้นตอน และ Basic Authentication
ใช้ Cloudflare แล้วทุกคนเป็นประเทศเดียวกันหมด
เพราะเมื่อผ่าน CDN ต้นทางของการเชื่อมต่อจะเป็น IP ของ CDN ให้กู้คืน IP จริงด้วย set_real_ip_from และ real_ip_header CF-Connecting-IP ก่อนจึงค่อยตัดสิน นอกจากนี้ยังมีวิธีจำกัดตามประเทศด้วย WAF ของ Cloudflare
ใช้ GeoLite2-City แล้วจำกัดถึงระดับเมืองได้หรือไม่
ใส่รหัสเมืองหรือภูมิภาคลงตัวแปรได้ แต่ความแม่นยำระดับเมืองต่ำกว่าระดับประเทศ จึงมีโอกาสตัดสินผิดและบล็อกผู้ใช้ที่ถูกต้อง สำหรับการควบคุมการเข้าถึง การใช้แค่ระดับประเทศปลอดภัยกว่า
สรุป
- การจำกัดตามประเทศบน Nginx ในปัจจุบันทำด้วย GeoIP2 (ngx_http_geoip2_module + GeoLite2
.mmdb) และอัปเดตข้อมูลด้วยgeoipupdate - เก็บรหัสประเทศลงตัวแปรด้วย
geoip2กำหนดอนุญาต/ปฏิเสธด้วยmapแล้วสั่งreturn 403ในlocationของwp-login.phpและ/wp-admin/ - หากผ่าน CDN ให้กู้คืน IP จริงก่อน และใช้การจำกัดตามประเทศเป็นมาตรการเสริมร่วมกับการยืนยันตัวตนสองขั้นตอนเป็นต้น
บทความที่เกี่ยวข้อง
- วิธีจำกัดการเข้าถึง REST API ของ WordPress
- วิธีสร้างรหัสผ่าน Basic Authentication ของ Apache ด้วย htpasswd | การป้องกัน wp-admin
- คู่มือฉบับสมบูรณ์การตั้งค่า Cloudflare กับ WordPress
อ้างอิง: 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 ไหม ผู้เผยแพร่เว็บไซต์นี้อยู่ที่ญี่ปุ่นและตอบเป็นภาษาญี่ปุ่น ติดต่อ (ภาษาญี่ปุ่น)