Read first: How to build openresty with GeoIP and Naxsi on CentOS 7
We build a simple GeoIP and ASNnum query server:
- http://example.com:31000 for current GeoIP and http://example.com/ip for current IP only
- http://example.com:31000/x.x.x.x to query any IP.
- http://example.com:31000/domain-name for GeoIP of domain-name and http://example.com:31000/domain-name/ip to return IP of domain-name only. If multiple IPs are set to single domain-name, all of them will be returned. Only A record will be used.
Sample requests are:
$ curl http://example.com/ x.x.x.x Country, Region, City ASN number $ curl http://example.com:31000/ip x.x.x.x $ curl http://example.com:31000/rdns x.x.x.x.com $ curl http://example.com:31000/74.125.203.199 74.125.203.199 th-in-f199.1e100.net United States, California, Mountain View AS15169 Google Inc. $ curl http://example.com:31000/www.google.com.hk 74.125.203.199 th-in-f199.1e100.net United States, California, Mountain View AS15169 Google Inc. $ curl http://example.com:31000/www.google.com.hk/ip 74.125.203.199 $ curl http://example.com:31000/www.google.com.hk/dns www-wide.l.google.com 74.125.203.199
File nginx.conf:
load_module /usr/local/openresty/nginx/modules/ngx_http_geoip2_module.so; worker_processes 1; events { worker_connections 1024; } http { map $http_x_forwarded_for $realip { ~^(\d+\.\d+\.\d+\.\d+) $1; default $remote_addr; } geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb { auto_reload 5m; $geoip2_metadata_country_build metadata build_epoch; $geoip2_data_country_code default=US source=$realip country iso_code; $geoip2_data_country_name source=$realip country names en; $geoip2_data_country_geonameid country geoname_id; $geoip2_data_country_is_eu country is_in_european_union; } geoip2 /usr/share/GeoIP/GeoLite2-City.mmdb { auto_reload 5m; $geoip2_metadata_city_build metadata build_epoch; $geoip2_data_city_name source=$realip city names en; $geoip2_data_city_geonameid source=$realip city geoname_id; $geoip2_data_continent_code source=$realip continent code; $geoip2_data_continent_geonameid source=$realip continent geoname_id; $geoip2_data_continent_name source=$realip continent names en; $geoip2_data_location_accuracyradius source=$realip location accuracy_radius; $geoip2_data_location_latitude source=$realip location latitude; $geoip2_data_location_longitude source=$realip location longitude; $geoip2_data_location_metrocode source=$realip location metro_code; $geoip2_data_location_timezone source=$realip location time_zone; $geoip2_data_postal_code source=$realip postal code; $geoip2_data_rcountry_geonameid source=$realip registered_country geoname_id; $geoip2_data_rcountry_iso source=$realip registered_country iso_code; $geoip2_data_rcountry_name source=$realip registered_country names en; $geoip2_data_rcountry_is_eu source=$realip registered_country is_in_european_union; $geoip2_data_region_geonameid source=$realip subdivisions 0 geoname_id; $geoip2_data_region_iso source=$realip subdivisions 0 iso_code; $geoip2_data_region_name source=$realip subdivisions 0 names en; } geoip2 /usr/share/GeoIP/GeoLite2-ASN.mmdb { auto_reload 5m; $geoip2_data_org source=$realip autonomous_system_organization; $geoip2_data_asn source=$realip autonomous_system_number; } ## FastCGI GeoIP 2 fastcgi_param MM_ADDR $remote_addr; fastcgi_param MM_CITY_NAME $geoip2_data_city_name; fastcgi_param MM_CITY_GEONAMEID $geoip2_data_city_geonameid; fastcgi_param MM_CONTINENT_CODE $geoip2_data_continent_code; fastcgi_param MM_CONTINENT_GEONAMEID $geoip2_data_continent_geonameid; fastcgi_param MM_CONTINENT_NAME $geoip2_data_continent_name; fastcgi_param MM_COUNTRY_GEONAMEID $geoip2_data_country_geonameid; fastcgi_param MM_COUNTRY_CODE $geoip2_data_country_code; fastcgi_param MM_COUNTRY_NAME $geoip2_data_country_name; fastcgi_param MM_COUNTRY_IN_EU $geoip2_data_country_is_eu; fastcgi_param MM_LOCATION_ACCURACY_RADIUS $geoip2_data_location_accuracyradius; fastcgi_param MM_LATITUDE $geoip2_data_location_latitude; fastcgi_param MM_LONGITUDE $geoip2_data_location_longitude; fastcgi_param MM_LOCATION_METROCODE $geoip2_data_location_metrocode; fastcgi_param MM_LOCATION_TIMEZONE $geoip2_data_location_timezone; fastcgi_param MM_POSTAL_CODE $geoip2_data_postal_code; fastcgi_param MM_REGISTERED_COUNTRY_GEONAMEID $geoip2_data_rcountry_geonameid; fastcgi_param MM_REGISTERED_COUNTRY_ISO $geoip2_data_rcountry_iso; fastcgi_param MM_REGISTERED_COUNTRY_NAME $geoip2_data_rcountry_name; fastcgi_param MM_REGISTERED_COUNTRY_IN_EU $geoip2_data_rcountry_is_eu; fastcgi_param MM_REGION_GEONAMEID $geoip2_data_region_geonameid; fastcgi_param MM_REGION $geoip2_data_region_iso; fastcgi_param MM_REGION_NAME $geoip2_data_region_name; fastcgi_param MM_ISP $geoip2_data_org; fastcgi_param MM_ORG $geoip2_data_org; include mime.types; default_type application/octet-stream; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; log_format app_log '$remote_addr [$time_local] "$request" $status $body_bytes_sent ' '$request_time $http_host "$http_referer" $http_user_agent'; map $remote_addr $app_loggable { default 1; "127.0.0.1" 0; "::1" 0; } server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } location /json { add_header Access-Control-Allow-Origin *; add_header Content-Type application/json; content_by_lua_block { ngx.say('{"ip":"'..ngx.var.remote_addr..'","code":"'.. ngx.var.geoip2_data_country_code..'"}') } } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } server { listen 31000; server_name localhost; access_log logs/access.log app_log if=$app_loggable; error_log logs/error.log warn; location = / { default_type "text/plain"; content_by_lua_block { local query_ip = ngx.var.remote_addr if ngx.var.remote_addr == "127.0.0.1"then query_ip = ngx.var.http_x_forwarded_for end local resolver = require "resty.dns.resolver" local r, err = resolver:new { nameservers = {"8.8.8.8", {"8.8.4.4", 53} }, retrans = 5, timeout = 2000 } local rdns = "" while true do if not r then ngx.log(ngx.ERR, "can't new resolver", err) break end local answers, err = r:reverse_query(query_ip) if not answers or #answers == 0 then break end rdns = answers[1].ptrdname break end if rdns then ngx.say(query_ip .. " " .. rdns) else ngx.say(query_ip) end local has_line = false if ngx.var.geoip2_data_country_name ~= nil then ngx.print(ngx.var.geoip2_data_country_name) has_line = true end if ngx.var.geoip2_data_region_name ~= nil then ngx.print(", ", ngx.var.geoip2_data_region_name) has_line = true end if ngx.var.geoip2_data_city_name ~= nil then ngx.print(", ", ngx.var.geoip2_data_city_name) has_line = true end if has_line then ngx.print("\n") end if ngx.var.geoip2_data_org ~= nil then ngx.say('AS'..ngx.var.geoip2_data_asn..' '..ngx.var.geoip2_data_org) end } } location ~ ^/([\d\.\:]+)$ { set_by_lua $query_ip ' local m, err = ngx.re.match(ngx.var.uri, "^/(.+)") if m then ngx.log(ngx.INFO, "ip", m[1]) return m[1] end '; set $up "http://127.0.0.1:31000/"; proxy_set_header X-Forwarded-For $query_ip; proxy_set_header Host $http_host; proxy_pass $up; proxy_hide_header 'Content-Type'; proxy_hide_header 'Vary'; proxy_hide_header 'Access-Control-Allow-Origin'; add_header 'Content-Type' 'text/plain'; add_header 'Vary' 'Accept-Encoding'; add_header 'Access-Control-Allow-Origin' '*'; } location = /ip { default_type "text/plain"; echo $remote_addr; } location = /rdns { default_type "text/plain"; content_by_lua_block { local resolver = require "resty.dns.resolver" local r, err = resolver:new { nameservers = {"8.8.8.8", {"8.8.4.4", 53} }, retrans = 5, timeout = 2000 } local rdns = "default" if not r then ngx.log(ngx.ERR, "can't new resolver", err) ngx.exit(200) end local answers, err = r:reverse_query(ngx.var.remote_addr) if not answers or #answers == 0 then ngx.exit(200) end rds = answers[1].ptrdname ngx.say(rds or "") } } location ~ /([^/]+)/*([^/]*)$ { default_type "text/plain"; set $query_host $1; set $qopt $2; content_by_lua_block { local resolver = require "resty.dns.resolver" local r, err = resolver:new { nameservers = {"8.8.8.8", {"8.8.4.4", 53} }, retrans = 5, timeout = 2000 } if not r then ngx.log(ngx.ERR, "can't new resolver", err) ngx.exit(500) end local answers, err = r:query(ngx.var.query_host) if not answers then ngx.log(ngx.ERR, "query error", ngx.var.query_host, ":", err, " answer: ", answers.errcode, answers.errstr) ngx.exit(200) elseif #answers == 0 then ngx.exit(200) end if string.len(ngx.var.qopt) > 0 then table.foreach(answers, function(i, a) if ngx.var.qopt == "dns" and a.cname then ngx.print(a.cname.. " ") end if a.address then ngx.say(a.address) end end) else local _ = {} table.foreach(answers, function(i, a) if a.address then table.insert(_, {"/"..a.address}) end end) if #_ == 0 then ngx.exit(200) end local resps = { ngx.location.capture_multi(_) } for i, resp in ipairs(resps) do ngx.say(resp.body) end end } } } }
Reference: https://gist.github.com/fffonion/44e5fb59e2a8f0efba5c1965c6043584
You can change port 31000 to 80