기본 콘텐츠로 건너뛰기

nginx 국가별 대역폭 (using geoip)

Nginx 에서 GeoIP 를 이용해 국가별로 접속 대역폭을 다르게 걸 수 있다. 콘텐츠 CDN 이 없을 때 해외 대역을 쭈꾸미로 만들어서 국내 서비스에 영향을 덜 주는 용도로 많이 쓴다.

두 가지 방법이 있음:

- (A) Maxmind 의 GeoIPCountryWhois.csv 를 쪼개서 geo 모듈에 include
- (B) nginx 의 ngx_http_geoip_module (외부 .dat DB) 사용

(A) 가 의존성 적고 제일 안전. (B) 는 빌드 옵션에 --with-http_geoip_module 이 들어가 있어야 함.


방법 A — CSV → include

# wget http://geolite.maxmind.com/download/geoip/database/GeoIPCountryCSV.zip
# unzip GeoIPCountryCSV.zip        # GeoIPCountryWhois.csv

CSV 원본 한 줄 예시:
"1.11.0.0","1.11.255.255","17498112","17563647","KR","Korea, Republic of"

이걸 nginx geo 문법으로 바꿔야 한다:
1.11.0.0/16 KR;

Yongbok 님이 올려둔 스크립트가 제일 편함:
# wget http://mirror.yongbok.net/ruo91/nginx/script/geo2nginx.pl
# chmod +x geo2nginx.pl
# ./geo2nginx.pl < GeoIPCountryWhois.csv > /usr/local/nginx/conf/nginxGeo.txt


nginx.conf 의 http 블록에:
geo $country {
    default no;
    include /usr/local/nginx/conf/nginxGeo.txt;
}

가상호스트의 server 블록에 대역폭 분기:
server {
    listen 80;
    server_name www.example.com;

    if ($country ~ ^(?:US|CA|ES)$) { set $limit_rate 500k; }
    if ($country ~ ^(?:RU|CN)$)     { set $limit_rate 1k;   }
    if ($country ~ ^KR$)            { set $limit_rate 0;    }  # 무제한

    location /files/ {
        root /var/www/files;
    }
}

$limit_rate 는 nginx 내장 변수라 값만 넣으면 해당 요청의 limit_rate 로 쓰인다. 따로 limit_rate 디렉티브 안 적어도 됨.


방법 B — geoip_country 모듈

nginx 빌드에 해당 모듈이 들어있어야 한다. Maxmind 의 GeoIP.dat (Country) 또는 GeoIPCity.dat 을 쓴다.

# wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
# gunzip GeoIP.dat.gz
# mv GeoIP.dat /usr/local/nginx/conf/

# http 블록
geoip_country /usr/local/nginx/conf/GeoIP.dat;

map $geoip_country_code $country_limit_rate {
    default     200k;
    KR          0;
    US          500k;
    CA          500k;
    RU          1k;
    CN          1k;
}

server {
    listen 80;
    location /files/ {
        set $limit_rate $country_limit_rate;
        root /var/www/files;
    }
}

map 쪽이 if 블록보다 설정이 깔끔하고 성능도 낫다. 2014 년 기준이면 거의 모든 nginx 빌드에 map 은 내장.


주의 사항

- nginx 의 if 는 evil 로 알려져 있다. server 레벨에서는 그나마 안전, location 안에서는 가급적 map 을 쓸 것.
- GeoLite DB 는 정기적으로 갱신 필요. 매월 1일쯤 cron 으로 다시 받는 걸 걸어두자.
# /etc/cron.d/geoip-update
0 3 1 * * root wget -q -O - http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz | gunzip > /usr/local/nginx/conf/GeoIP.dat && /usr/sbin/nginx -s reload

- CDN / proxy 뒤에 있으면 $remote_addr 가 프록시 IP 라 GeoIP 가 말짱 도루묵. 이 경우 real_ip_header X-Forwarded-For + set_real_ip_from 로 원래 IP 를 먼저 확보한 뒤 GeoIP 가 그 값을 쓰게 해야 한다.
- Maxmind 가 GeoIP2 (MMDB 포맷) 로 가는 중이라, 오래 운영할 프로젝트라면 점차 GeoIP2 계열 모듈 (nginx-mod-http-geoip2) 로 넘어갈 준비 할 것.


원출처: http://www.kutukupret.com/2010/09/16/nginx-limit-website-visitor-bandwidth-by-country/