IpGeoLookup
A lightweight, zero-dependency Ruby gem for resolving IPv4 and IPv6 addresses to geographic locations. Ships with an embedded MaxMind GeoLite2 database and a pure Ruby MMDB reader - no external gems, no API keys, no setup.
Features
- Zero dependencies - pure Ruby MMDB reader, no native extensions, no external gems
- IPv4 and IPv6 - resolves to country, region, city, coordinates, timezone, and more
- Batteries included - GeoLite2 City database ships with the gem
- Fast - binary trie traversal over MaxMind's MMDB format
-
Secure - no
Marshal.load, rejects ambiguous IP octets with leading zeros - Thread-safe - safe for Puma, Sidekiq, and other multi-threaded servers
-
Fork-friendly -
:filemode usespreadfor shared OS page cache across workers -
Configurable - use the embedded database or point to your own
.mmdbfile
Installation
gem "ip_geo_lookup"bundle installThat's it - the database is included.
Usage
Basic lookup
require "ip_geo_lookup"
result = IpGeoLookup.lookup("8.8.8.8")
result = IpGeoLookup.lookup("2001:4860:4860::8888")Accessing results
result = IpGeoLookup.lookup("8.8.8.8")
# Core fields
result.country_code # => "US"
result.country_name # => "United States"
result.region # => "California"
result.city # => "Mountain View"
# Extended fields
result.continent_code # => "NA"
result.continent_name # => "North America"
result.latitude # => 37.386
result.longitude # => -122.0838
result.time_zone # => "America/Los_Angeles"
result.postal_code # => "94035"
# Hash-style access
result[:country_code] # => "US"
# Full MMDB record
result.raw # => {"country" => {"iso_code" => "US", ...}, ...}
# Conversions
result.to_h # => {country_code: "US", country_name: "United States", ...}
result.to_s # => "Mountain View, California, United States (US)"
# Sorting
results = ips.map { |ip| IpGeoLookup.lookup(ip) }.compact.sortHandling unknown IPs
Returns nil when the IP address is not found or is invalid:
IpGeoLookup.lookup("192.168.1.1") # => nil (private range)
IpGeoLookup.lookup("not_an_ip") # => nil (invalid format)
IpGeoLookup.lookup("08.8.8.8") # => nil (leading zeros rejected)
IpGeoLookup.lookup(nil) # => nilConfiguration
IpGeoLookup.configure do |config|
config.database_path = "/path/to/GeoLite2-City.mmdb"
config.mode = :memory # optional: load entire DB into memory for single-process apps
endLifecycle
IpGeoLookup.reload! # re-reads from disk, respects configured path
IpGeoLookup.close # releases file handle / memory
IpGeoLookup.metadata # => {"database_type" => "GeoLite2-City", ...}How It Works
The gem includes a pure Ruby reader for MaxMind's MMDB binary format. On lookup:
- The IP string is validated and converted to an integer in a single pass
- The MMDB binary trie is walked (32 bits for IPv4, 128 for IPv6)
- The matching record is decoded from the data section
- A
Resultobject is returned (ornilif no match)
Two I/O modes are available:
-
:file(default) - keeps the file open and usesIO#preadfor reads; the OS page cache shares data across forked workers automatically -
:memory- reads the entire file into a Ruby String for fastest lookups in single-process environments
Compatibility
- Ruby >= 2.6.0
- Zero external dependencies
- Thread-safe
- Linux, macOS, Windows
Development
bundle install
bundle exec rake specTest fixtures are generated automatically during the test run - no external database file needed.
Updating the MaxMind database
The embedded GeoLite2 City database lives in data/GeoLite2-City.mmdb (gitignored due to size). To update it:
- Create a free account at MaxMind
- Download the GeoLite2 City MMDB file
- Copy it into the gem:
cp /path/to/GeoLite2-City.mmdb data/GeoLite2-City.mmdb
- Rebuild the gem:
gem build ip_geo_lookup.gemspec
Contributing
- Fork it
- Create your feature branch (
git checkout -b feature/my-feature) - Commit your changes
- Push to the branch
- Create a Pull Request
License
Available as open source under the MIT License.
Attribution
This product includes GeoLite2 data created by MaxMind, available from https://www.maxmind.com.