Configuration
Publishing Configuration
Section titled “Publishing Configuration”php artisan vendor:publish --tag="suspend-config"This creates config/suspend.php.
Primary Key Type
Section titled “Primary Key Type”Configure the primary key type for Suspend tables:
'primary_key_type' => 'id', // 'id', 'uuid', or 'ulid'| Type | Description |
|---|---|
id | Auto-incrementing integer (default) |
uuid | UUID v4 strings |
ulid | ULID strings (sortable) |
Note: Set this before running migrations.
Morph Types
Section titled “Morph Types”Configure how polymorphic relationships store model types:
// For context (suspended entities)'context_morph_type' => 'string', // 'string', 'numeric', 'uuid', 'ulid'
// For actors (suspended_by, revoked_by)'actor_morph_type' => 'string',Using numeric reduces storage but requires a morph map:
// In AppServiceProvideruse Illuminate\Database\Eloquent\Relations\Relation;
Relation::morphMap([ 1 => App\Models\User::class, 2 => App\Models\Organization::class,]);IP Resolvers
Section titled “IP Resolvers”Choose how client IP addresses are extracted:
use Cline\Suspend\Resolvers\Ip\StandardIpResolver;use Cline\Suspend\Resolvers\Ip\CloudflareIpResolver;use Cline\Suspend\Resolvers\Ip\AwsApiGatewayIpResolver;use Cline\Suspend\Resolvers\Ip\FastlyIpResolver;use Cline\Suspend\Resolvers\Ip\AkamaiIpResolver;use Cline\Suspend\Resolvers\Ip\TrustedProxyIpResolver;
'ip_resolver' => StandardIpResolver::class,| Resolver | Use When |
|---|---|
StandardIpResolver | Direct connections, standard proxies |
CloudflareIpResolver | Behind Cloudflare CDN |
AwsApiGatewayIpResolver | Behind AWS API Gateway/ALB |
FastlyIpResolver | Behind Fastly CDN |
AkamaiIpResolver | Behind Akamai CDN |
TrustedProxyIpResolver | Custom trusted proxy setup |
CDN-Specific Headers
Section titled “CDN-Specific Headers”Each CDN resolver reads the appropriate header:
- Cloudflare:
CF-Connecting-IP - AWS:
X-Forwarded-For(first IP) - Fastly:
Fastly-Client-IP - Akamai:
True-Client-IP
Geo Resolvers
Section titled “Geo Resolvers”Configure IP geolocation for country-based suspensions:
CDN-Based (Recommended)
Section titled “CDN-Based (Recommended)”Free, fast, no API limits - use headers from your CDN:
use Cline\Suspend\Resolvers\Geo\Cdn\CloudflareGeoResolver;use Cline\Suspend\Resolvers\Geo\Cdn\AwsCloudFrontGeoResolver;use Cline\Suspend\Resolvers\Geo\Cdn\FastlyGeoResolver;use Cline\Suspend\Resolvers\Geo\Cdn\AkamaiGeoResolver;use Cline\Suspend\Resolvers\Geo\Cdn\VercelGeoResolver;
'geo_resolver' => CloudflareGeoResolver::class,Local Database
Section titled “Local Database”Use MaxMind GeoLite2 or GeoIP2 database:
use Cline\Suspend\Resolvers\Geo\Local\MaxMindLocalGeoResolver;
'geo_resolver' => MaxMindLocalGeoResolver::class,
'maxmind_database' => storage_path('geoip/GeoLite2-City.mmdb'),Download the database from MaxMind.
Requires: composer require geoip2/geoip2
API-Based
Section titled “API-Based”Use third-party geolocation APIs:
use Cline\Suspend\Resolvers\Geo\Api\IpApiGeoResolver;use Cline\Suspend\Resolvers\Geo\Api\IpStackGeoResolver;use Cline\Suspend\Resolvers\Geo\Api\IpInfoGeoResolver;use Cline\Suspend\Resolvers\Geo\Api\IpDataGeoResolver;use Cline\Suspend\Resolvers\Geo\Api\Ip2LocationApiGeoResolver;use Cline\Suspend\Resolvers\Geo\Api\DbIpApiGeoResolver;use Cline\Suspend\Resolvers\Geo\Api\IpGeolocationIoGeoResolver;
'geo_resolver' => IpApiGeoResolver::class,Chain Resolver
Section titled “Chain Resolver”Use multiple resolvers with fallback:
use Cline\Suspend\Resolvers\ChainResolver;
'geo_resolver' => [ CloudflareGeoResolver::class, // Try CDN first (free) MaxMindLocalGeoResolver::class, // Fallback to local DB IpApiGeoResolver::class, // Fallback to API],Null Resolver
Section titled “Null Resolver”Disable geolocation entirely:
use Cline\Suspend\Resolvers\Geo\NullGeoResolver;
'geo_resolver' => NullGeoResolver::class, // DefaultAPI Keys
Section titled “API Keys”Configure API keys for geo services:
'api_keys' => [ 'ip_api' => env('SUSPEND_IP_API_KEY'), 'ipstack' => env('SUSPEND_IPSTACK_KEY'), 'ipinfo' => env('SUSPEND_IPINFO_TOKEN'), 'ipgeolocation_io' => env('SUSPEND_IPGEOLOCATION_IO_KEY'), 'ip2location' => env('SUSPEND_IP2LOCATION_KEY'), 'abstractapi' => env('SUSPEND_ABSTRACTAPI_KEY'), 'dbip' => env('SUSPEND_DBIP_KEY'), 'ipdata' => env('SUSPEND_IPDATA_KEY'),],Add to your .env:
SUSPEND_IP_API_KEY=your-key-hereSUSPEND_IPSTACK_KEY=your-key-hereGeo Cache TTL
Section titled “Geo Cache TTL”Cache geolocation results to reduce API calls:
'geo_cache_ttl' => 3600, // 1 hour, set to 0 to disableCustom Table Names
Section titled “Custom Table Names”Override default table names:
'tables' => [ 'suspensions' => 'my_suspensions',],Note: Set this before running migrations.
Middleware Configuration
Section titled “Middleware Configuration”Configure the built-in suspension middleware:
'middleware' => [ // Automatically check IP against suspensions 'check_ip' => true,
// Automatically check country against suspensions 'check_country' => false,
// HTTP response code when suspended 'response_code' => 403,
// Response message when suspended 'response_message' => 'Access denied. Your access has been suspended.',
// Routes to exclude from checks 'except' => [ 'login', 'logout', 'contact', 'suspended', ],],Environment Variables
Section titled “Environment Variables”Recommended environment variables:
# Primary key type (set before migrations)SUSPEND_PRIMARY_KEY_TYPE=id
# IP ResolutionSUSPEND_IP_RESOLVER=standard
# Geo ResolutionSUSPEND_GEO_RESOLVER=cloudflare
# MaxMind Database PathSUSPEND_MAXMIND_DATABASE=/path/to/GeoLite2-City.mmdb
# API Keys (only needed for API-based resolvers)SUSPEND_IP_API_KEY=SUSPEND_IPSTACK_KEY=SUSPEND_IPINFO_TOKEN=
# CacheSUSPEND_GEO_CACHE_TTL=3600Then in config:
'ip_resolver' => match(env('SUSPEND_IP_RESOLVER', 'standard')) { 'cloudflare' => CloudflareIpResolver::class, 'aws' => AwsApiGatewayIpResolver::class, 'fastly' => FastlyIpResolver::class, default => StandardIpResolver::class,},
'geo_resolver' => match(env('SUSPEND_GEO_RESOLVER', 'null')) { 'cloudflare' => CloudflareGeoResolver::class, 'maxmind' => MaxMindLocalGeoResolver::class, 'ip_api' => IpApiGeoResolver::class, default => NullGeoResolver::class,},Example Configurations
Section titled “Example Configurations”Simple Setup (No Geo)
Section titled “Simple Setup (No Geo)”return [ 'primary_key_type' => 'id', 'ip_resolver' => StandardIpResolver::class, 'geo_resolver' => NullGeoResolver::class,];Cloudflare Setup
Section titled “Cloudflare Setup”return [ 'primary_key_type' => 'ulid', 'ip_resolver' => CloudflareIpResolver::class, 'geo_resolver' => CloudflareGeoResolver::class,];Enterprise Setup with Fallbacks
Section titled “Enterprise Setup with Fallbacks”return [ 'primary_key_type' => 'uuid', 'context_morph_type' => 'uuid', 'actor_morph_type' => 'uuid',
'ip_resolver' => CloudflareIpResolver::class,
'geo_resolver' => [ CloudflareGeoResolver::class, MaxMindLocalGeoResolver::class, ],
'maxmind_database' => storage_path('geoip/GeoIP2-City.mmdb'),
'geo_cache_ttl' => 86400, // 24 hours
'middleware' => [ 'check_ip' => true, 'check_country' => true, 'response_code' => 403, 'except' => ['login', 'logout', 'suspended', 'api/health'], ],];