spatie/laravel-backup-server
Receive, store, and manage encrypted backups from multiple Laravel apps on a dedicated backup server. Built on top of spatie/laravel-backup, it centralizes backup uploads, retention, and monitoring for safer off-site storage.
composer require spatie/laravel-backup-server
php artisan vendor:publish --provider="Spatie\BackupServer\BackupServerServiceProvider" --tag="config"
config/backup-server.php):
'storage' => storage_path('app/backups'),
'allowed_clients' => ['client1.example.com', 'client2.example.com'],
config/backup-server.php):
'server_url' => 'https://backup.example.com',
'client_id' => 'client1.example.com',
'client_secret' => env('BACKUP_CLIENT_SECRET'),
laravel-backup:
php artisan backup:run
app/Console/Kernel.php:
protected function schedule(Schedule $schedule)
{
$schedule->command('backup:run')->daily();
$schedule->command('backup-server:upload')->after('backup:run');
}
Client-Side:
laravel-backup to generate backups locally.backup-server to upload to the central server:
'backup_server' => [
'enabled' => true,
'upload_after_backup' => true,
],
Server-Side:
storage/backups/{client_id}/{backup_name}.zip).allowed_clients in config.'retention' => [
'keep_backups' => 30,
'keep_days' => 365,
],
BACKUP_CLIENT_SECRET).staging, production, etc., with distinct client_ids.'backup_server' => [
'tags' => ['production', 'database'],
],
\Log::info('Backup uploaded to server', ['client' => $clientId, 'backup' => $backupName]);
Route::get('/backup-health', function () {
return response()->json(['status' => \Spatie\BackupServer\BackupServer::checkHealth()]);
});
Authentication Failures:
client_id and client_secret match the server’s allowed_clients and their respective secrets.403 Forbidden errors if uploads fail silently.Storage Permissions:
storage/backups directory must be writable by the web server user (e.g., www-data or nginx).chmod -R 755 storage/backups or adjust ownership:
sudo chown -R www-data:www-data storage/backups
Large Backup Files:
max_execution_time or post_max_size.php.ini or split backups into smaller chunks using laravel-backup's split_backup option.Client-Side Configuration Overrides:
config/backup-server.php override server defaults. Test locally before deploying:
'server_url' => env('BACKUP_SERVER_URL', 'https://backup.example.com'),
Enable Verbose Logging:
Add to config/logging.php:
'channels' => [
'backup' => [
'driver' => 'single',
'path' => storage_path('logs/backup.log'),
'level' => 'debug',
],
],
Then log manually:
\Log::debug('Backup upload started', ['data' => $backupData]);
Test Uploads Locally:
Use the backup-server:test-upload command to simulate uploads without affecting production:
php artisan backup-server:test-upload --client=client1.example.com
Custom Storage:
Override the default storage by binding a custom Spatie\BackupServer\Storage\Storage implementation in the server’s AppServiceProvider:
public function register()
{
$this->app->bind(
\Spatie\BackupServer\Storage\Storage::class,
\App\CustomBackupStorage::class
);
}
Pre/Post-Processing:
Extend the BackupServer class to add logic before/after uploads:
namespace App\Services;
use Spatie\BackupServer\BackupServer as BaseBackupServer;
class BackupServer extends BaseBackupServer
{
protected function beforeUpload($backup)
{
// Encrypt the backup before upload
$this->encryptBackup($backup);
}
}
Then bind it in AppServiceProvider:
$this->app->bind(\Spatie\BackupServer\BackupServer::class, \App\Services\BackupServer::class);
Web Interface:
Use the backup-server:list command to build a custom dashboard for managing backups:
Route::get('/backups', function () {
return \Spatie\BackupServer\BackupServer::listBackups();
});
How can I help you explore Laravel packages today?