If you’re running a Laravel app and want an easy way to back it up to Azure Blob Storage without Docker images or third-party SaaS tools, here’s a self-contained Bash script that does exactly that.
It backs up:
- Your Laravel project files (with exclusions like
vendor/andlogs) - Your MySQL database (via
mysqldump) - Packages everything into a
.tar.gz - Uploads to Azure Blob Storage using
az CLI - Cleans up local backups older than X days
Requirements
bash,tar,gzip,findmysqldump(MySQL/MariaDB client)- Azure CLI
The Script
#!/usr/bin/env bashset-Eeuo pipefail# ---- Paths ----LARAVEL_DIR="/path/to/laravel/project"# Path to your Laravel project rootBACKUP_DIR="/path/to/local/backup/directory"# Local backup directory# ---- Azure Storage (account + key) ----AZURE_STORAGE_ACCOUNT="<ACCOUNT_NAME>"AZURE_STORAGE_KEY="<ACCOUNT-KEY>"AZURE_CONTAINER="<CONTAINER-NAME>"# ---- Retention (local only) ----RETAIN_LOCAL_DAYS=7# ---- Backup content exclusion ----EXCLUDES=("vendor""node_modules""storage/framework/cache""storage/logs"".git")#############################################timestamp_utc(){date-u +"%Y%m%dT%H%M%SZ";}require_cmd(){command-v"$1">/dev/null 2>&1||{echo"ERROR: Missing required command:$1">&2;exit1;}}read_env_var(){localkey="$1"localval=""if[[-f"$LARAVEL_DIR/.env"]];thenval="$(grep-E"^${key}=""$LARAVEL_DIR/.env" 2>/dev/null |tail-n1 |sed-E"s/^${key}=(.*)$/\1/" |tr-d'\r'||true)"fi if[[-n"$val"&&"${val:0:1}"=='"'&&"${val: -1}"=='"']];thenval="${val:1:-1}"elif[[-n"$val"&&"${val:0:1}"=="'"&&"${val: -1}"=="'"]];thenval="${val:1:-1}"fiecho"$val"}dump_mysql(){localdb_host db_port db_name db_user db_pass db_socket dump_pathdb_host="$(read_env_var"DB_HOST")"db_port="$(read_env_var"DB_PORT")"db_name="$(read_env_var"DB_DATABASE")"db_user="$(read_env_var"DB_USERNAME")"db_pass="$(read_env_var"DB_PASSWORD")"db_socket="$(read_env_var"DB_SOCKET")"dump_path="$1" require_cmd mysqldumpdb_host="${db_host:-127.0.0.1}"db_port="${db_port:-3306}"localargs=(--user="$db_user"--single-transaction--quick--routines--events--triggers)if[[-n"$db_socket"]];thenargs+=(--socket="$db_socket")elseargs+=(--host="$db_host"--port="$db_port")fiumask077MYSQL_PWD="$db_pass" mysqldump"${args[@]}""$db_name">"$dump_path"}make_archive(){localsrc_dir="$1"localdb_sql="$2"localout_tar_gz="$3"localstagestage="$(mktemp-d)"trap'rm -rf "$stage"' RETURNmkdir-p"$stage/site""$stage/db"pushd"$src_dir">/dev/nulllocaltar_excludes=()forein"${EXCLUDES[@]}";dotar_excludes+=("--exclude=$e")donetar-cf -"${tar_excludes[@]}". |tar-C"$stage/site"-xf -popd>/dev/nullcp"$db_sql""$stage/db/database.sql"tar-C"$stage"-czf"$out_tar_gz" site db}upload_with_azcli(){localfile="$1"AZURE_STORAGE_ACCOUNT="$AZURE_STORAGE_ACCOUNT"AZURE_STORAGE_KEY="$AZURE_STORAGE_KEY"\ az storage blob upload\--container-name"$AZURE_CONTAINER"\--file"$file"\--name"$(basename"$file")"\--overwritetrue>/dev/null}main(){[[-d"$LARAVEL_DIR"]]||{echo"ERROR: LARAVEL_DIR not found:$LARAVEL_DIR">&2;exit1;}mkdir-p"$BACKUP_DIR"localts app_name base_name db_dump archivets="$(timestamp_utc)"app_name="$(basename"$LARAVEL_DIR")"base_name="${app_name}-${ts}"db_dump="${BACKUP_DIR}/${base_name}.sql"archive="${BACKUP_DIR}/${base_name}.tar.gz"echo"[1/4] Dumping MySQL →$db_dump" dump_mysql"$db_dump"echo"[2/4] Creating archive →$archive" make_archive"$LARAVEL_DIR""$db_dump""$archive"echo"[3/4] Uploading to Azure via az CLI" upload_with_azcli"$archive"echo"Upload complete:$(basename"$archive")"echo"[4/4] Pruning local backups older than${RETAIN_LOCAL_DAYS}d" find"$BACKUP_DIR"-type f-name"${app_name}-*.tar.gz"-mtime +"$RETAIN_LOCAL_DAYS"-print-delete||truefind"$BACKUP_DIR"-type f-name"${app_name}-*.sql"-mtime +"$RETAIN_LOCAL_DAYS"-print-delete||true echo"Done."}main"$@"How It Works
Database Dump
- Reads
DB_HOST,DB_DATABASE,DB_USERNAME,DB_PASSWORDfrom.env - Runs
mysqldump
- Reads
File Packaging
- Copies project files while excluding unnecessary directories
- Adds
database.sql - Compresses into
tar.gz
Azure Upload
- Uses
az storage blob uploadwithAZURE_STORAGE_ACCOUNT+AZURE_STORAGE_KEY
- Uses
Retention Cleanup
- Deletes
.sqland.tar.gzfiles older thanRETAIN_LOCAL_DAYS
- Deletes
Usage
Save the script:
nano laravel-backup.shchmod +x laravel-backup.shConfigure variables:
LARAVEL_DIRBACKUP_DIRAZURE_STORAGE_ACCOUNTAZURE_STORAGE_KEYAZURE_CONTAINER
Run manually:
./laravel-backup.shOr schedule with cron:
crontab-e0 3*** /path/to/laravel-backup.sh>> /var/log/laravel-backup.log 2>&1Top comments(1)
Subscribe

if anyone wants to push their tarballs to s3 instead, i cover uploading to s3 with curl in bash here:
dev.to/gbhorwood/uploading-to-s3-w...
if your tarballs are too big for either azure or s3, i go over how to split them easily here:
dev.to/gbhorwood/bash-splitting-ta...
For further actions, you may consider blocking this person and/orreporting abuse




