Blog / Create a backup of your Laravel project on Dropbox
5 min - 30 Oct 2024
TL;DR: How to quickly create a backup of a Laravel project and store it on Dropbox using Spatie Laravel-backup and Flysystem-dropbox packages.
A sample Laravel project can be found on this Github Repository. Find out more on Capsules or X.
In web project management, performing regular backups is essential to prevent permanent data loss. Various types of data require backups, including databases, user-generated files, or even files directly related to the web project itself.
Project files are often already managed by a version control system like Github or Gitlab. However, it’s generally not recommended to store user data there. Dropbox can be an excellent choice for securely storing this type of data.
Before transferring backups to Dropbox, it’s useful to generate them first. Spatie’s laravel-backup
package makes this task much simpler. Use the following command to install it :
composer require spatie/laravel-backup
Next, simply create the backup
configuration file to quickly set up the project backup :
config/backup.php
<?php
return [
'backup' => [
'name' => 'capsules',
'source' => [
'files' => [
'include' => [ base_path() ],
'exclude' => [ base_path( 'vendor' ), base_path( 'node_modules' ) ],
'relative_path' => null
],
'databases' => [ 'sqlite' ]
],
'database_dump_filename_base' => 'database',
'database_dump_file_extension' => '',
'destination' => [
'compression_method' => ZipArchive::CM_DEFAULT,
'compression_level' => 9,
'filename_prefix' => "backup-",
'disks' => [ 'local' ]
],
'temporary_directory' => '',
'password' => null,
'encryption' => 'default',
'tries' => 1,
'retry_delay' => 0,
]
];
To start the backup :
php artisan backup:run
Starting backup...
Dumping database /dropbox/database/database.sqlite...
Determining files to backup...
Zipping 110 files and directories...
Created zip containing 110 files and directories. Size is 112.76 KB
Copying zip to disk named local...
Successfully copied zip to disk named local.
Backup completed!
The php artisan backup:run
command creates a compressed backup that includes the items specified in the include
key while excluding those listed in exclude
. It also adds the specified databases
and stores everything in the folder defined by the name
key, naming the file with the filename_prefix
followed by the backup date in the format YYY-MM-DD-HH-mm-ss
. This backup is saved in the location set by the disks
key, which in this case is local
and redirects to storage/app/private
.
Additional configuration elements, not mentioned here above, are nonetheless essential for the proper functioning of the package.
storage
> app
> private
> capsules
- backup-2024-10-29-08-30-00.zip
- backup-2024-10-28-08-30-00.zip
...
With the backup procedure now operational, the next step is to link it to your Dropbox account. For this, we once again turn to Spatie and its flysystem-dropbox
package. As the name suggests, this is the Flysystem adapter for the Dropbox V2 API :
composer require spatie/flysystem-dropbox
A new configuration needs to be added to the filesystems
configuration file.
config/filesystems.php
<?php
return [
'disks' => [
...
'dropbox' => [
'driver' => 'dropbox',
'token_url' => env( 'DROPBOX_TOKEN_URL' ),
'refresh_token' => env( 'DROPBOX_REFRESH_TOKEN' )
]
]
];
Laravel backup
also needs to be linked to the new dropbox
disk. This is a good opportunity to adjust some additional settings.
<?php
return [
'backup' => [
...
'name' => '',
...
'destination' => [
...
'filename_prefix' => Illuminate\Support\Str::replace( '.', '-', env( 'DROPBOX_APP_NAME' ) ) . '-',
'disks' => [ 'dropbox' ]
],
...
]
];
name
key is left empty to avoid duplicating the folder name ith the Dropbox app, and the filename_prefix
now uses the DROPBOX_APP_NAME
environment variable instead of backup-
.It is now time to configure the Dropbox integration. The following steps detail the Dropbox setup process. Be aware that some steps may be overly complex.
A. Create a Dropbox Application :
Create app
Scoped access
App folder
Capsules Codes Article
Submit
B. Authorize Access :
Capsules Codes Article
app by modifying <YOUR_APP_KEY>
in the following url.https://www.dropbox.com/oauth2/authorize?client_id=<YOUR_APP_KEY>&response_type=code&token_access_type=offline
C. Generate the Required Token :
refresh_token
by replacing <ACCESS_CODE>
with the previously generated access code, along with <APP_KEY>
and <APP_SECRET>
found in the settings of the newly created app :curl https://api.dropbox.com/oauth2/token -d code=<ACCESS_CODE> -d grant_type=authorization_code -u <APP_KEY>:<APP_SECRET>
A response in the following format will appear, and a folder will be created in the Dropbox interface :
{"access_token": "sl.B48oJpRyl-FP61gr56g1GUa4G26L3TAQasMbiRRyuAGHpUQXz0hyeA4OrO8Zes6clhQxhA8dyFurNcx4_gwPXJb_K3ZZOfdzBIVwHieInx-EEFNgIc6ZOR3VMRjoOQ-Ske_QjGMePmzS", "token_type": "bearer", "expires_in": 14399, "refresh_token": "PKnAG5FX-ngAAAAAAAAAAVaXknd9i45Xk6t4-FrmXGjR4jWEljmBALOF3Xexp4AY", "scope": "account_info.read files.content.read files.content.write files.metadata.read files.metadata.write", "uid": "682879329", "account_id": "dbid:AADQ-j2-ihak-i0IwMiVS8F5-KhkcyTHyg8"}
The refresh_token
should be added to the application’s environment variables, along with the app_key
and app_secret
located in the settings of the newly created Dropbox application. These can then be added to the .env
file.
.env.example
DROPBOX_APP_NAME="Capsules Codes Article"
DROPBOX_APP_KEY=
DROPBOX_APP_SECRET=
DROPBOX_REFRESH_TOKEN=
DROPBOX_TOKEN_URL=https://${DROPBOX_APP_KEY}:${DROPBOX_APP_SECRET}@api.dropbox.com/oauth2/token
The final step is to create the service provider that will establish the connection to the Dropbox service : DropboxServiceProvider
.
app\Providers\DropboxServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\ServiceProvider;
use League\Flysystem\Filesystem;
use Spatie\Dropbox\Client as DropboxClient;
use Spatie\FlysystemDropbox\DropboxAdapter;
use GuzzleHttp\Client;
class DropboxServiceProvider extends ServiceProvider
{
public function boot(): void
{
Storage::extend( 'dropbox', function( Application $app, array $config )
{
$resource = ( new Client() )->post( $config[ 'token_url' ] , [ 'form_params' => [ 'grant_type' => 'refresh_token', 'refresh_token' => $config[ 'refresh_token' ] ] ]);
$accessToken = json_decode( $resource->getBody(), true )[ 'access_token' ];
$adapter = new DropboxAdapter( new DropboxClient( $accessToken ) );
return new FilesystemAdapter( new Filesystem( $adapter, $config ), $adapter, $config );
});
}
}
Do not forget to add it to the providers.php
.
bootstrap/providers.php
<?php
return [ App\Providers\DropboxServiceProvider::class ];
All that is left is to add the daily backup scheduling commands in the console.php
file.
routes/console.php
<?php
use Illuminate\Support\Facades\Schedule;
Schedule::command( 'backup:run' )->daily();
Schedule::command( 'backup:clean' )->daily();
daily
method, provided that a scheduler has been configured for the application. Without this daily command, the refresh_token
will expire. > php artisan backup:run
Starting backup...
Dumping database /article/database/database.sqlite...
Determining files to backup...
Zipping 35 files and directories...
Created zip containing 35 files and directories. Size is 36.74 KB
Copying zip to disk named dropbox...
Successfully copied zip to disk named dropbox.
Backup completed!
> php artisan backup:clean
Starting cleanup...
Cleaning backups of on disk dropbox...
Used storage after cleanup: 36.74 KB.
Cleanup completed!
Glad this helped.