PHPackages                             vpndetector/laravel-vpn-detector - 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. vpndetector/laravel-vpn-detector

ActiveLibrary[Security](/categories/security)

vpndetector/laravel-vpn-detector
================================

VPN, proxy and Tor detection middleware for Laravel, powered by the IP2Proxy database.

1.0.0(1mo ago)10MITPHPPHP ^8.3CI passing

Since Jun 23Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/Crakenar/VpnCheckLaravelSdk)[ Packagist](https://packagist.org/packages/vpndetector/laravel-vpn-detector)[ RSS](/packages/vpndetector-laravel-vpn-detector/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (1)Dependencies (5)Versions (2)Used By (0)

🛡️ Laravel VPN Detector
=======================

[](#️-laravel-vpn-detector)

> Block VPN, proxy, and Tor traffic in your Laravel application — powered by the [IP2Proxy](https://www.ip2proxy.com/) PX2 database.

[![PHP](https://camo.githubusercontent.com/f276fa86a026b80ddb39a8c325682146659ba56cdc872905db20f421963fe47f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e332532422d3737374242343f6c6f676f3d706870)](https://www.php.net/)[![Laravel](https://camo.githubusercontent.com/3d9c6b5ae9bf4a266a0111ab622c86271130f96e4fd3062a0a44d8ad66cae46c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d31322e782d4646324432303f6c6f676f3d6c61726176656c)](https://laravel.com/)[![License](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)](#license)

---

What it does
------------

[](#what-it-does)

Laravel VPN Detector looks up every incoming request's IP address against a local copy of the IP2Proxy database and can:

- **Block requests** from VPN, public proxy, web proxy, or Tor nodes via a drop-in middleware
- **Force a logout** when an authenticated user switches to a Tor exit node mid-session
- **Keep the database fresh** automatically with a built-in Artisan command and scheduler integration

All lookups are done **in-process against your own database** — no external API calls at runtime, no latency overhead.

---

How it works
------------

[](#how-it-works)

```
Incoming request
       │
       ▼
 getClientIp()          Resolves the real IP:
                        CF-Connecting-IP → X-Forwarded-For → request()->ip()
       │
       ▼
 checkProxyType()       SELECT from ip2proxy_px2_ipv4/ipv6
                        WHERE INET_ATON(?) BETWEEN ip_from AND ip_to
       │
       ▼
 proxy_type?            VPN | TOR | PUB | WEB → blocked
                        null or other           → allowed

```

---

Requirements
------------

[](#requirements)

DependencyVersionPHP^8.3Laravel^12.0MySQL / MariaDBAny version supporting `INET_ATON` / `INET6_ATON`IP2Proxy accountFree tier works (PX2 database)---

Installation
------------

[](#installation)

### 1. Install via Composer

[](#1-install-via-composer)

```
composer require vpndetector/laravel-vpn-detector
```

### 2. Publish config and migrations

[](#2-publish-config-and-migrations)

```
# Publish the config file to config/vpn-detector.php
php artisan vendor:publish --tag=vpn-detector-config

# Publish the migrations
php artisan vendor:publish --tag=vpn-detector-migrations

# Run the migrations (creates ip2proxy_px2_ipv4 and ip2proxy_px2_ipv6 tables)
php artisan migrate
```

### 3. Set your IP2Proxy token

[](#3-set-your-ip2proxy-token)

Add your download token to `.env` (get it at [ip2location.com](https://www.ip2location.com)):

```
VPN_DETECTOR_IP2PROXY_TOKEN=your-token-here
```

### 4. Import the database

[](#4-import-the-database)

```
php artisan vpn-detector:update-database
```

This downloads the PX2 CSV files from IP2Proxy (~300 MB each), extracts them, and bulk-imports them into the two database tables. Expect it to take 2–5 minutes on first run.

---

Architecture
------------

[](#architecture)

The package is built around three layers:

```
VpnDetectionServiceInterface
        │
        ├── VpnDetectionService          (base: direct DB lookup)
        │
        └── CachedVpnDetectionService    (decorator: wraps base with a cache layer)
                │
                └── delegates to VpnDetectionService on cache miss

```

**`IpLookupResult` DTO** is returned by `checkProxyType()` instead of raw `stdClass`, giving you typed, expressive access to the result:

```
$result = app(VpnDetectionServiceInterface::class)->checkProxyType('1.2.3.4');

$result->isBlocked();       // true for VPN | TOR | PUB | WEB
$result->isVpn();
$result->isTor();
$result->isPublicProxy();
$result->isWebProxy();
$result->isClean();         // true when proxy_type === '-'
$result->toArray();         // ['ip', 'proxy_type', 'country_code', 'country_name', 'blocked']
```

The **`VpnDetector` Facade** provides a clean static interface:

```
use VpnDetector\Facades\VpnDetector;

VpnDetector::isUsingProxy();
VpnDetector::checkProxyType('1.2.3.4');
VpnDetector::getClientIp();
```

---

Configuration
-------------

[](#configuration)

After publishing, `config/vpn-detector.php` exposes:

```
return [
    // IP2Proxy download token (required for database updates)
    'ip2proxy_token' => env('VPN_DETECTOR_IP2PROXY_TOKEN'),

    // HTTP status returned by BlockVpnMiddleware (default: 403)
    'block_status_code' => env('VPN_DETECTOR_BLOCK_STATUS', 403),

    // Cache lookup results (strongly recommended in production)
    'cache' => [
        'enabled' => env('VPN_DETECTOR_CACHE_ENABLED', true),
        'store'   => env('VPN_DETECTOR_CACHE_STORE', null), // null = Laravel default
        'ttl'     => env('VPN_DETECTOR_CACHE_TTL', 3600),   // seconds
    ],

    // Scheduler settings for automatic database refresh
    'schedule' => [
        'frequency'           => env('VPN_DETECTOR_SCHEDULE_FREQUENCY', 'daily'),
        'daily_at'            => env('VPN_DETECTOR_SCHEDULE_AT', '02:00'),
        'timezone'            => env('VPN_DETECTOR_SCHEDULE_TIMEZONE', null),
        'environments'        => ['production', 'staging'],
        'without_overlapping' => true,
        'run_in_background'   => true,
    ],
];
```

Full list of `.env` keys: see [`.env.example`](.env.example).

---

Usage
-----

[](#usage)

### Middleware — block VPN/proxy users

[](#middleware--block-vpnproxy-users)

Register `BlockVpnMiddleware` on any route or group:

```
use VpnDetector\Http\Middleware\BlockVpnMiddleware;

// Single route
Route::get('/checkout', CheckoutController::class)
    ->middleware(BlockVpnMiddleware::class);

// Route group
Route::middleware(BlockVpnMiddleware::class)->group(function () {
    Route::get('/dashboard', DashboardController::class);
    Route::get('/account', AccountController::class);
});
```

Blocked requests receive a `403 Access via VPN or proxy is not permitted.` response.

---

### Action — force-logout Tor users

[](#action--force-logout-tor-users)

Use `CheckVpnBlocked` in your own middleware or controller when you want finer control (e.g. only log out authenticated Tor users):

```
use VpnDetector\Action\CheckVpnBlocked;

class EnsureNotTor
{
    public function handle(Request $request, Closure $next)
    {
        if (app(CheckVpnBlocked::class)->handle()) {
            return redirect()->route('login')->withErrors('Session terminated for security reasons.');
        }

        return $next($request);
    }
}
```

The IP is cached in the session so the database is only queried once per unique IP per session.

---

### Service — direct injection

[](#service--direct-injection)

Inject `VpnDetectionService` (or its interface) anywhere:

```
use VpnDetector\Contracts\VpnDetectionServiceInterface;

class SecurityController extends Controller
{
    public function __construct(private VpnDetectionServiceInterface $vpn) {}

    public function status(): JsonResponse
    {
        $ip    = $this->vpn->getClientIp();
        $entry = $this->vpn->checkProxyType($ip);

        return response()->json([
            'ip'         => $ip,
            'proxy_type' => $entry?->proxy_type,
            'country'    => $entry?->country_name,
            'blocked'    => $this->vpn->isUsingProxy(),
        ]);
    }
}
```

---

### Scheduler — keep the database fresh

[](#scheduler--keep-the-database-fresh)

Add `SchedulesVpnDetector` to your console kernel to automatically refresh the IP2Proxy data:

```
use VpnDetector\Traits\SchedulesVpnDetector;

class Kernel extends ConsoleKernel
{
    use SchedulesVpnDetector;

    protected function schedule(Schedule $schedule): void
    {
        // Uses frequency from config/vpn-detector.php (default: daily at 02:00)
        $this->scheduleVpnDetector($schedule);

        // Or use the production preset (daily at 02:00, background, no overlap)
        $this->scheduleVpnDetectorForProduction($schedule);

        // Or pass a custom cron expression
        $this->scheduleVpnDetector($schedule, '0 3 * * 0'); // every Sunday at 03:00
    }
}
```

---

Database tables
---------------

[](#database-tables)

The package creates two tables populated from the IP2Proxy PX2 dataset:

ColumnTypeDescription`ip_from`decimal(39,0)Start of IP range (integer representation)`ip_to`decimal(39,0)End of IP range`proxy_type`varchar(3)`VPN`, `TOR`, `PUB`, `WEB`, `-``country_code`char(2)ISO 3166-1 alpha-2`country_name`varchar(64)Full country nameBoth `ip_from` and `ip_to` form a composite primary key, allowing efficient range lookups via `INET_ATON` / `INET6_ATON`.

> **Note:** IP2Proxy recommends using the IPv6 table for both IPv4 and IPv6 queries, but coverage is incomplete in practice. This package queries both tables, routing by address family.

---

Benchmark
---------

[](#benchmark)

The package ships with a self-contained benchmark command. It **generates 6 000 000 synthetic rows** (3M IPv4 + 3M IPv6) into a temporary SQLite file, then measures lookup latency — no real IP2Proxy database or API token required.

```
# From the package directory (no host app needed)
php bin/benchmark

# Via Composer script
composer benchmark

# Inside a Laravel app (after installing the package)
php artisan vpn-detector:benchmark

# Options (same for all three entry points)
php bin/benchmark --rows=6000000 --iterations=2000
php bin/benchmark --rows=500000          # quick smoke test
php bin/benchmark --no-cache             # skip the cache scenario
php bin/benchmark --keep-db              # keep SQLite file for inspection
```

Example output (AMD Ryzen 7, SQLite — MySQL with proper indexes will be significantly faster):

```
  Laravel VPN Detector -- Benchmark
  ==================================
  Dataset     : 6,000,000 rows  (3,000,000 IPv4 + 3,000,000 IPv6)
  Iterations  : 1,000 per scenario
  Cache       : enabled (scenario 2)

  Generating 3000000 ipv4 rows...  3,000,000 rows in `ip2proxy_px2_ipv4`.
  Generating 3000000 ipv6 rows...  3,000,000 rows in `ip2proxy_px2_ipv6`.

  Test pool  : 6000 IPs (3000 IPv4 + 3000 IPv6)

  -- Scenario 1: Direct DB lookup (no cache) --

 1000/1000 [============================] 100%

+--------------+---------------+
| Metric       | Value         |
+--------------+---------------+
| Iterations   | 1,000         |
| DB hits      | 1,000         |
| DB misses    | 0             |
| Total time   | 58,526.344 ms |
| Average      | 58.526 ms     |
| Min          | 180.6 us      |
| P50 (median) | 57.965 ms     |
| P95          | 110.748 ms    |
| P99          | 114.839 ms    |
| Max          | 136.482 ms    |
+--------------+---------------+

  -- Scenario 2: Warm cache (array store) --

 1000/1000 [============================] 100%

+--------------+----------+
| Metric       | Value    |
+--------------+----------+
| Iterations   | 1,000    |
| DB hits      | 1,000    |
| DB misses    | 0        |
| Total time   | 2.854 ms |
| Average      | 2.9 us   |
| Min          | 2.3 us   |
| P50 (median) | 2.4 us   |
| P95          | 2.7 us   |
| P99          | 2.9 us   |
| Max          | 390.1 us |
+--------------+----------+

  Cache speedup: 20,507.5x faster (avg)
  Benchmark complete.

```

> These numbers use SQLite as the backend. Production MySQL/MariaDB with a real IP2Proxy dataset and proper indexes will have lower raw lookup latency; the cache speedup ratio (~20 000x) holds regardless of the database engine.

---

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance90

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community4

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

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

Unknown

Total

1

Last Release

45d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/a4c783e917131122a74f2ede5537fbdcf51c4d1075cecf43df7d339780559934?d=identicon)[Crakenar](/maintainers/Crakenar)

---

Tags

middlewarelaravelproxysecuritytorip2proxyvpn

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/vpndetector-laravel-vpn-detector/health.svg)

```
[![Health](https://phpackages.com/badges/vpndetector-laravel-vpn-detector/health.svg)](https://phpackages.com/packages/vpndetector-laravel-vpn-detector)
```

###  Alternatives

[statamic/cms

The Statamic CMS Core Package

4.9k3.8M1.1k](/packages/statamic-cms)[backpack/crud

Quickly build admin interfaces using Laravel, Bootstrap and JavaScript.

3.4k3.8M227](/packages/backpack-crud)[unopim/unopim

UnoPim Laravel PIM

10.8k2.5k](/packages/unopim-unopim)[bagisto/bagisto

Bagisto Laravel E-Commerce

28.0k175.2k9](/packages/bagisto-bagisto)[leantime/leantime

Open source project management system for non-project managers. Simple like Trello, powerful like Jira. Built with neurodiversity in mind.

10.2k4.0k](/packages/leantime-leantime)[akaunting/laravel-firewall

Web Application Firewall (WAF) package for Laravel

1.0k525.8k2](/packages/akaunting-laravel-firewall)

PHPackages © 2026

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