{"id":21292684,"url":"https://github.com/streamdp/ip-info","last_synced_at":"2026-04-02T21:45:41.014Z","repository":{"id":262973896,"uuid":"860554622","full_name":"streamdp/ip-info","owner":"streamdp","description":"Microservice for IP-based geolocation.","archived":false,"fork":false,"pushed_at":"2025-02-14T12:52:09.000Z","size":109,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-14T13:42:29.014Z","etag":null,"topics":["golang","grpc-server","http-server","json","postgresql"],"latest_commit_sha":null,"homepage":"https://ip-info.oncook.top","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/streamdp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-20T16:50:57.000Z","updated_at":"2025-02-14T12:52:13.000Z","dependencies_parsed_at":"2024-11-15T11:19:44.949Z","dependency_job_id":"7b5ca5b4-2524-4cf2-b45e-b9ee64a38cba","html_url":"https://github.com/streamdp/ip-info","commit_stats":null,"previous_names":["streamdp/ip-info"],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamdp%2Fip-info","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamdp%2Fip-info/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamdp%2Fip-info/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamdp%2Fip-info/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/streamdp","download_url":"https://codeload.github.com/streamdp/ip-info/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243762232,"owners_count":20343972,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","grpc-server","http-server","json","postgresql"],"created_at":"2024-11-21T13:51:27.396Z","updated_at":"2026-04-02T21:45:41.008Z","avatar_url":"https://github.com/streamdp.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# IP-INFO\n[![Website ip-info.oncook.top](https://img.shields.io/website-up-down-green-red/https/ip-info.oncook.top.svg)](https://ip-info.oncook.top)\n[![GitHub release](https://img.shields.io/github/release/streamdp/ip-info.svg)](https://github.com/streamdp/ip-info/releases/)\n[![test](https://github.com/streamdp/ip-info/actions/workflows/test.yml/badge.svg)](https://github.com/streamdp/ip-info/actions/workflows/test.yml)\n## ⚠️ Breaking Changes\nStarting from release **v1.0.0**, the database schema has changed. The `ip_to_city_one` and `ip_to_city_two` tables now\ninclude a new generated column `ip_range` (of type `inet`), computed automatically from `ip_start` and `ip_end` using\n`inet_merge(ip_start, ip_end)`:\n```sql\nip_range inet generated always as (inet_merge(ip_start, ip_end)) stored\n```\nThe SP-GiST index is now created on `ip_range` instead of `ip_start`, and IP lookups use the `\u003e\u003e= ` operator against\n`ip_range` instead of the previous approach.\n\n**If you are upgrading from a previous version, you must re-initialize your database** using the updated\n[init.sql](database/model/init.sql) script before starting the application. The existing schema is not compatible with\nthis release and the application will not work correctly without the migration.\n\n## Microservice for IP-based geolocation\nThis microservice is a small, independent software application designed to determine the geographic location of a device \nbased on its IP address. It achieves this by using a free public database called [db-ip.com](https://db-ip.com)\n(*free version provides about __77%__ accuracy*), which contains a vast amount\nof information linking IP addresses to specific locations.\n## Key features:\n* **Automatic Database Updates:** The microservice regularly updates its local copy of the **db-ip.com** database to \nensure that the location data is always accurate and up-to-date.\n* **Fast Lookup:** It is optimized to perform quick searches within the database, allowing it to efficiently determine \nthe location associated with a given IP address.\n* **HTTP and gRPC Support:** The microservice can be accessed and interacted with using both protocols, providing \nflexibility in how it can be integrated into other systems or applications.\n* **Rate limiting:** The microservice provides per-client rate limits and sends a **429** HTTP response when the client makes \nrequests too frequently.\n* **Caching:** The microservice implements caching to improve availability and reduce database load.\n## API:\nList of the **HTTP** endpoints:\n* [GET] **/healthz** - check node status\n* [GET] **/client-ip** - return client ip address info, works like other \"my ip\" services\n* [GET] **/ip-info** - return info for the specified ip address\n* [GET] **/app/version** - return app version\n\nList of the **gRPC** methods:\n* [GRPC] **/IpInfo/GetClientIp** - return client ip address info, works like other \"my ip\" services\n* [GRPC] **/IpInfo/GetIpInfo** - return info for the specified ip address\n## Usage example:\nStart postgresql and ip-info containers:\n```shell\n$ docker-compose up -d\n```\nWe are waiting for the database to be updated:\n```shell\n$ docker logs -f ip-info-container \nIP_INFO: 2024/09/22 16:41:44 HTTP server listening at :8080\nIP_INFO: 2024/09/22 16:41:44 gRPC server listening at [::]:50051\nIP_INFO: 2024/09/22 16:41:45 ip database update started\nIP_INFO: 2024/09/22 16:41:45 truncate ip_to_city_one table before importing update\nIP_INFO: 2024/09/22 16:41:45 droping ip_to_city_one_ip_start_gist_idx index\nIP_INFO: 2024/09/22 16:41:45 import ip database updates\nIP_INFO: 2024/09/22 16:43:41 creating  ip_to_city_one_ip_start_gist_idx index on ip_to_city_one table\nIP_INFO: 2024/09/22 16:45:18 switching backup and working tables\nIP_INFO: 2024/09/22 16:45:18 updating database config\nIP_INFO: 2024/09/22 16:45:18 ip database update completed, next update through 223.2h\n```\nAnd we can make several test requests:\n```shell\n$ curl localhost:8080/ip-info?ip=8.8.8.8\n{\n  \"error\": \"\",\n  \"content\": {\n    \"ip\": \"8.8.8.8\",\n    \"continent\": \"NA\",\n    \"country\": \"US\",\n    \"state_prov\": \"California\",\n    \"city\": \"Mountain View\",\n    \"latitude\": -122.085,\n    \"longitude\": 37.4223\n  }\n}\n```\n```shell\n$ grpcurl  -plaintext -d '{\"ip\": \"211.27.38.98\"}' 127.0.0.1:50051 IpInfo/GetIpInfo\n{\n  \"ip\": \"211.27.38.98\",\n  \"continent\": \"OC\",\n  \"country\": \"AU\",\n  \"stateProv\": \"New South Wales\",\n  \"city\": \"Sydney\",\n  \"latitude\": 151.209,\n  \"longitude\": -33.8688\n}\n```\n## Benchmarking (i3-7100U CPU @ 2.40GHz, 11GiB RAM, PostgreSQL 16.2, 8 068 719 records)\nFor testing purposes, I used a simple custom function to generate a random IP address for each HTTP or gRPC call. To \nensure repeatability of results, I've added an example below:\n```go\nfunc GenerateIPV4() string {\n\treturn fmt.Sprintf(\n\t\t\"%d.%d.%d.%d\",\n\t\trand.Intn(256),\n\t\trand.Intn(256),\n\t\trand.Intn(256),\n\t\trand.Intn(256),\n\t)\n}\n\nfunc (s *Server) ipInfo(useClientIp bool) func(http.ResponseWriter, *http.Request) {\n        ...\t\t\n        ipString = GenerateIPV4()\n        ipInfo, err := s.locator.GetIpInfo(r.Context(), ipString)\n        ...\n```\nFor security reasons, this is not available in the production version. \n* **http** benchmarking with [hey - HTTP load generator tool](https://github.com/rakyll/hey) **without** cache, random IP:\n```shell\n$ hey -c 2 -n 10000 -T \"application/json\" http://127.0.0.1:8080/ip-info?ip=8.8.8.8\n  Total:\t4.1939 secs\n  Slowest:\t0.0044 secs\n  Fastest:\t0.0005 secs\n  Average:\t0.0008 secs\n  Requests/sec:\t2384.4086\n```\nwhen **redis** cache used, one static IP address (for cache hit checking):\n```shell\n  Total:\t2.0778 secs\n  Slowest:\t0.0163 secs\n  Fastest:\t0.0002 secs\n  Average:\t0.0004 secs\n  Requests/sec:\t4812.7207\n```\nwhen **memory** cache used, one static IP address (for cache hit checking):\n```shell\n  Total:\t0.8988 secs\n  Slowest:\t0.0150 secs\n  Fastest:\t0.0001 secs\n  Average:\t0.0002 secs\n  Requests/sec:\t11126.3097\n```\n* **gRPC** benchmarking with [ghz - Simple gRPC load testing tool](https://github.com/bojand/ghz) **without** cache, random IP:\n```shell\n$ ghz -c 2 -n 10000 127.0.0.1:50051 --call IpInfo.GetIpInfo -d '{\"ip\":\"8.8.8.8\"}' --insecure \n  Total:\t6.83 s\n  Slowest:\t5.97 ms\n  Fastest:\t0.57 ms\n  Average:\t1.13 ms\n  Requests/sec:\t1463.12\n```\nwhen **redis** cache used, one static IP address (for cache hit checking):\n```shell\n  Total:\t4.63 s\n  Slowest:\t7.73 ms\n  Fastest:\t0.27 ms\n  Average:\t0.70 ms\n  Requests/sec:\t2158.29\n```\nwhen **memory** cache used, one static IP address (for cache hit checking):\n```shell\n  Total:\t3.17 s\n  Slowest:\t19.62 ms\n  Fastest:\t0.13 ms\n  Average:\t0.42 ms\n  Requests/sec:\t3154.36\n```\n## Rate limiting\nYou could choose **limiter** between [redis_rate](https://github.com/go-redis/redis_rate) (_redis_ should be present)\nand [golimiter](https://github.com/streamdp/golimiter), using **-limiter** flag or **IP_INFO_LIMITER**\nenvironment variable. To enable rate limiting run _ip-info_ microservice with the **-enable-limiter** flag or \n**IP_INFO_ENABLE_LIMITER** environment variable. The default rate limit value is 10 requests per second per client, \nyou can adjust it with the **-rate-limit** flag or **IP_INFO_RATE_LIMIT** environment variable. \n```shell\nversion: \"3.4\"\nservices:\n   ip-info:\n      image: streamdp/ip-info:v0.2.0\n      container_name: ip-info\n      environment:\n         - IP_INFO_DATABASE_URL=postgresql://postgres:postgres@postgres:5432/dbip?sslmode=disable\n         - IP_INFO_ENABLE_LIMITER=true\n         - IP_INFO_RATE_LIMIT=15 # default 10 requests per second per client\n         - IP_INFO_LIMITER=redis_rate # default \"golimiter\"\n         - REDIS_URL=redis://:qwerty@redis:6379/0\n      ports:\n         - \"8080:8080\"\n         - \"50051:50051\"\n      restart: always\n   \n   redis:\n      image: redis\n      container_name: redis\n      ports:\n         - \"6379:6379\"\n      command: redis-server --save \"\" --maxmemory 64mb --maxmemory-policy allkeys-lfu --requirepass qwerty\n      restart: always\n```\n```shell\n$ docker-compose up -d\n```\n## Caching\nCaching in-memory with [microcache](https://github.com/streamdp/microcache) library is enabled by default, to disable you need \nto run _ip-info_ microservice with the **-disable-cache** flag or **IP_INFO_DISABLE_CACHE=true** environment variable. \nThe default **TTL** value is **3600** seconds, you can adjust it with the **-cache-ttl** flag or **IP_INFO_CACHE_TTL** \nenvironment variable. You could choose cacher between **redis** and **microcache**, using **-cacher** \nflag or **IP_INFO_CACHER** environment variable. \n```shell\nversion: \"3.4\"\nservices:\n   ip-info:      \n      environment:\n         - IP_INFO_CACHE_TTL=1800 # default 3600 seconds\n         - IP_INFO_CACHER=redis # default \"microcache\"\n         - REDIS_URL=redis://:qwerty@redis:6379/0\n```\n## Help \nYou can see all available command flags when you run the application with the -h flag.\n```shell\n$ ./bin/app -h\nip-info is a microservice for IP location determination\n\nUsage of ./bin/app:\n  -cache-ttl int\n        cache ttl in seconds (default 3600)\n  -cacher string\n        where to store cache entries: redis, microcache (default \"microcache\")\n  -db-request-timeout int\n        database request timeout in milliseconds (default 5000)\n  -disable-cache\n        disable cache\n  -enable-limiter\n        enable rate limiter\n  -grpc-port int\n        grpc server port (default 50051)\n  -h    display help\n  -http-port int\n        http server port (default 8080)\n  -http-read-timeout int\n        http server read timeout (default 5000)\n  -limiter string\n        what use to limit queries: redis_rate, golimiter (default \"golimiter\")\n  -rate-limit int\n        rate limit, rps per client (default 10)\n  -rate-limit-ttl int\n        rate limit entries ttl in seconds (default 60)\n  -read-header-timeout int\n        http server read header timeout (default 5000)\n  -redis-db int\n        redis database\n  -redis-host string\n        redis host (default \"127.0.0.1\")\n  -redis-port int\n        redis port (default 6379)\n  -v    display version\n  -write-timeout int\n        http server write timeout (default 5000)\n```\n## Contributing\nContributions are welcome! If you encounter any issues, have suggestions for new features, or want to improve **ip-info**, please feel free to open an issue or submit a pull request on the project's GitHub repository.\n## License\n**ip-info** is released under the _GPL 3.0_ License. See the [LICENSE](https://github.com/streamdp/ip-info/blob/master/LICENSE) file for complete license details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstreamdp%2Fip-info","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstreamdp%2Fip-info","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstreamdp%2Fip-info/lists"}