diff --git a/backup.env b/backup.env new file mode 100644 index 00000000..b5080d7d --- /dev/null +++ b/backup.env @@ -0,0 +1,8 @@ +# Backup schedule in cron format (every 6 hours by default) +BACKUP_CRONSTRING=@every 6h + +# Optional: AWS S3 configuration if you want to push backups to S3 +# AWS_ACCESS_KEY_ID=your_access_key +# AWS_SECRET_ACCESS_KEY=your_secret_key +# S3_BUCKET=your_bucket_name +# S3_REGION=your_region \ No newline at end of file diff --git a/backup.log b/backup.log new file mode 100644 index 00000000..8f9ad672 --- /dev/null +++ b/backup.log @@ -0,0 +1,18 @@ +open /home/alsodev/compose.yaml: no such file or directory +open /home/alsodev/compose.yaml: no such file or directory +open /home/alsodev/compose.yaml: no such file or directory +open /home/alsodev/compose.yaml: no such file or directory +open /home/alsodev/compose.yaml: no such file or directory +Backup completed at ./backups/20250319_180001 +open /home/alsodev/compose.yaml: no such file or directory +open /home/alsodev/compose.yaml: no such file or directory +open /home/alsodev/compose.yaml: no such file or directory +open /home/alsodev/compose.yaml: no such file or directory +open /home/alsodev/compose.yaml: no such file or directory +Backup completed at ./backups/20250320_000001 +open /home/alsodev/compose.yaml: no such file or directory +open /home/alsodev/compose.yaml: no such file or directory +open /home/alsodev/compose.yaml: no such file or directory +open /home/alsodev/compose.yaml: no such file or directory +open /home/alsodev/compose.yaml: no such file or directory +Backup completed at ./backups/20250320_060002 diff --git a/backup.sh b/backup.sh new file mode 100755 index 00000000..835019a2 --- /dev/null +++ b/backup.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Path to your docker-compose files +COMPOSE_FILES="-f compose.yaml -f overrides/compose.mariadb.yaml -f overrides/compose.redis.yaml -f overrides/compose.https.yaml" + +# Create backup with files +docker compose $COMPOSE_FILES exec backend bench --site all backup --with-files + +# Optional: Copy backups to a local directory outside the Docker volume +# Create a backups directory if it doesn't exist +mkdir -p ./backups +TIMESTAMP=$(date +"%Y%m%d_%H%M%S") +docker compose $COMPOSE_FILES exec backend mkdir -p /home/frappe/frappe-bench/backups-export +docker compose $COMPOSE_FILES exec backend cp -r /home/frappe/frappe-bench/sites/*/backup/* /home/frappe/frappe-bench/backups-export/ + +# Copy the backups from the container to the host +docker compose $COMPOSE_FILES cp backend:/home/frappe/frappe-bench/backups-export/ ./backups/$TIMESTAMP + +# Cleanup the temporary directory in the container +docker compose $COMPOSE_FILES exec backend rm -rf /home/frappe/frappe-bench/backups-export + +echo "Backup completed at ./backups/$TIMESTAMP" + +# Optional: Implement backup rotation/cleanup to prevent using too much disk space +# Keep only the last 7 days of backups +find ./backups -type d -mtime +7 -exec rm -rf {} \; 2>/dev/null || true \ No newline at end of file diff --git a/create-site.yaml b/create-site.yaml new file mode 100644 index 00000000..7a83921f --- /dev/null +++ b/create-site.yaml @@ -0,0 +1,29 @@ +services: + create-site: + image: frappe/erpnext:v15.54.4 + entrypoint: + - bash + - -c + command: + - > + wait-for-it -t 120 db:3306; + wait-for-it -t 120 redis-cache:6379; + wait-for-it -t 120 redis-queue:6379; + export start=`date +%s`; + until [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty"` ]] && \ + [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".redis_cache // empty"` ]] && \ + [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".redis_queue // empty"` ]]; + do + echo "Waiting for sites/common_site_config.json to be created"; + sleep 5; + if (( `date +%s`-start > 120 )); then + echo "could not find sites/common_site_config.json with required keys"; + exit 1 + fi + done; + echo "sites/common_site_config.json found"; + rm -rf sites/erpnext.appsatile.com; + mysql -h db -uroot -p123 -e "DROP DATABASE IF EXISTS _1a2a97c0df78d27f"; + bench new-site --mariadb-root-username=root --db-root-password=123 --admin-password=admin123 --db-host=db --mariadb-user-host-login-scope=% --install-app erpnext erpnext.appsatile.com; + volumes: + - sites:/home/frappe/frappe-bench/sites \ No newline at end of file diff --git a/email.env b/email.env new file mode 100644 index 00000000..d77a8b58 --- /dev/null +++ b/email.env @@ -0,0 +1,8 @@ +# Email configuration +MAIL_HOST=smtp.gmail.com +MAIL_PORT=587 +MAIL_USE_TLS=1 +MAIL_LOGIN=your-email@gmail.com +MAIL_PASSWORD=your-app-password +MAIL_EMAIL_ID=your-email@gmail.com +MAIL_SENDER_NAME=ERPNext Administrator \ No newline at end of file diff --git a/gdrive-backup.env b/gdrive-backup.env new file mode 100644 index 00000000..4aa5eaa3 --- /dev/null +++ b/gdrive-backup.env @@ -0,0 +1,10 @@ +# Google Drive rclone configuration +# You'll need to generate this token using rclone setup on your local machine first +RCLONE_GDRIVE_TOKEN={"access_token":"YOUR_ACCESS_TOKEN","token_type":"Bearer","refresh_token":"YOUR_REFRESH_TOKEN","expiry":"EXPIRY_TIMESTAMP"} + +# Optional: If using a Team Drive (Google Workspace) +RCLONE_TEAM_DRIVE_ID= + +# Optional: If you want to use a specific folder within your Google Drive +# Get this ID from the URL when you're in the folder: https://drive.google.com/drive/folders/YOUR_FOLDER_ID +RCLONE_FOLDER_ID= \ No newline at end of file diff --git a/gdrive-backup.yaml b/gdrive-backup.yaml new file mode 100644 index 00000000..b7a3eccd --- /dev/null +++ b/gdrive-backup.yaml @@ -0,0 +1,52 @@ +services: + backup: + image: frappe/erpnext:v15.54.4 + entrypoint: ["bash", "-c"] + command: + - | + # Install rclone if not already installed + if ! command -v rclone &> /dev/null; then + echo "Installing rclone..." + curl https://rclone.org/install.sh | bash + fi + + # Create a backup of all sites with files + echo "Creating backup..." + bench --site all backup --with-files + + # Configure rclone for Google Drive if not already configured + if [ ! -f /root/.config/rclone/rclone.conf ]; then + mkdir -p /root/.config/rclone/ + echo "Creating rclone config from environment variables..." + cat > /root/.config/rclone/rclone.conf << EOF + [gdrive] + type = drive + token = ${RCLONE_GDRIVE_TOKEN} + team_drive = ${RCLONE_TEAM_DRIVE_ID} + root_folder_id = ${RCLONE_FOLDER_ID} + EOF + fi + + # Upload backups to Google Drive + echo "Uploading backups to Google Drive..." + TODAY=$(date +%Y-%m-%d) + for site_path in /home/frappe/frappe-bench/sites/*/; do + site=$(basename "$site_path") + if [ "$site" != "assets" ] && [ -d "${site_path}backup" ]; then + echo "Pushing backup for $site to Google Drive..." + rclone copy ${site_path}backup gdrive:ERPNext_Backups/$site/$TODAY/ --progress + fi + done + + # Cleanup old backups (keeping last 7 days) + echo "Cleaning up old local backups..." + find /home/frappe/frappe-bench/sites/*/backup -type f -mtime +7 -delete + volumes: + - sites:/home/frappe/frappe-bench/sites + - rclone-config:/root/.config/rclone + +volumes: + sites: + external: true + name: frappe_docker_sites + rclone-config: \ No newline at end of file diff --git a/pwd.yml b/pwd.yml index a5de2a39..0f8ea2f4 100644 --- a/pwd.yml +++ b/pwd.yml @@ -125,7 +125,7 @@ services: - sites:/home/frappe/frappe-bench/sites - logs:/home/frappe/frappe-bench/logs ports: - - "8080:8080" + - "80:8080" queue-long: image: frappe/erpnext:v15.54.5 diff --git a/run-backup-cron.sh b/run-backup-cron.sh new file mode 100755 index 00000000..af9d3683 --- /dev/null +++ b/run-backup-cron.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# Path to your docker-compose files +COMPOSE_FILES="-f compose.yaml -f overrides/compose.mariadb.yaml -f overrides/compose.redis.yaml -f overrides/compose.https.yaml -f overrides/compose.backup-cron.yaml" + +# Start the backup cron service +docker compose --env-file backup.env $COMPOSE_FILES up -d cron \ No newline at end of file diff --git a/run-gdrive-backup.sh b/run-gdrive-backup.sh new file mode 100755 index 00000000..1eb206e9 --- /dev/null +++ b/run-gdrive-backup.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# Path to your Google Drive backup configuration +GDRIVE_BACKUP_FILE="gdrive-backup.yaml" + +# Run the backup with Google Drive environment variables +docker compose -f $GDRIVE_BACKUP_FILE --env-file gdrive-backup.env up backup + +echo "Google Drive backup completed at $(date)" \ No newline at end of file diff --git a/run-s3-backup.sh b/run-s3-backup.sh new file mode 100755 index 00000000..03cf7558 --- /dev/null +++ b/run-s3-backup.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# Path to your S3 backup configuration +S3_BACKUP_FILE="s3-backup.yaml" + +# Run the backup with appropriate environment variables +docker compose -f $S3_BACKUP_FILE --env-file backup.env up backup + +echo "S3 backup completed at $(date)" \ No newline at end of file diff --git a/s3-backup.yaml b/s3-backup.yaml new file mode 100644 index 00000000..69c9f198 --- /dev/null +++ b/s3-backup.yaml @@ -0,0 +1,34 @@ +services: + backup: + image: frappe/erpnext:v15.54.4 + entrypoint: ["bash", "-c"] + command: + - | + # Create a backup of all sites with files + bench --site all backup --with-files + + # Upload backups to S3 + for site_path in /home/frappe/frappe-bench/sites/*/; do + site=$(basename "$site_path") + if [ -d "${site_path}backup" ]; then + echo "Pushing backup for $site to S3..." + cd "${site_path}backup" + # Use aws cli to sync backups to S3 + aws s3 sync . s3://${S3_BUCKET}/${site}/$(date +%Y-%m-%d)/ + fi + done + + # Cleanup old backups (keeping last 7 days) + find /home/frappe/frappe-bench/sites/*/backup -type f -mtime +7 -delete + environment: + - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} + - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} + - S3_BUCKET=${S3_BUCKET} + - AWS_DEFAULT_REGION=${S3_REGION} + volumes: + - sites:/home/frappe/frappe-bench/sites + +volumes: + sites: + external: true + name: frappe_docker_sites \ No newline at end of file diff --git a/setup-email.sh b/setup-email.sh new file mode 100755 index 00000000..7ae12b82 --- /dev/null +++ b/setup-email.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Read email configuration +source email.env + +# Path to your docker-compose files +COMPOSE_FILES="-f compose.yaml -f overrides/compose.mariadb.yaml -f overrides/compose.redis.yaml -f overrides/compose.https.yaml" + +# Configure email settings +docker compose $COMPOSE_FILES exec backend bench --site erpnext.appsatile.com set-config -g mail_server "$MAIL_HOST" +docker compose $COMPOSE_FILES exec backend bench --site erpnext.appsatile.com set-config -g mail_port "$MAIL_PORT" +docker compose $COMPOSE_FILES exec backend bench --site erpnext.appsatile.com set-config -g use_tls "$MAIL_USE_TLS" +docker compose $COMPOSE_FILES exec backend bench --site erpnext.appsatile.com set-config -g mail_login "$MAIL_LOGIN" +docker compose $COMPOSE_FILES exec backend bench --site erpnext.appsatile.com set-config -g mail_password "$MAIL_PASSWORD" +docker compose $COMPOSE_FILES exec backend bench --site erpnext.appsatile.com set-config -g auto_email_id "$MAIL_EMAIL_ID" +docker compose $COMPOSE_FILES exec backend bench --site erpnext.appsatile.com set-config -g email_sender_name "$MAIL_SENDER_NAME" + +# Make these configurations take effect +docker compose $COMPOSE_FILES restart backend + +echo "Email configuration completed" \ No newline at end of file diff --git a/setup-gdrive-backup-cron.sh b/setup-gdrive-backup-cron.sh new file mode 100755 index 00000000..529a1b1d --- /dev/null +++ b/setup-gdrive-backup-cron.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# Add cron job to run Google Drive backup daily at 2 AM +CRON_JOB="0 2 * * * $(pwd)/run-gdrive-backup.sh >> $(pwd)/gdrive-backup.log 2>&1" + +# Check if cron job already exists +if crontab -l 2>/dev/null | grep -q "run-gdrive-backup.sh"; then + echo "Google Drive backup cron job already exists" +else + # Add new cron job + (crontab -l 2>/dev/null; echo "$CRON_JOB") | crontab - + echo "Google Drive backup cron job added" +fi \ No newline at end of file