PHPackages                             bespredel/geo-restrict - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. bespredel/geo-restrict

ActiveLibrary[Security](/categories/security)

bespredel/geo-restrict
======================

Middleware to restrict access to Laravel applications based on IP geolocation.

v1.4.0(2mo ago)220MITPHPPHP &gt;=8.1CI passing

Since Jun 24Pushed 2mo agoCompare

[ Source](https://github.com/BespredeL/geo-restrict)[ Packagist](https://packagist.org/packages/bespredel/geo-restrict)[ RSS](/packages/bespredel-geo-restrict/feed)WikiDiscussions master Synced today

READMEChangelog (10)Dependencies (9)Versions (14)Used By (0)

GeoRestrict - Advanced GeoIP Middleware for Laravel
===================================================

[](#georestrict---advanced-geoip-middleware-for-laravel)

[![Readme EN](https://camo.githubusercontent.com/2e56ca214ef4d8d00bb5d7aa4ec232fc666ccba95fab518ecc19ef1c0aeaa1d6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f524541444d452d454e2d626c75652e737667)](https://github.com/BespredeL/geo-restrict/blob/master/README.md)[![Readme RU](https://camo.githubusercontent.com/9cc74b00b88d39864ca5656899377d910ba6cc1474e523d99f254eea0f1f6fd5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f524541444d452d52552d626c75652e737667)](https://github.com/BespredeL/geo-restrict/blob/master/README_RU.md)[![GitHub license](https://camo.githubusercontent.com/c8d21d6e069c319a1600e80cb1f98c211df3911b71f23aac373822690a19128d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d3435386137622e737667)](https://github.com/BespredeL/geo-restrict/blob/master/LICENSE)[![Downloads](https://camo.githubusercontent.com/0cf7e7fbb4abef867a6314572f90d92597dd1efeca6edb9df2a3586b56a78a10/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f62657370726564656c2f67656f2d72657374726963742e737667)](https://packagist.org/packages/bespredel/geo-restrict)

[![Latest Version](https://camo.githubusercontent.com/01551cb2018bdbb33c859e914cbbfd00bf9fa1e34379dc418fb2e3cb5de3b2e5/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f62657370726564656c2f47656f52657374726963743f6c6f676f3d676974687562)](https://github.com/BespredeL/geo-restrict/releases)[![Latest Version Packagist](https://camo.githubusercontent.com/221c613bfb7382a6914205a9ea81e88f9c71c44278a62a5e8d2a72720f33cdad/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f62657370726564656c2f67656f2d72657374726963742e7376673f6c6f676f3d7061636b6167697374266c6f676f436f6c6f723d776869746526636f6c6f723d463238443141)](https://packagist.org/packages/bespredel/geo-restrict)[![PHP from Packagist](https://camo.githubusercontent.com/0c639f14b9cafce8b83f1b6146c271943ba9bc1f6a08600081abb63aef3ae9b7/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f62657370726564656c2f67656f2d72657374726963742e7376673f6c6f676f3d706870266c6f676f436f6c6f723d776869746526636f6c6f723d373737424234)](https://php.net)[![Laravel Version](https://camo.githubusercontent.com/8c69c1fbc1927fe6fb505dafc30892d853d9b3ec54764dbaa88a1c6ffb03625e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d25334525334431302d4646324432303f6c6f676f3d6c61726176656c)](https://laravel.com)

🚀 Production-ready GeoIP access control for Laravel applications

GeoRestrict is a powerful and flexible Laravel middleware that allows you to control access to your application based on user geolocation.

It supports filtering by country, region, city, ASN, ISP, and provides advanced features like multi-provider fallback, caching, rate limiting, and flexible rule configuration.

---

✨ Features
----------

[](#-features)

- 🌍 Geo-based filtering (country, region, city, ASN, ISP)
- 🔀 Multiple GeoIP providers with fallback support
- ⚡ Built-in caching for performance optimization
- 🚦 Rate limiting for external GeoIP services
- 🧠 Flexible allow/deny rules with callbacks
- ⏱ Time-based access restrictions
- 📍 Route-level targeting (patterns + HTTP methods)
- 🛡 IP whitelist support
- 🌐 Multi-language error responses
- 📊 Logging for allowed and blocked requests

---

📦 Installation
--------------

[](#-installation)

1. Install the package via Composer::

```
composer require bespredel/geo-restrict
```

2. Publish the config file:

```
php artisan vendor:publish --provider="Bespredel\GeoRestrict\GeoRestrictServiceProvider" --tag=geo-restrict-config
```

3. (Optional) Publish language files for customization:

```
php artisan vendor:publish --provider="Bespredel\GeoRestrict\GeoRestrictServiceProvider" --tag=geo-restrict-lang
```

---

⚙️ Configuration
----------------

[](#️-configuration)

The configuration file allows you to fully customize how GeoRestrict behaves.

**Example:**

```
return [
    'services' => [
        // Example provider with options
        [
            'provider' => \Bespredel\GeoRestrict\Providers\Ip2LocationIoProvider::class,
            'options'  => [
                'api_key' => 'your-ip2location-api-key', // required
                'lang'    => 'en', // optional
            ],
        ],

        // Example provider without options
        \Bespredel\GeoRestrict\Providers\IpWhoIsProvider::class,

        // or
        [
            'provider' => \Bespredel\GeoRestrict\Providers\IpWhoIsProvider::class,
            'options'  => [],
        ],

        // Example array provider
        [
            'name' => 'ipapi.co',
            'url'  => 'https://ipapi.co/:ip/json/',
            'headers' => [
                'Accept' => 'application/json',
            ],
            'map'  => [
                'country' => 'country_code',
                'region'  => 'region_code',
                'city'    => 'city',
                'asn'     => 'asn',
                'isp'     => 'org',
            ],
        ],

        // Add more services; priority is based on order
    ],

    'geo_services' => [
        'cache_ttl'  => 1440,
        'rate_limit' => 30,
        'provider_timeout' => 5,
        'provider_retries' => 0,
        'provider_retry_delay_ms' => 150,
    ],

    'access' => [
        'rules' => [
            'allow' => [
                'country'  => ['RU'],
                'region'   => [],
                'city'     => [],
                'asn'      => [],
                'callback' => null, // function($geo) { return ...; }
                'time'     => [
                    // ['from' => '08:00', 'to' => '20:00']
                ],
            ],
            'deny'  => [
                'country'  => [],
                'region'   => [],
                'city'     => [],
                'asn'      => [],
                'callback' => null, // function($geo) { return ...; }
                'time'     => [
                    // ['from' => '22:00', 'to' => '06:00']
                ],
            ],
        ],
    ],

    'routes' => [
        'only'    => [], // ['admin/*', 'api/v1/*']
        'except'  => [],
        'methods' => [], // ['GET', 'POST']
    ],

    'excluded_networks' => [
        '127.0.0.1',
        '::1',
        '10.0.0.0/8',
        '192.168.0.0/16',
        '172.16.0.0/12',
        // Add more as needed
    ],

    'logging' => [
        'blocked_requests' => true,
        'allowed_requests' => false,
        'channel' => 'geo-restrict', // Use your custom channel name
    ],

    'observability' => [
        'log_cache_hits' => false,
        'log_provider_latency' => false,
        'log_deny_reasons' => false,
    ],

    'block_response' => [
        'type'  => 'abort', // 'abort', 'json', 'view'
        'view'  => 'errors.geo_blocked',
        'json'  => [
            'message' => 'Access denied: your region is restricted.',
        ],
    ]
];
```

---

### Key parameters explained

[](#key-parameters-explained)

- **services** - list of geo-services used to resolve location by IP. Each provider supports only its documented parameters (see table below).
- **geo\_services.cache\_ttl** - cache lifetime in minutes (0 disables caching).
- **geo\_services.rate\_limit** - max requests per minute per IP to geo services.
- **geo\_services.provider\_timeout/provider\_retries** - provider timeout and retry policy.
- **access.rules.allow/deny** - allow/deny rules by country, region, ASN, callbacks and time periods.
- **logging** - enable logging of blocked or allowed requests.
- **observability** - optional debug diagnostics for cache hits, latency and deny reasons.
- **block\_response.type** - response type: 'abort', 'json', or 'view'.
- **routes.only/except/methods** - route and method matching.
- **excluded\_networks** - list of IP networks to exclude from geo restriction.

---

#### Supported Providers and Parameters

[](#supported-providers-and-parameters)

ProviderClassRequired ParamsOptional ParamsIP2Location.ioIp2LocationIoProviderapi\_key, iplangipwho.isIpWhoIsProvideripapi\_keyip-api.comIpApiComProvideriplangipapi.coIpApiCoProvideriplangOnly parameters listed in `requiredParams` and `optionalParams` for each provider will be used in the request. If a required parameter is missing, an error will be thrown and logged. Optional parameters are included only if set in config.

---

### Provider architecture

[](#provider-architecture)

All geo providers now inherit from `AbstractGeoProvider` and only need to define:

- `baseUrl`, `endpoint` (with :param placeholders)
- `requiredParams`, `optionalParams`
- `responseMap` (array for mapping API fields to standard keys)
- `isValidResponse(array $data)` (checks if API response is valid)
- `getErrorMessage(array $data)` (returns error message for invalid response)

**Example of a minimal provider:**

```
class ExampleProvider extends AbstractGeoProvider {
    protected ?string $baseUrl = 'https://example.com/';
    protected ?string $endpoint = 'api/:ip';
    protected array $requiredParams = ['ip'];
    protected array $optionalParams = ['lang'];
    protected array $responseMap = [
        'country' => 'country_code',
        'region'  => 'region',
        'city'    => 'city',
        'asn'     => 'asn',
        'isp'     => 'isp',
    ];
    protected function isValidResponse(array $data): bool {
        return isset($data['country_code']);
    }
    protected function getErrorMessage(array $data): string {
        return 'example.com: invalid response';
    }
    public function getName(): string { return 'example.com'; }
}
```

This makes it easy to add new providers and ensures all logic is unified and DRY.

### Compatibility notes

[](#compatibility-notes)

- `GeoAccess::passesRules()` is still available for backward compatibility.
- New code can use `GeoAccess::evaluateRules()` for a structured rule-check result.

---

🚀 Usage
-------

[](#-usage)

1. Add the middleware to routes:

```
Route::middleware(['geo-restrict'])->group(function () {
    // ...
});
```

2. Or apply directly:

```
Route::get('/secret', 'SecretController@index')->middleware('geo-restrict');
```

---

🔧 Customization
---------------

[](#-customization)

- Add your geo-services to the `services` array; order defines priority.
- Use allow/deny rules for flexible filtering.
- For complex cases, use callback functions in rules.
- For localization, use language files.

---

🌐 Localization and Language Files
---------------------------------

[](#-localization-and-language-files)

GeoRestrict supports multi-language block messages. To customize or add new translations:

1. Publish the language files:

```
php artisan vendor:publish --provider="Bespredel\GeoRestrict\GeoRestrictServiceProvider" --tag=geo-restrict-lang
```

2. Edit files in `resources/lang/vendor/geo-restrict/` as needed. Add new locales by creating new folders (e.g., `it`, `es`).

- The block message is automatically shown in the user's country language (based on the country code, if a corresponding language file exists), or in the application's default language.
- To add a new language, create a file like:

```
resources/lang/it/messages.php

```

No code changes are required - the language is detected automatically based on the country code (e.g., IT, FR, DE, RU, EN, etc.).

---

⚡ Cache Management &amp; Tag-based Cache Flush
----------------------------------------------

[](#-cache-management--tag-based-cache-flush)

GeoRestrict uses Laravel's cache for geo-data and rate limiting. If your cache driver supports tags (Redis, Memcached), all geoip cache entries are tagged with `geoip`.

- To flush all geoip cache entries at once, use the artisan command:

```
php artisan geo-restrict:clear-cache
```

You will see:

```
GeoIP cache flushed.

```

> **Note:** Tag-based cache flush is only available for Redis and Memcached drivers. For other drivers, cache will not be flushed in bulk.

---

📊 Logging: Custom Channel Support
---------------------------------

[](#-logging-custom-channel-support)

GeoRestrict supports logging to a custom channel. By default, all logs (blocked/allowed requests, provider errors, rate limits) go to the main Laravel log. To use a separate channel, set the `logging.channel` parameter in your `config/geo-restrict.php`:

```
'logging' => [
    'blocked_requests' => true,
    'allowed_requests' => false,
    'channel' => 'geo-restrict', // Use your custom channel name
],
```

Add a channel to your `config/logging.php`:

```
'channels' => [
    // ...
    'geo-restrict' => [
        'driver' => 'single',
        'path' => storage_path('logs/geo-restrict.log'),
        'level' => 'info',
    ],
],
```

If `channel` is not set or is `null`, logs will go to the default log channel.

---

📄 License
---------

[](#-license)

This package is open-source software licensed under the MIT license.

---

⭐ Support
---------

[](#-support)

If you find this package useful, consider giving it a star ⭐ on GitHub.

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance86

Actively maintained with recent releases

Popularity10

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~27 days

Recently: every ~62 days

Total

12

Last Release

69d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/3052150?v=4)[Aleksandr Kireev](/maintainers/BespredeL)[@BespredeL](https://github.com/BespredeL)

---

Top Contributors

[![BespredeL](https://avatars.githubusercontent.com/u/3052150?v=4)](https://github.com/BespredeL "BespredeL (61 commits)")

---

Tags

access-controlapi-securitycountry-blockinggeo-blockinggeo-restrictiongeoipgeoip-filtergeolocationip-filteringip-geolocationip-securitylaravellaravel-middlewarelaravel-packagelaravel-securitymiddlewarerate-limitingsaas-securitymiddlewarelaravelgeoipaccessIPlocationgeorestriction

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/bespredel-geo-restrict/health.svg)

```
[![Health](https://phpackages.com/badges/bespredel-geo-restrict/health.svg)](https://phpackages.com/packages/bespredel-geo-restrict)
```

###  Alternatives

[stevebauman/location

Retrieve a user's location by their IP Address

1.3k8.5M90](/packages/stevebauman-location)[hibit-dev/geodetect

Automatically detect user's geo data based on their IP address

2322.8k](/packages/hibit-dev-geodetect)[interaction-design-foundation/laravel-geoip

Support for multiple Geographical Location services.

19267.9k3](/packages/interaction-design-foundation-laravel-geoip)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
