In this port I will show you how to backup your Laravel application not only to the server where your application is running but also to remote FTP server or even to your local computer. Especially if you have application you update data quite often and you really cannot loose your data, you should consider making often backups and you really don’t want to do it manually.
Backup Package installation and configuration
First of all, we won’t write backup functionality from scratch. There is also great package to do this (assuming you are using Laravel 5.5 or higher) – Laravel Backup by Spatie. Start with running:
1 |
composer require spatie/laravel-backup |
and then
1 |
php artisan vendor:publish --provider="Spatie\Backup\BackupServiceProvider" |
Go to config/backup.php file and adjust some things. For my config in exclude I put:
1 2 3 4 5 |
'exclude' => [ base_path('vendor'), base_path('node_modules'), base_path('.env'), ], |
just to make sure .env file won’t leak any where. Assuming you want to make backup to remote FTP server it’s just extra security – in case anyone got access to this server, they still won’t have access to my password.
In disks I’ve set:
1 2 3 4 |
'disks' => [ 'local', 'ftp', ], |
Probably I’ve made some other small adjustments, so here is my complete file structure (after removing comments):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
<?php return [ 'backup' => [ 'name' => config('app.name'), 'source' => [ 'files' => [ 'include' => [ base_path(), ], 'exclude' => [ base_path('vendor'), base_path('node_modules'), base_path('.env'), ], 'followLinks' => false, ], 'databases' => [ 'mysql', ], ], 'database_dump_compressor' => null, 'destination' => [ 'filename_prefix' => '', 'disks' => [ 'local', 'ftp', ], ], 'temporary_directory' => storage_path('app/backup-temp'), ], 'notifications' => [ 'notifications' => [ \Spatie\Backup\Notifications\Notifications\BackupHasFailed::class => ['mail'], \Spatie\Backup\Notifications\Notifications\UnhealthyBackupWasFound::class => ['mail'], \Spatie\Backup\Notifications\Notifications\CleanupHasFailed::class => ['mail'], \Spatie\Backup\Notifications\Notifications\BackupWasSuccessful::class => ['mail'], \Spatie\Backup\Notifications\Notifications\HealthyBackupWasFound::class => ['mail'], \Spatie\Backup\Notifications\Notifications\CleanupWasSuccessful::class => ['mail'], ], 'notifiable' => \Spatie\Backup\Notifications\Notifiable::class, 'mail' => [ 'to' => 'PUT_YOUR_MAIL_HERE', ], 'slack' => [ 'webhook_url' => '', 'channel' => null, 'username' => null, 'icon' => null, ], ], 'monitorBackups' => [ [ 'name' => config('app.name'), 'disks' => ['local', 'ftp'], 'newestBackupsShouldNotBeOlderThanDays' => 1, 'storageUsedMayNotBeHigherThanMegabytes' => 5000, ], ], 'cleanup' => [ 'strategy' => \Spatie\Backup\Tasks\Cleanup\Strategies\DefaultStrategy::class, 'defaultStrategy' => [ 'keepAllBackupsForDays' => 7, 'keepDailyBackupsForDays' => 16, 'keepWeeklyBackupsForWeeks' => 8, 'keepMonthlyBackupsForMonths' => 4, 'keepYearlyBackupsForYears' => 2, 'deleteOldestBackupsWhenUsingMoreMegabytesThan' => 5000, ], ], ]; |
FTP configuration
Next thing is configuring your FTP connection. It’s pretty easy. Just go to config/filesystems.php and into disks
key put new driver, for example like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
'ftp' => [ 'driver' => 'ftp', 'host' => env('BACKUP_FTP_HOST'), 'username' => env('BACKUP_FTP_USERNAME'), 'password' => env('BACKUP_FTP_PASSWORD'), // Optional FTP Settings... // 'port' => 21, // 'root' => '', // 'passive' => true, // 'ssl' => true, // 'timeout' => 30, ], |
Testing and setting backups
Now, fill in .env with with your FTP server settings and now you should be able to run:
1 |
php artisan backup:run |
If you set everything in correct way it should work. If it doesn’t double check you have all the data correct, for me I was not able to set very strong FTP password (it didn’t work so I used something simpler).
When you confirm the above command really make backup in your FTP server and in your storage directory, you can now add into schedule method of your app/Console/Kernel.php file the following commands:
1 2 3 |
$schedule->command('backup:clean')->weekly()->at('01:00'); $schedule->command('backup:run')->twiceDaily(11, 23); $schedule->command('backup:monitor')->daily()->at('03:00'); |
Of course you should adjust frequency to your own needs and you should make sure you added to cron on your server Laravel scheduler.
Downloading backups to your local machine
So now, you should have your backups created both on FTP server and also on the server your application is running. This gives you quite big security, but you might also want to get copy on your local machine to put this for example into your NAS.
I personnaly use Mac, and I’ve created the following script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/bin/bash HOST='PUT_YOUR_FTP_HOST' USER='PUT_YOUR_FTP_USER' PASSWD='PUT_YOUR_FTP_PASSWORD' ftp -inv $HOST<<EOF quote USER $USER quote PASS $PASSWD bin cd /Path/On/Ftp lcd "/Volumes/Backup/MyApp" mget *.zip mdel *.zip bye EOF |
that will download backup from remote FTP and later remove those files from the FTP. So in case my Mac is turned off my backup will be on FTP, but when it’s on it will download backup to my local machine. If you want to not delete files from FTP, you can just remove mdel *.zip line. What is important here – files from FTP will be deleted no matter if saving backup to your local machine fails or not. In my case I download files from FTP to my location in this line:
1 |
lcd "/Volumes/Backup/MyApp" |
but this is not my NAS location, but local directory. No idea why, but sometimes when I had this script running in background I got info from my Mac that my NAS location was invalid, so file was not saved but it was removed from my FTP. Using path in your Mac machine seems to be much safer solution (at least in my case).
Last thing is of course saving above script and adding it into cron for example like this:
1 |
* * * * * /Users/marcin/Cron/ftp_backup.sh |
Of course you should test command before and make sure cron will be able to run this command without any problems (probably you should put your PATH variable into cron in some cases – at least I had to do it to make sure everything is running fine).
Summary
So to sum up, it’s pretty easy to make some decent backup solution for your Laravel application. Of course if you need more security, you could use more FTP servers, but in my case one is quite enough.