Last active 1697445670 Unlisted

Backup system user (without backups enabled in plan) with all its objects

v-backup-user-without-backups.sh Raw
1#!/bin/bash
2# info: backup system user (without backups enabled in plan) with all its objects
3# options: USER
4#
5# example: v-backup-user admin yes
6#
7# This function is used for backing up user with all its domains and databases.
8
9#----------------------------------------------------------#
10# Variables & Functions #
11#----------------------------------------------------------#
12
13# Argument definition
14user=$1
15notify=${2-no}
16
17# Includes
18# shellcheck source=/etc/hestiacp/hestia.conf
19source /etc/hestiacp/hestia.conf
20# shellcheck source=/usr/local/hestia/func/main.sh
21source $HESTIA/func/main.sh
22# shellcheck source=/usr/local/hestia/func/domain.sh
23source $HESTIA/func/domain.sh
24# shellcheck source=/usr/local/hestia/func/db.sh
25source $HESTIA/func/db.sh
26# shellcheck source=/usr/local/hestia/func/backup.sh
27source $HESTIA/func/backup.sh
28# load config file
29source_conf "$HESTIA/conf/hestia.conf"
30
31
32# Return Disk Usage
33get_user_disk_usage() {
34 u_usage=0
35 web_exclusions=''
36 mail_exclusions=''
37 db_exclusions=''
38 user_exclusions=''
39
40 # Parsing excludes
41 if [ -e "$USER_DATA/backup-excludes.conf" ]; then
42 web_exclusions=$(grep 'WEB=' $USER_DATA/backup-excludes.conf \
43 | awk -F "WEB='" '{print $2}' | cut -f 1 -d \')
44 mail_exclusions=$(grep 'MAIL=' $USER_DATA/backup-excludes.conf \
45 | awk -F "MAIL='" '{print $2}' | cut -f 1 -d \')
46 db_exclusions=$(grep 'DB=' $USER_DATA/backup-excludes.conf \
47 | awk -F "DB='" '{print $2}' | cut -f 1 -d \')
48 user_exclusions=$(grep 'USER=' $USER_DATA/backup-excludes.conf \
49 | awk -F "USER='" '{print $2}' | cut -f 1 -d \')
50 fi
51
52 if [ -f "$USER_DATA/web.conf" ] && [ "$web_exclusions" != '*' ]; then
53 usage=0
54 domains=$(grep 'DOMAIN=' $USER_DATA/web.conf \
55 | awk -F "DOMAIN='" '{print $2}' | cut -f 1 -d \')
56
57 for domain in $domains; do
58 exclusion=$(echo -e "$web_exclusions" | tr ',' '\n' | grep "^$domain\|\*$")
59 if [ -z "$exclusion" ]; then
60 # Defining home directory
61 home_dir="$HOMEDIR/$user/web/$domain/"
62 exclusion=$(echo -e "$web_exclusions" | tr ',' '\n' | grep "^$domain\|\*:")
63 fargs=()
64
65 if [ -n "$exclusion" ]; then
66 xdirs=$(echo -e "$exclusion" | tr ':' '\n' | grep -v "$domain\|\*")
67 for xpath in $xdirs; do
68 fargs+=(--exclude="$xpath")
69 done
70 fi
71
72 # Checking home directory exist
73 if [ -e "$home_dir" ]; then
74 disk_usage=$(nice -n 19 du -shm "$home_dir" "${fargs[@]}" | cut -f 1)
75 u_usage=$((u_usage + disk_usage))
76 fi
77 fi
78 done
79 fi
80
81 if [ -f "$USER_DATA/mail.conf" ] && [ "$mail_exclusions" != '*' ]; then
82 usage=0
83 domains=$(grep 'DOMAIN=' "$USER_DATA/mail.conf" \
84 | awk -F "DOMAIN='" '{print $2}' | cut -f 1 -d \')
85
86 for domain in $domains; do
87 check_exl=$(echo "$mail_exclusions" | tr ',' '\n' | grep "^$domain$")
88 if [ -f "$USER_DATA/mail/$domain.conf" ] && [ -z "$check_exl" ]; then
89 accounts=$(grep 'ACCOUNT=' "$USER_DATA/mail/$domain.conf" \
90 | awk -F "ACCOUNT='" '{print $2}' | cut -f 1 -d \')
91
92 for account in $accounts; do
93 home_dir=$HOMEDIR/$user/mail/$domain/$account
94 exclusion=$(echo "$mail_exclusions" | tr ',' '\n' | grep "$domain:")
95 exclusion=$(echo "$exclusion" | tr ':' '\n' | grep -E "^$account|\*")
96
97 if [ -z "$exclusion" ] && [ -e "$home_dir" ]; then
98 disk_usage=$(nice -n 19 du -shm "$home_dir" | cut -f 1)
99 u_usage=$((u_usage + disk_usage))
100 fi
101 done
102 fi
103 done
104 fi
105
106 if [ -f "$USER_DATA/db.conf" ] && [ "$db_exclusions" != '*' ]; then
107 usage=0
108 databases=$(grep 'DB=' "$USER_DATA/db.conf" \
109 | awk -F "DB='" '{print $2}' | cut -f 1 -d \')
110 for database in $databases; do
111 exclusion=$(echo "$db_exclusions" | tr ',' '\n' | grep "^$database$")
112 if [ -z "$exclusion" ]; then
113 # Get database values
114 get_database_values
115
116 # Switching on db type
117 case $DB_SYSTEM in
118 mysql) get_mysql_disk_usage ;;
119 pgsql) get_pgsql_disk_usage ;;
120 esac
121 u_usage=$((u_usage + usage))
122 fi
123 done
124 fi
125
126 if [ "$user_exclusions" != '*' ]; then
127 fargs=()
128 for xpath in $(echo "$user_exclusions" | tr ',' '\n'); do
129 fargs+=(--exclude="$xpath")
130 done
131 usage=$(du -shm "$HOMEDIR/$user" --exclude "$HOMEDIR/$user/web" --exclude "$HOMEDIR/$user/mail" --exclude "$HOMEDIR/$user/conf" "${fargs[@]}" | cut -f 1)
132 u_usage=$((u_usage + usage))
133 fi
134
135 echo ${u_usage}
136}
137
138#----------------------------------------------------------#
139# Verifications #
140#----------------------------------------------------------#
141
142check_args '1' "$#" 'USER [NOTIFY]'
143is_format_valid 'user'
144is_system_enabled "$BACKUP_SYSTEM" 'BACKUP_SYSTEM'
145is_object_valid 'user' 'USER' "$user"
146if [ "$POLICY_BACKUP_SUSPENDED_USERS" != "yes" ]; then
147 is_object_unsuspended 'user' 'USER' "$user"
148fi
149#is_backup_enabled
150# If user has backups enabled, exit
151BACKUPS=$(grep "^BACKUPS=" $USER_DATA/user.conf | cut -f2 -d \')
152if [[ "$BACKUPS" -gt '0' ]]; then
153 check_result "$E_DISABLED" "backup for user $user is already enabled"
154fi
155
156# Only allow 1 backup for the user
157BACKUPS=1
158# Perform verification if read-only mode is enabled
159check_hestia_demo_mode
160
161#----------------------------------------------------------#
162# Action #
163#----------------------------------------------------------#
164
165check_backup_conditions
166
167# Set backup directory if undefined
168if [ -z "$BACKUP" ]; then
169 BACKUP=/backup
170fi
171
172# Check if backup folder exists and have the correct permission
173if [[ ! -d "$BACKUP" ]]; then
174 mkdir -p $BACKUP
175fi
176if [ "$(stat -c %a "$BACKUP")" != 755 ]; then
177 chmod 755 $BACKUP
178fi
179
180# Get current time
181start_time=$(date '+%s')
182
183# Set notification email and subject
184#subj="$user → backup failed"
185#email=$(grep CONTACT "$HESTIA/data/users/admin/user.conf" | cut -f 2 -d \')
186
187# Validate available disk space (take usage * 2, due to the backup handling)
188let u_disk=$(($(get_user_disk_usage) * 2))
189let v_disk=$(($(stat -f --format="%a*%S" $BACKUP)))/1024/1024
190
191if [ "$u_disk" -gt "$v_disk" ]; then
192 let u_disk_original=$(get_user_disk_usage)
193 # Always notify on failure
194 echo "Not enough disk space available ($v_disk mb) to perform the backup of $user. ( $u_disk_original mb * 2 = $u_disk mb). https://hestiacp.com/docs/server-administration/backup-restore.html" | $SENDMAIL -s "$subj" "$email" "yes"
195 # Deleting task from queue
196 sed -i "/v-backup-user $user /d" $HESTIA/data/queue/backup.pipe
197 check_result "$E_LIMIT" "not enough disk space available ($v_disk mb) to perform the backup of $user. ( $u_disk_original mb * 2 = $u_disk mb)."
198fi
199
200if [ -z "$BACKUP_TEMP" ]; then
201 BACKUP_TEMP=$BACKUP
202fi
203
204# Creating temporary directory
205tmpdir=$(mktemp -p $BACKUP_TEMP -d)
206
207if [ "$?" -ne 0 ]; then
208 echo "Can't create tmp dir $tmpdir" | $SENDMAIL -s "$subj" "$email" "yes"
209 # Deleting task from queue
210 sed -i "/v-backup-user $user /d" $HESTIA/data/queue/backup.pipe
211 check_result "$E_NOTEXIST" "can't create tmp dir"
212fi
213
214# Backup sys configs
215echo "-- SYSTEM --" | tee $BACKUP/$user.log
216mkdir $tmpdir/hestia
217
218echo -e "$(date "+%F %T") $user.conf" | tee -a $BACKUP/$user.log
219cp -r $USER_DATA/user.conf $tmpdir/hestia/
220cp -r $USER_DATA/ssl $tmpdir/hestia/
221
222if [ -e "$USER_DATA/stats.log" ]; then
223 echo -e "$(date "+%F %T") stats.log" | tee -a $BACKUP/$user.log
224 cp -r $USER_DATA/stats.log $tmpdir/hestia/
225fi
226
227if [ -e "$USER_DATA/history.log" ]; then
228 echo -e "$(date "+%F %T") history.log" | tee -a $BACKUP/$user.log
229 cp -r $USER_DATA/history.log $tmpdir/hestia/
230fi
231
232if [ -e "$USER_DATA/backup-excludes.conf" ]; then
233 echo -e "$(date "+%F %T") backup-excludes.conf" | tee -a $BACKUP/$user.log
234 cp -r $USER_DATA/backup-excludes.conf $tmpdir/hestia/
235fi
236
237# Backup PAM
238mkdir $tmpdir/pam
239echo -e "$(date "+%F %T") pam" | tee -a $BACKUP/$user.log
240grep "^$user:" /etc/passwd > $tmpdir/pam/passwd
241grep "^$user:" /etc/shadow > $tmpdir/pam/shadow
242grep "^$user:" /etc/group > $tmpdir/pam/group
243echo
244
245# Parsing excludes
246if [ -e "$USER_DATA/backup-excludes.conf" ]; then
247 source $USER_DATA/backup-excludes.conf
248fi
249
250# WEB domains
251if [ -n "$WEB_SYSTEM" ] && [ "$WEB" != '*' ]; then
252 echo -e "\n-- WEB --" | tee -a $BACKUP/$user.log
253 mkdir $tmpdir/web/
254
255 # Parsing domain exclusions
256 conf="$USER_DATA/web.conf"
257 for domain in $(search_objects 'web' 'SUSPENDED' "*" 'DOMAIN'); do
258 exclusion=$(echo -e "$WEB" | tr ',' '\n' | grep "^$domain$\|^\*$")
259 if [ -z "$exclusion" ]; then
260 web_list="$web_list $domain"
261 else
262 echo "$(date "+%F %T") excluding $domain" | tee -a $BACKUP/$user.log
263 fi
264 done
265 web_list=$(echo "$web_list" | sed -e "s/ */\ /g" -e "s/^ //")
266
267 i=0
268
269 for domain in $web_list; do
270 check_backup_conditions
271 ((i++))
272 echo -e "$(date "+%F %T") $domain" | tee -a $BACKUP/$user.log
273 mkdir -p $tmpdir/web/$domain/conf
274 mkdir -p $tmpdir/web/$domain/hestia
275
276 # Get domain variables
277 domain_idn=$domain
278 format_domain_idn
279 get_domain_values 'web'
280
281 # Backup web.conf
282 cd $tmpdir/web/$domain/
283 conf="$USER_DATA/web.conf"
284 grep "DOMAIN='$domain'" $conf > hestia/web.conf
285
286 # Backup vhost config
287 if [ -e "$HOMEDIR/$user/conf/web/$domain/$WEB_SYSTEM.conf" ]; then
288 cp $HOMEDIR/$user/conf/web/$domain/$WEB_SYSTEM.conf* conf/
289 elif [ -e "$HOMEDIR/$user/conf/web/$domain.$WEB_SYSTEM.conf" ]; then
290 cp $HOMEDIR/$user/conf/web/$domain.$WEB_SYSTEM.conf* conf/
291 else
292 # legacy format: all domain configs in single file
293 tpl_file="$WEBTPL/$WEB_SYSTEM/$WEB_BACKEND/$TPL.tpl"
294 conf="$HOMEDIR/$user/conf/web/$WEB_SYSTEM.conf"
295 get_web_config_lines "$tpl_file" "$conf"
296 sed -n "$top_line,$bottom_line p" $conf > conf/$WEB_SYSTEM.conf
297 fi
298
299 # Backup ssl vhost
300 if [ "$SSL" = 'yes' ]; then
301 if [ -e "$HOMEDIR/$user/conf/web/$domain/$WEB_SYSTEM.ssl.conf" ]; then
302 cp $HOMEDIR/$user/conf/web/$domain/$WEB_SYSTEM.ssl.conf* conf/
303 elif [ -e "$HOMEDIR/$user/conf/web/$domain.$WEB_SYSTEM.ssl.conf" ]; then
304 cp $HOMEDIR/$user/conf/web/$domain.$WEB_SYSTEM.ssl.conf* conf/
305 else
306 # legacy format: all domain configs in single file
307 tpl_file="$WEBTPL/$WEB_SYSTEM/$WEB_BACKEND/$TPL.stpl"
308 conf="$HOMEDIR/$user/conf/web/s$WEB_SYSTEM.conf"
309 get_web_config_lines "$tpl_file" "$conf"
310 sed -n "$top_line,$bottom_line p" $conf > conf/s$WEB_SYSTEM.conf
311 fi
312 fi
313
314 # Backup proxy config
315 if [ -n "$PROXY_SYSTEM" ] && [ -n "$PROXY" ]; then
316 if [ -e "$HOMEDIR/$user/conf/web/$domain/$PROXY_SYSTEM.conf" ]; then
317 cp $HOMEDIR/$user/conf/web/$domain/$PROXY_SYSTEM.conf* conf/
318 elif [ -e "$HOMEDIR/$user/conf/web/$domain.$PROXY_SYSTEM.conf" ]; then
319 cp $HOMEDIR/$user/conf/web/$domain.$PROXY_SYSTEM.conf* conf/
320 else
321 # legacy format: all domain configs in single file
322 tpl_file="$WEBTPL/$PROXY_SYSTEM/$PROXY.tpl"
323 conf="$HOMEDIR/$user/conf/web/$PROXY_SYSTEM.conf"
324 get_web_config_lines "$tpl_file" "$conf"
325 sed -n "$top_line,$bottom_line p" $conf > conf/$PROXY_SYSTEM.conf
326 fi
327 fi
328
329 # Backup ssl proxy config
330 if [ -n "$PROXY_SYSTEM" ] && [ -n "$PROXY" ] && [ "$SSL" = 'yes' ]; then
331 if [ -e "$HOMEDIR/$user/conf/web/$domain/$PROXY_SYSTEM.ssl.conf" ]; then
332 cp $HOMEDIR/$user/conf/web/$domain/$PROXY_SYSTEM.ssl.conf* conf/
333 elif [ -e "$HOMEDIR/$user/conf/web/$domain.$PROXY_SYSTEM.ssl.conf" ]; then
334 cp $HOMEDIR/$user/conf/web/$domain.$PROXY_SYSTEM.ssl.conf* conf/
335 else
336 # legacy format: all domain configs in single file
337 tpl_file="$WEBTPL/$PROXY_SYSTEM/$PROXY.stpl"
338 conf="$HOMEDIR/$user/conf/web/s$PROXY_SYSTEM.conf"
339 get_web_config_lines "$tpl_file" "$conf"
340 sed -n "$top_line,$bottom_line p" $conf > conf/s$PROXY_SYSTEM.conf
341 fi
342 fi
343
344 domain_conf=$(grep "DOMAIN='$domain'" $conf)
345 parse_object_kv_list_non_eval domain_conf
346
347 mkdir -p template/$WEB_SYSTEM/
348 mkdir template/php-fpm/
349
350 if [ $WEB_BACKEND == 'php-fpm' ]; then
351 cp $HESTIA/data/templates/web/$WEB_SYSTEM/php-fpm/$TPL.tpl template/$WEB_SYSTEM/
352 cp $HESTIA/data/templates/web/$WEB_SYSTEM/php-fpm/$TPL.stpl template/$WEB_SYSTEM/
353 cp $HESTIA/data/templates/web/php-fpm/$BACKEND.tpl template/php-fpm/
354 else
355 cp $HESTIA/data/templates/web/$WEB_SYSTEM/$TPL.tpl template/$WEB_SYSTEM/
356 cp $HESTIA/data/templates/web/$WEB_SYSTEM/$TPL.stpl template/$WEB_SYSTEM/
357 fi
358 if [ -n "$PROXY_SYSTEM" ] && [ -n "$PROXY" ]; then
359 mkdir template/$PROXY_SYSTEM
360 cp $HESTIA/data/templates/web/$PROXY_SYSTEM/$PROXY.tpl template/$PROXY_SYSTEM/
361 cp $HESTIA/data/templates/web/$PROXY_SYSTEM/$PROXY.stpl template/$PROXY_SYSTEM/
362 fi
363
364 # Backup ssl certificates
365 if [ "$SSL" = 'yes' ]; then
366 cp $HOMEDIR/$user/conf/web/$domain/ssl/$domain.* conf/
367 cp $USER_DATA/ssl/$domain.* hestia/
368 fi
369
370 # Changin dir to documentroot
371 cd $HOMEDIR/$user/web/$domain
372
373 # Define exclude arguments
374 exclusion=$(echo -e "$WEB" | tr ',' '\n' | grep "^$domain\|\*:")
375 set -f
376 fargs=()
377 fargs+=(--exclude='./logs/*')
378 if [ -n "$exclusion" ]; then
379
380 if [[ "$exclusion" =~ '*' ]]; then
381 exclusion="${exclusion/\*/$domain}"
382 fi
383
384 xdirs="$(echo -e "$exclusion" | tr ':' '\n' | grep -v $domain)"
385 for xpath in $xdirs; do
386 if [ -d "$xpath" ]; then
387 fargs+=(--exclude=$xpath/*)
388 echo "$(date "+%F %T") excluding directory $xpath"
389 msg="$msg\n$(date "+%F %T") excluding directory $xpath"
390 else
391 echo "$(date "+%F %T") excluding file $xpath"
392 msg="$msg\n$(date "+%F %T") excluding file $xpath"
393 fargs+=(--exclude=$xpath)
394 fi
395 done
396 fi
397 set +f
398
399 # Backup files
400 if [ "$BACKUP_MODE" = 'zstd' ]; then
401 tar "${fargs[@]}" -cpf- * | pzstd -"$BACKUP_GZIP" - > $tmpdir/web/$domain/domain_data.tar.zst
402 else
403 tar "${fargs[@]}" -cpf- * | gzip -"$BACKUP_GZIP" - > $tmpdir/web/$domain/domain_data.tar.gz
404 fi
405 done
406
407 # Print total
408 if [ "$i" -eq 1 ]; then
409 echo -e "$(date "+%F %T") *** $i domain ***" | tee -a $BACKUP/$user.log
410 else
411 echo -e "$(date "+%F %T") *** $i domains ***" | tee -a $BACKUP/$user.log
412 fi
413fi
414
415# DNS domains
416if [ -n "$DNS_SYSTEM" ] && [ "$DNS" != '*' ]; then
417 echo -e "\n-- DNS --" | tee -a $BACKUP/$user.log
418 mkdir $tmpdir/dns/
419
420 # Parsing domain exclusions
421 for domain in $(search_objects 'dns' 'SUSPENDED' "*" 'DOMAIN'); do
422 exclusion=$(echo "$DNS" | tr ',' '\n' | grep "^$domain$")
423 if [ -z "$exclusion" ]; then
424 dns_list="$dns_list $domain"
425 else
426 echo "$(date "+%F %T") excluding $domain"
427 msg="$msg\n$(date "+%F %T") excluding $domain"
428 fi
429 done
430 dns_list=$(echo "$dns_list" | sed -e "s/ */\ /g" -e "s/^ //")
431
432 i=0
433 for domain in $dns_list; do
434 ((i++))
435 echo -e "$(date "+%F %T") $domain" | tee -a $BACKUP/$user.log
436 domain_idn="$domain"
437 # Building directory tree
438 mkdir -p $tmpdir/dns/$domain/conf
439 mkdir -p $tmpdir/dns/$domain/conf/keys
440 mkdir -p $tmpdir/dns/$domain/hestia
441
442 # Backup dns.conf
443 cd $tmpdir/dns/$domain/
444 conf="$USER_DATA/dns.conf"
445 grep "DOMAIN='$domain'" $conf > hestia/dns.conf
446
447 # Backup dns recods
448 cp $USER_DATA/dns/$domain.conf hestia/$domain.conf
449 if [ "$DNS_SYSTEM" != 'remote' ]; then
450 cp $HOMEDIR/$user/conf/dns/$domain.db conf/$domain.db
451 fi
452 # Backup DNSSEC public and private key if enabled
453 dnssec=$(grep "DOMAIN='$domain'" $USER_DATA/dns.conf | grep "DNSSEC='yes'")
454 if [ -n "$dnssec" ]; then
455 format_domain_idn
456 cp $USER_DATA/keys/K$domain_idn*.* $tmpdir/dns/$domain/conf/keys
457 fi
458 done
459
460 # Print total
461 if [ "$i" -eq 1 ]; then
462 echo -e "$(date "+%F %T") *** $i domain ***" | tee -a $BACKUP/$user.log
463 else
464 echo -e "$(date "+%F %T") *** $i domains ***" | tee -a $BACKUP/$user.log
465 fi
466fi
467
468# Mail domains
469if [ -n "$MAIL_SYSTEM" ] && [ "$MAIL" != '*' ]; then
470 echo -e "\n-- MAIL --" | tee -a $BACKUP/$user.log
471 mkdir $tmpdir/mail/
472
473 # Parsing domain exclusions
474 conf="$USER_DATA/mail.conf"
475 for domain in $(search_objects 'mail' 'SUSPENDED' "*" 'DOMAIN'); do
476 check_exl=$(echo "$MAIL" | tr ',' '\n' | grep "^$domain$")
477 if [ -z "$check_exl" ]; then
478 mail_list="$mail_list $domain"
479 else
480 echo "$(date "+%F %T") excluding $domain" | tee -a $BACKUP/$user.log
481 fi
482 done
483 mail_list=$(echo "$mail_list" | sed -e "s/ */\ /g" -e "s/^ //")
484
485 i=0
486 for domain in $mail_list; do
487 check_backup_conditions
488 ((i++))
489 echo -e "$(date "+%F %T") $domain" | tee -a $BACKUP/$user.log
490 mkdir -p $tmpdir/mail/$domain/conf
491 mkdir -p $tmpdir/mail/$domain/hestia
492 domain_idn=$domain
493 format_domain_idn
494
495 # Backup exim config
496 if [[ "$MAIL_SYSTEM" =~ exim ]]; then
497 cd $tmpdir/mail/$domain/
498 cp -r $HOMEDIR/$user/conf/mail/$domain/* conf/
499 fi
500
501 # Backup mail.conf
502 conf="$USER_DATA/mail.conf"
503 grep "DOMAIN='$domain'" $conf > hestia/mail.conf
504 cp $USER_DATA/mail/$domain.* hestia/
505 if [ -n "$(ls $USER_DATA/mail/ | grep *@$domain)" ]; then
506 cp $USER_DATA/mail/*@$domain.* hestia/
507 fi
508
509 # Backup emails
510 cd $HOMEDIR/$user/mail/$domain_idn
511 accounts=()
512 for account in *; do
513 exclusion=$(echo "$MAIL" | tr ',' '\n' | grep "$domain:")
514 exclusion=$(echo "$exclusion" | tr ':' '\n' | grep -E "^$account|\*")
515
516 # Checking exclusions
517 if [ -z "$exclusion" ] && [[ "$MAIL_SYSTEM" =~ exim ]]; then
518 accounts+=($account)
519 else
520 echo "$(date "+%F %T") excluding mail account $account" \
521 | tee -a $BACKUP/$user.log
522 fi
523 done
524 # Compress archive
525 if [ ${#accounts[@]} -gt 0 ]; then
526 if [ "$BACKUP_MODE" = 'zstd' ]; then
527 tar -cpf- "${accounts[@]}" | pzstd -"$BACKUP_GZIP" - > $tmpdir/mail/$domain/accounts.tar.zst
528 else
529 tar -cpf- "${accounts[@]}" | gzip -"$BACKUP_GZIP" - > $tmpdir/mail/$domain/accounts.tar.gz
530 fi
531 fi
532 done
533
534 # Print total
535 if [ "$i" -eq 1 ]; then
536 echo -e "$(date "+%F %T") *** $i domain ***" | tee -a $BACKUP/$user.log
537 else
538 echo -e "$(date "+%F %T") *** $i domains ***" | tee -a $BACKUP/$user.log
539 fi
540fi
541
542# Databases
543if [ -n "$DB_SYSTEM" ] && [ "$DB" != '*' ]; then
544 echo -e "\n-- DB --" | tee -a $BACKUP/$user.log
545 mkdir $tmpdir/db/
546
547 # Parsing database exclusions
548 for database in $(search_objects 'db' 'SUSPENDED' "*" 'DB'); do
549 exclusion=$(echo "$DB" | tr ',' '\n' | grep "^$database$")
550 if [ -z "$exclusion" ]; then
551 db_list="$db_list $database"
552 else
553 echo "$(date "+%F %T") excluding $database" \
554 | tee -a $BACKUP/$user.log
555 fi
556 done
557
558 i=0
559 conf="$USER_DATA/db.conf"
560 db_list=$(echo "$db_list" | sed -e "s/ */\ /g" -e "s/^ //")
561 for database in $db_list; do
562 check_backup_conditions
563 ((i++))
564 get_database_values
565
566 echo -e "$(date "+%F %T") $database ($TYPE)" | tee -a $BACKUP/$user.log
567 mkdir -p $tmpdir/db/$database/conf
568 mkdir -p $tmpdir/db/$database/hestia
569
570 cd $tmpdir/db/$database/
571 grep "DB='$database'" $conf > hestia/db.conf
572
573 dump="$tmpdir/db/$database/$database.$TYPE.sql"
574 if [ "$BACKUP_MODE" = 'zstd' ]; then
575 dumpgz="$tmpdir/db/$database/$database.$TYPE.sql.zst"
576 else
577 dumpgz="$tmpdir/db/$database/$database.$TYPE.sql.gz"
578 fi
579
580 grants="$tmpdir/db/$database/conf/$database.$TYPE.$DBUSER"
581 if [ ! -f "$dumpgz" ]; then
582
583 WAIT_LOOP_ENTERED=0
584 while true; do
585 if pgrep -x "mysqldump" > /dev/null; then
586 WAIT_LOOP_ENTERED=1
587 echo "Wait other mysqldump to finish"
588 sleep 1
589 else
590 if [ "$WAIT_LOOP_ENTERED" -eq 1 ]; then
591 echo "We can use mysqldump now"
592 fi
593 break
594 fi
595 done
596
597 case $TYPE in
598 mysql) dump_mysql_database ;;
599 pgsql) dump_pgsql_database ;;
600 esac
601
602 # Compress dump
603 if [ "$BACKUP_MODE" = 'zstd' ]; then
604 pzstd -$BACKUP_GZIP $dump
605 rm $dump
606 else
607 gzip -$BACKUP_GZIP $dump
608 fi
609 fi
610 done
611
612 # Print total
613 if [ "$i" -eq 1 ]; then
614 echo -e "$(date "+%F %T") *** $i database ***" \
615 | tee -a $BACKUP/$user.log
616 else
617 echo -e "$(date "+%F %T") *** $i databases ***" \
618 | tee -a $BACKUP/$user.log
619 fi
620fi
621
622# Cron jobs
623if [ -n "$CRON_SYSTEM" ] && [ "$CRON" != '*' ]; then
624 echo -e "\n-- CRON --" | tee -a $BACKUP/$user.log
625 mkdir $tmpdir/cron/
626
627 # Backup cron.conf
628 cp $USER_DATA/cron.conf $tmpdir/cron/
629 cron_record=$(wc -l $USER_DATA/cron.conf | cut -f 1 -d ' ')
630
631 if [ -e "/var/spool/cron/$user" ]; then
632 cron_list="$cron_record"
633 cp /var/spool/cron/$user $tmpdir/cron/
634 fi
635
636 # Print total
637 if [ "$cron_record" -eq 1 ]; then
638 echo -e "$(date "+%F %T") *** $cron_record job ***" \
639 | tee -a $BACKUP/$user.log
640 else
641 echo -e "$(date "+%F %T") *** $cron_record jobs ***" \
642 | tee -a $BACKUP/$user.log
643 fi
644fi
645
646# User Directories
647if [ "$USER" != '*' ]; then
648 echo -e "\n-- User Dir --" | tee -a $BACKUP/$user.log
649 mkdir $tmpdir/user_dir
650 cd $HOMEDIR/$user
651
652 # Parsing directory exclusions
653 USER=''
654 if [ -e "$USER_DATA/backup-excludes.conf" ]; then
655 source $USER_DATA/backup-excludes.conf
656 fi
657 fargs=()
658 for xpath in $(echo "$USER" | tr ',' '\n'); do
659 if [ -d "$xpath" ]; then
660 fargs+=(--exclude="$xpath"/*)
661 echo "$(date "+%F %T") excluding directory $xpath" \
662 | tee -a $BACKUP/$user.log
663 else
664 echo "$(date "+%F %T") excluding file $xpath" \
665 | tee -a $BACKUP/$user.log
666 fargs+=(--exclude="$xpath")
667 fi
668 done
669
670 IFS=$'\n'
671 set -f
672 i=0
673
674 for udir in $(ls -a | egrep -v "^conf$|^web$|^dns$|^tmp$|^mail$|^\.\.$|^\.$"); do
675 exclusion=$(echo "$USER" | tr ',' '\n' | grep "^$udir$")
676 if [ -z "$exclusion" ]; then
677 ((i++))
678 udir_list="$udir_list $udir"
679 echo -e "$(date "+%F %T") adding $udir" | tee -a $BACKUP/$user.log
680
681 check_backup_conditions
682
683 # Backup files and dirs
684 if [ "$BACKUP_MODE" = 'zstd' ]; then
685 tar --anchored -cpf- "${fargs[@]}" $udir | pzstd -"$BACKUP_GZIP" - > $tmpdir/user_dir/$udir.tar.zst
686 else
687 tar --anchored -cpf- "${fargs[@]}" $udir | gzip -"$BACKUP_GZIP" - > $tmpdir/user_dir/$udir.tar.gz
688 fi
689
690 fi
691 done
692 set +f
693 udir_list=$(echo "$udir_list" | sed -e "s/ */\ /g" -e "s/^ //")
694
695 # Print total
696 if [ "$i" -eq 1 ]; then
697 echo -e "$(date "+%F %T") *** $i user directory ***" \
698 | tee -a $BACKUP/$user.log
699 else
700 echo -e "$(date "+%F %T") *** $i directories ***" \
701 | tee -a $BACKUP/$user.log
702 fi
703fi
704
705if [ "$BACKUP_MODE" = 'zstd' ]; then
706 touch $tmpdir/.zstd
707fi
708
709# Get backup size
710size="$(du -shm $tmpdir | cut -f 1)"
711
712# Get current time
713end_time=$(date '+%s')
714time_n_date=$(date +'%T %F')
715time=$(echo "$time_n_date" | cut -f 1 -d \ )
716date=$(echo "$time_n_date" | cut -f 2 -d \ )
717backup_new_date=$(date +"%Y-%m-%d_%H-%M-%S")
718
719echo -e "\n-- SUMMARY --" | tee -a $BACKUP/$user.log
720
721errorcode="0"
722# Switching on backup system types
723for backup_type in $(echo -e "${BACKUP_SYSTEM//,/\\n}"); do
724 case $backup_type in
725 local) local_backup ;;
726 ftp) ftp_backup ;;
727 sftp) sftp_backup ;;
728 b2) b2_backup ;;
729 rclone) rclone_backup ;;
730 esac
731done
732
733# Removing tmpdir
734rm -rf $tmpdir
735if [[ "$errorcode" != "0" ]]; then
736 if [[ "$BACKUP_SYSTEM" =~ "local" ]]; then
737 echo -e "$(date "+%F %T") *** Local backup was successfully executed. Remote backup failed ***" \
738 | tee -a $BACKUP/$user.log
739 BACKUP_SYSTEM="local"
740 else
741 echo -e "$(date "+%F %T") *** Remote backup failed ***" \
742 | tee -a $BACKUP/$user.log
743
744 exit $error_code
745 fi
746fi
747# Calculation run time
748run_time=$((end_time - start_time))
749run_time=$((run_time / 60))
750current_time=$(date "+%T")
751if [ "$run_time" -lt 1 ]; then
752 run_time=1
753fi
754min=minutes
755if [ "$run_time" -eq 1 ]; then
756 min=minute
757fi
758
759echo "$(date "+%F %T") Size: $size MB" | tee -a $BACKUP/$user.log
760echo "$(date "+%F %T") Runtime: $run_time $min" | tee -a $BACKUP/$user.log
761
762#----------------------------------------------------------#
763# Hestia #
764#----------------------------------------------------------#
765
766# Removing duplicate
767#touch $USER_DATA/backup.conf
768#sed -i "/$user.$backup_new_date.tar/d" $USER_DATA/backup.conf
769
770# Registering new backup
771#backup_str="BACKUP='$user.$backup_new_date.tar'"
772#backup_str="$backup_str TYPE='$BACKUP_SYSTEM' SIZE='$size'"
773#backup_str="$backup_str WEB='${web_list// /,}'"
774#backup_str="$backup_str DNS='${dns_list// /,}'"
775#backup_str="$backup_str MAIL='${mail_list// /,}'"
776#backup_str="$backup_str DB='${db_list// /,}'"
777#backup_str="$backup_str CRON='$cron_list'"
778#backup_str="$backup_str UDIR='${udir_list// /,}'"
779#backup_str="$backup_str RUNTIME='$run_time' TIME='$time' DATE='$date'"
780#echo "$backup_str" >> $USER_DATA/backup.conf
781
782# Removing old backups
783#tail -n $BACKUPS $USER_DATA/backup.conf > $USER_DATA/backup.conf_
784#mv -f $USER_DATA/backup.conf_ $USER_DATA/backup.conf
785#chmod 660 $USER_DATA/backup.conf
786#chmod 660 $BACKUP/$user.log
787
788# Deleting task from queue
789sed -i "/v-backup-user $user /d" $HESTIA/data/queue/backup.pipe
790
791#U_BACKUPS=$(grep BACKUP $USER_DATA/backup.conf | wc -l)
792#update_user_value "$user" '$U_BACKUPS' "$U_BACKUPS"
793cd $BACKUP
794
795# Send notification
796#if [ -e "$BACKUP/$user.log" ] && [ "$notify" = "yes" ]; then
797# subj="$user → backup has been completed"
798# email=$(get_user_value '$CONTACT')
799# cat $BACKUP/$user.log | $SENDMAIL -s "$subj" "$email" "$notify"
800# $BIN/v-add-user-notification "$user" "Backup created successfully" "<p><span class='u-text-bold'>Archive:</span> <code>$user.$backup_new_date.tar</code></p>"
801#fi
802
803# Logging
804#$BIN/v-log-action "$user" "Info" "Backup" "Backup created (Archive: $backup_new_date.tar)."
805$BIN/v-log-action "system" "Info" "Backup" "Backup created (User: $user, Archive: $backup_new_date.tar)."
806log_event "$OK" "$ARGUMENTS"
807
808exit