Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 30 additions & 74 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,31 @@
> [!IMPORTANT]
> This is a fork of Malith-Rukshan/geoip-api. I added the ability to do self-lookups, that is look up the geolocation of the sender's IP. This was used for geolocating the closest STUN servers for my other project: [FileFerry](https://github.com/smp46/FileFerry).

<p style="text-align:center;" align="center">
<img align="center" src="https://raw.githubusercontent.com/Malith-Rukshan/geoip-api/refs/heads/main/api/static/img/logo.png" alt="GeoIP API" width="300px" height="300px"/>
<img align="center" src="https://raw.githubusercontent.com/smp46/geoip-api/refs/heads/main/api/static/img/logo.png" alt="GeoIP API" width="300px" height="300px"/>
</p>
<h1 align="center">GeoIP API</h1>
<div align='center'>

[![PyPI Package](https://img.shields.io/badge/PyPI-geoip--py-4B8BBE?logo=pypi&style=flat)](https://pypi.org/project/geoip-py/)
[![FastAPI](https://img.shields.io/badge/FastAPI-Demo-009688?logo=fastapi&style=flat)](https://geoip-api.malith.dev/)
[![Docker](https://img.shields.io/badge/Docker-Ready-2496ED?logo=docker&style=flat)](https://hub.docker.com/r/malithrukshan/geoip-api)
</div>

<h4 align="center"> A self-hosted IP geolocation API and Python package that works completely offline! 🚀</h4>
<h4 align="center"> A self-hosted IP geolocation API and Python package that works completely offline! 🚀</h4>

<div align="center">
- Deploy your own private GeoIP service with complete control over your data and infrastructure -
<br/>
<sup><sub>Powered by MaxMind's GeoLite2 databases </sub></sup>
<sup><sub>Powered by MaxMind's GeoLite2 databases </sub></sup>
</div>

## Features
## Features

- 🌍 Fast and reliable IP geolocation lookups
- 🔒 Self-hosted solution with no external API dependencies
- 🛠️ Dual functionality: Python package and REST API
- 🐳 Easy deployment with Docker and cloud platforms
- 📊 Get country, city, coordinates, timezone, ISP, and ASN data
- 🎨 Beautiful, interactive demo UI for testing
- 🚀 Built with FastAPI for high performance
- 📦 Automatic GeoLite2 database downloads and updates
- Fast and reliable IP geolocation lookups
- Self-hosted solution with no external API dependencies
- Dual functionality: Python package and REST API
- Easy deployment with Docker and cloud platforms
- Get country, city, coordinates, timezone, ISP, and ASN data
- Beautiful, interactive demo UI for testing
- Built with FastAPI for high performance
- Automatic GeoLite2 database downloads and updates

## 🛠️ Usage
## Usage

### Python Package

Expand Down Expand Up @@ -67,18 +64,17 @@ print(result)
# }
```

### REST API

✅ Demo : https://geoip-api.malith.dev/

#### Simple Endpoints
#### Endpoints

```
# Simple path parameter
https://your-domain.com/8.8.8.8

# Query parameter
https://your-domain.com/?ip=8.8.8.8

# No parameter (uses the client's IP address)
https://your-domain.com/
```

#### Standard API Endpoint
Expand Down Expand Up @@ -106,21 +102,10 @@ https://your-domain.com/api/v1/geoip/lookup/8.8.8.8
}
```

## 📦 Deployment Options

### 🚀 Cloud Deployment

One-click deployment to popular platforms:

[![Deploy with heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)
[![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/Malith-Rukshan/geoip-api)

[![Deploy to Railway](https://railway.app/button.svg)](https://railway.app/template/6zn6HZ)
[![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/Malith-Rukshan/geoip-api)
## Deployment Options

### 🐳 Docker
### Docker

The fastest way to deploy your own GeoIP API:

```bash
docker pull malithrukshan/geoip-api
Expand Down Expand Up @@ -153,13 +138,13 @@ Then run:
docker-compose up -d
```

### 🔨 Building Docker Image Locally
### Building Docker Image Locally

If you want to build and run the Docker image from source:

1. Clone the repository
```bash
git clone https://github.com/Malith-Rukshan/geoip-api.git
git clone https://github.com/smp46/geoip-api.git
cd geoip-api
```
2. Build the Docker image
Expand All @@ -172,7 +157,7 @@ If you want to build and run the Docker image from source:
```
4. Access the API at http://localhost:8000

## 💻 Local Development
## Local Development

### Prerequisites

Expand All @@ -183,7 +168,7 @@ If you want to build and run the Docker image from source:

1. Clone the repository
```bash
git clone https://github.com/Malith-Rukshan/geoip-api.git
git clone https://github.com/smp46/geoip-api.git
cd geoip-api
```

Expand Down Expand Up @@ -215,50 +200,21 @@ black --check src tests api
mypy src tests api
```

## 🌐 Use Cases

- **Security & Compliance**: Enhance security systems with IP-based threat detection while maintaining data sovereignty
- **Content Localization**: Deliver region-specific content based on visitor location without sharing user data
- **Analytics**: Analyze traffic patterns and user demographics with geographic data that remains within your infrastructure
- **Fraud Prevention**: Identify suspicious login attempts based on geographic anomalies
- **Development Environment**: Use a local GeoIP service in your development environment without external API dependencies

## 📜 License
## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## ⚠️ Database License Notice
## Database License Notice

This project uses GeoLite2 data created by MaxMind, available from [https://www.maxmind.com](https://www.maxmind.com). The GeoLite2 databases are licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.

## 🔧 Acknowledgements
## Acknowledgements

- GeoLite2 databases provided by [MaxMind](https://www.maxmind.com)
- Mirror of GeoLite2 databases maintained by [P3TERX](https://github.com/P3TERX/GeoLite.mmdb)
- Built with [FastAPI](https://fastapi.tiangolo.com/) and [Python](https://www.python.org/)
- Powered by [geoip2](https://github.com/maxmind/GeoIP2-python) library

### 🇺🇳 Flags By : [Animated Country Flags](https://github.com/Malith-Rukshan/animated-country-flags)

## 🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## 🌟 Support and Community

If you found this project helpful, please give it a ⭐ on GitHub. This helps more developers discover the project! 🫶

## 📬 Contact

If you have any questions, feedback, or just want to say hi, you can reach out to me:

- Email: [[email protected]](mailto:[email protected])
- GitHub: [@Malith-Rukshan](https://github.com/Malith-Rukshan)
### Flags By : [Animated Country Flags](https://github.com/Malith-Rukshan/animated-country-flags)

🧑‍💻 Built with 💖 by [Malith Rukshan](https://github.com/Malith-Rukshan)
25 changes: 21 additions & 4 deletions api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from contextlib import asynccontextmanager
from ipaddress import ip_address as IPvAnyAddress
from typing import Optional
import re

from fastapi import Depends, FastAPI, HTTPException, Query, Request, status
from fastapi.middleware.cors import CORSMiddleware
Expand Down Expand Up @@ -59,6 +60,7 @@ async def lifespan(app: FastAPI):
title=API_TITLE,
description=API_DESCRIPTION,
version=API_VERSION,
proxy_headers=True,
docs_url="/docs",
redoc_url="/redoc",
lifespan=lifespan,
Expand Down Expand Up @@ -125,12 +127,27 @@ async def lookup_ip_query(
):
"""
Look up geolocation information using a query parameter.
Or the requesters IP address, if not otherwise provided.
"""
if ip is None:
# If no IP is provided, show the homepage
return templates.TemplateResponse(request, "index.html")

try:
if ip is None:
# Use requester's IP, if IP not provided
client = request.client
if client is not None:
ip = client.host
else:
# Handle the case where client is None
raise HTTPException(status_code=400, detail="Client IP not available")
# If IP is a Docker container IP, use X-Forwarded-For header
if re.match(
r"\b172\.(1[6-9]|[2-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.\d{1,3}\.\d{1,3}\b",
ip,
):
ip = request.headers.get("X-Forwarded-For")
# If IP is still None, return index page
if ip is None:
return templates.TemplateResponse(request, "index.html")

# Validate IP address format
IPvAnyAddress(ip)

Expand Down