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.
- 🔐 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
- PHP 8.1 or higher
- Laravel 10, 11, or 12
- Database (MySQL, PostgreSQL, SQLite, etc.)
You can install the package via Composer:
composer require forepath/laravel-s3-server
Publish the configuration file to customize the S3 server settings:
php artisan vendor:publish --provider="LaravelS3Server\S3ServiceProvider" --tag="s3server-config"
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.
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
]);
Your S3 server is now available at /s3/{bucket}/{key}
and supports all standard S3 operations!
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,
];
auth
: Set tofalse
to disable authentication (not recommended for production)auth_driver
: The authentication driver class to use
storage_driver
: The storage driver class to use for file operations
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 |
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
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'];
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
]);
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
// Get all credentials
$credentials = S3AccessCredential::all();
// Find by access key ID
$credential = S3AccessCredential::where('access_key_id', 'AKIAIOSFODNN7EXAMPLE')->first();
$credential = S3AccessCredential::where('access_key_id', 'AKIAIOSFODNN7EXAMPLE')->first();
$credential->update([
'description' => 'Updated description',
]);
$credential = S3AccessCredential::where('access_key_id', 'AKIAIOSFODNN7EXAMPLE')->first();
$credential->delete();
The package uses a driver-based authentication system. The default DatabaseAuthenticationDriver
authenticates requests using credentials stored in the database.
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,
The package uses a driver-based storage system. The default FileStorageDriver
stores files using Laravel's Storage facade.
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,
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.
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.
- 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
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
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',
]);
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
Problem: Files not being stored or retrieved
Solutions:
- Check Laravel's storage configuration
- Verify storage directory permissions
- Ensure the storage driver is properly configured
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
Problem: Database tables not created
Solutions:
- Run migrations:
php artisan migrate
- Check database connection
- Verify migration files are present
Enable debug mode to get more detailed error information:
// In config/s3server.php
'debug' => true,
We welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Clone your fork
- Install dependencies:
composer install
- Run tests:
composer test
- Make your changes
- Submit a pull request
This package follows Laravel's coding standards. We use Laravel Pint for code formatting:
./vendor/bin/pint
Please see CHANGELOG.md for more information on what has changed recently.
- Marcel Menk - Author
- ForePath - Company
- All Contributors
The MIT License (MIT). Please see License File for more information.
- Documentation: GitHub Wiki
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Built with ❤️ for the Laravel community