forepath / laravel-s3-server
Lightweight Laravel-compatible S3 protocol server
Requires
- php: ^8.1
- laravel/framework: ^10|^11|^12
Requires (Dev)
- laravel/pint: ^1.13
- phpstan/phpstan: ^1.10
README
A lightweight, Laravel-compatible Amazon S3 protocol server that allows you to run your own S3-compatible storage service within your Laravel application. Perfect for development, testing, or self-hosted storage solutions.
Features
- 🔐 Full S3 Protocol Support - Compatible with AWS S3 API v4
- 🔐 Secure Authentication - AWS Signature Version 4 (AWS4-HMAC-SHA256) authentication
- 💾 Database-Backed Credentials - Store and manage S3 credentials in your database
- 🔒 Bucket-Level Access Control - Restrict credentials to specific buckets for enhanced security
- 🔒 Encrypted Storage - Secret keys are automatically encrypted using Laravel's encryption
- 🔒 Flexible Storage Drivers - File-based storage with extensible driver system
- 🛡️ Laravel Integration - Seamless integration with Laravel's service container
- ⚡ Lightweight - Minimal overhead, maximum performance
- 🔒 Production Ready - Built with security and reliability in mind
Requirements
- PHP 8.1 or higher
- Laravel 10, 11, or 12
- Database (MySQL, PostgreSQL, SQLite, etc.)
Installation
You can install the package via Composer:
composer require forepath/laravel-s3-server
Quick Start
1. Publish Configuration
Publish the configuration file to customize the S3 server settings:
php artisan vendor:publish --provider="LaravelS3Server\S3ServiceProvider" --tag="s3server-config"
2. Run Migrations
Run the migrations to create the necessary database tables:
php artisan migrate
This will create the s3_access_credentials
table with support for bucket restrictions.
3. Create S3 Credentials
Add S3 credentials to your database:
use LaravelS3Server\Models\S3AccessCredential; S3AccessCredential::create([ 'access_key_id' => 'AKIAIOSFODNN7EXAMPLE', 'secret_access_key' => 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', 'description' => 'Development credentials', 'bucket' => null, // Optional: restrict to specific bucket ]);
4. Start Using S3
Your S3 server is now available at /s3/{bucket}/{key}
and supports all standard S3 operations!
Configuration
The configuration file is located at config/s3server.php
:
return [ // Enable/disable authentication 'auth' => true, // Authentication driver class 'auth_driver' => LaravelS3Server\Drivers\DatabaseAuthenticationDriver::class, // Storage driver class 'storage_driver' => LaravelS3Server\Drivers\FileStorageDriver::class, ];
Authentication Settings
auth
: Set tofalse
to disable authentication (not recommended for production)auth_driver
: The authentication driver class to use
Storage Settings
storage_driver
: The storage driver class to use for file operations
Usage
S3 API Endpoints
The package automatically registers the following S3-compatible endpoints:
Method | Endpoint | Description |
---|---|---|
PUT |
/s3/{bucket}/{key} |
Upload an object |
GET |
/s3/{bucket}/{key} |
Download an object |
GET |
/s3/{bucket} |
List bucket contents |
DELETE |
/s3/{bucket}/{key} |
Delete an object |
Using with AWS CLI
Configure AWS CLI to use your local S3 server:
aws configure set aws_access_key_id AKIAIOSFODNN7EXAMPLE aws configure set aws_secret_access_key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY aws configure set region us-east-1 aws configure set endpoint_url http://localhost:8000/s3
Using with AWS SDK
use Aws\S3\S3Client; $s3Client = new S3Client([ 'version' => 'latest', 'region' => 'us-east-1', 'endpoint' => 'http://localhost:8000/s3', 'use_path_style_endpoint' => true, 'credentials' => [ 'key' => 'AKIAIOSFODNN7EXAMPLE', 'secret' => 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', ], ]); // Upload a file $s3Client->putObject([ 'Bucket' => 'my-bucket', 'Key' => 'example.txt', 'Body' => 'Hello, World!', ]); // Download a file $result = $s3Client->getObject([ 'Bucket' => 'my-bucket', 'Key' => 'example.txt', ]); echo $result['Body'];
Managing Credentials
Creating Credentials
use LaravelS3Server\Models\S3AccessCredential; // Create a new credential with access to any bucket $credential = S3AccessCredential::create([ 'access_key_id' => 'AKIAIOSFODNN7EXAMPLE', 'secret_access_key' => 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', 'description' => 'Development credentials', 'bucket' => null, // null means access to any bucket ]); // Create a credential restricted to a specific bucket $restrictedCredential = S3AccessCredential::create([ 'access_key_id' => 'AKIAIOSFODNN7EXAMPLE2', 'secret_access_key' => 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY2', 'description' => 'Production credentials for user-uploads bucket', 'bucket' => 'user-uploads', // Only access to 'user-uploads' bucket ]);
Bucket Restrictions
The S3 server supports bucket-level access control. You can restrict credentials to access only specific buckets:
- No Restriction: Set
bucket
tonull
to allow access to any bucket - Single Bucket: Set
bucket
to a specific bucket name to restrict access to only that bucket - Security: Credentials with bucket restrictions will receive 401 Unauthorized when trying to access other buckets
Listing Credentials
// Get all credentials $credentials = S3AccessCredential::all(); // Find by access key ID $credential = S3AccessCredential::where('access_key_id', 'AKIAIOSFODNN7EXAMPLE')->first();
Updating Credentials
$credential = S3AccessCredential::where('access_key_id', 'AKIAIOSFODNN7EXAMPLE')->first(); $credential->update([ 'description' => 'Updated description', ]);
Deleting Credentials
$credential = S3AccessCredential::where('access_key_id', 'AKIAIOSFODNN7EXAMPLE')->first(); $credential->delete();
Architecture
Authentication Drivers
The package uses a driver-based authentication system. The default DatabaseAuthenticationDriver
authenticates requests using credentials stored in the database.
Custom Authentication Driver
Create a custom authentication driver by implementing the AuthenticationDriver
:
<?php namespace App\Services; use Illuminate\Http\Request; use LaravelS3Server\Contracts\AuthenticationDriver; class CustomAuthDriver implements AuthenticationDriver { public function authenticate(Request $request): bool { // Your custom authentication logic return true; } public function getSecretKeyByAccessKeyId(string $accessKeyId): ?string { // Return the secret key for the given access key ID return 'your-secret-key'; } }
Then update your configuration:
'auth_driver' => App\Services\CustomAuthDriver::class,
Storage Drivers
The package uses a driver-based storage system. The default FileStorageDriver
stores files using Laravel's Storage facade.
Custom Storage Driver
Create a custom storage driver by implementing the S3StorageDriver
interface:
<?php namespace App\Services; use LaravelS3Server\Contracts\S3StorageDriver; class CustomStorageDriver implements S3StorageDriver { public function put(string $path, string $content): void { // Store the file } public function get(string $path): ?string { // Retrieve the file content return null; } public function delete(string $path): void { // Delete the file } public function list(string $prefix): array { // List files in the prefix return []; } }
Then update your configuration:
'storage_driver' => App\Services\CustomStorageDriver::class,
Security
Credential Encryption
All secret access keys are automatically encrypted using Laravel's built-in encryption system. The encryption uses your application's APP_KEY
and AES-256-CBC encryption.
Authentication
The package implements AWS Signature Version 4 (AWS4-HMAC-SHA256) authentication, which is the same authentication method used by AWS S3. This ensures compatibility with all S3 clients and SDKs.
Best Practices
- Use HTTPS in Production: Always use HTTPS when deploying to production
- Rotate Credentials: Regularly rotate your S3 credentials
- Monitor Access: Implement logging to monitor S3 access
- Backup APP_KEY: Ensure your
APP_KEY
is backed up securely - Limit Permissions: Use the principle of least privilege
Testing
Manual Testing
You can test the S3 server using the AWS CLI:
# List buckets (will show bucket-like directories) aws s3 ls s3:// --endpoint-url http://localhost:8000/s3 # Create a bucket (upload a file to create the bucket) aws s3 cp test.txt s3://my-bucket/test.txt --endpoint-url http://localhost:8000/s3 # List bucket contents aws s3 ls s3://my-bucket/ --endpoint-url http://localhost:8000/s3 # Download a file aws s3 cp s3://my-bucket/test.txt downloaded.txt --endpoint-url http://localhost:8000/s3 # Delete a file aws s3 rm s3://my-bucket/test.txt --endpoint-url http://localhost:8000/s3
Programmatic Testing
use LaravelS3Server\Models\S3AccessCredential; // Create test credentials with bucket restriction S3AccessCredential::create([ 'access_key_id' => 'test-key', 'secret_access_key' => 'test-secret', 'description' => 'Test credentials for test-bucket', 'bucket' => 'test-bucket', ]); // Test with AWS SDK $s3Client = new S3Client([ 'version' => 'latest', 'region' => 'us-east-1', 'endpoint' => 'http://localhost:8000/s3', 'use_path_style_endpoint' => true, 'credentials' => [ 'key' => 'test-key', 'secret' => 'test-secret', ], ]); // Test upload $s3Client->putObject([ 'Bucket' => 'test-bucket', 'Key' => 'test.txt', 'Body' => 'Test content', ]);
Troubleshooting
Common Issues
1. Authentication Failures
Problem: Getting 401 Unauthorized errors
Solutions:
- Verify credentials exist in the database
- Check that the access key ID matches exactly
- Ensure the request includes proper AWS Signature Version 4 headers
- Verify your
APP_KEY
is set correctly
2. File Storage Issues
Problem: Files not being stored or retrieved
Solutions:
- Check Laravel's storage configuration
- Verify storage directory permissions
- Ensure the storage driver is properly configured
3. Configuration Issues
Problem: Configuration not being loaded
Solutions:
- Publish the configuration file:
php artisan vendor:publish --provider="LaravelS3Server\S3ServiceProvider" --tag="s3server-config"
- Clear configuration cache:
php artisan config:clear
- Verify the service provider is registered
4. Migration Issues
Problem: Database tables not created
Solutions:
- Run migrations:
php artisan migrate
- Check database connection
- Verify migration files are present
Debug Mode
Enable debug mode to get more detailed error information:
// In config/s3server.php 'debug' => true,
Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
- Fork the repository
- Clone your fork
- Install dependencies:
composer install
- Run tests:
composer test
- Make your changes
- Submit a pull request
Code Style
This package follows Laravel's coding standards. We use Laravel Pint for code formatting:
./vendor/bin/pint
Changelog
Please see CHANGELOG.md for more information on what has changed recently.
Credits
- Marcel Menk - Author
- ForePath - Company
- All Contributors
License
The MIT License (MIT). Please see License File for more information.
Support
- Documentation: GitHub Wiki
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Built with ❤️ for the Laravel community