├── .gitignore ├── README.md ├── backup.py ├── config.py └── logger.py /.gitignore: -------------------------------------------------------------------------------- 1 | venv/ 2 | .idea/ 3 | __pycache__/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linux Backup Script 2 | 3 | A script to create backups on linux systems. 4 | 5 | ## How to use the script 6 | 7 | Install [rClone](https://rclone.org/downloads/) and set up your preferred cloud storage 8 | ```shell 9 | curl https://rclone.org/install.sh | sudo bash 10 | rclone config 11 | ``` 12 | 13 | - To use a specific folder in your cloud storage, fill in the `root_folder_id` value 14 | - **Example:** If you use [pCloud]((https://www.pcloud.com/login)), you can navigate to a folder and copy the folder ID from the url bar 15 | - If you are on a headless machine, you might need to download rClone on a device with access to an internet browser 16 | - In Windows, open `cmd` and navigate to the folder with the `rclone.exe` file 17 | - Paste the displayed command into `cmd` and paste the response back into the rClone configuration. 18 | 19 | Install tmux and create new session for [mounting](https://rclone.org/commands/rclone_mount/) 20 | ```shell 21 | apt install tmux 22 | tmux new -s backup 23 | 24 | # is the name you chose for the remote in the rclone config 25 | rcloune mount : /path/to/empty/folder --vfs-cache-mode writes 26 | ``` 27 | Clone this repository and edit `config.py` 28 | ```shell 29 | git clone https://github.com/tibue99/linux-backup 30 | ``` 31 | End mounting 32 | ```shell 33 | fusermount -uz /linux/path 34 | ``` 35 | 36 | ## Manual backup 37 | ```shell 38 | python3 backup.py 39 | ``` 40 | 41 | ## Automatic backup 42 | Set a cronjob to backup periodically. This [cronjob](https://crontab.guru/#0_3_*_*_*) creates a backup every day at 3 AM. 43 | ```shell 44 | crontab -e 45 | 0 3 * * * python3 /path/to/backup.py 46 | 47 | # View cronjobs 48 | crontab -l 49 | ``` 50 | 51 | ## Credits 52 | 53 | This repository is based on the code of [Tutorialwork](https://github.com/Tutorialwork/Linux-Backup-Script). -------------------------------------------------------------------------------- /backup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | from sys import platform 4 | 5 | import config 6 | from logger import Logger 7 | 8 | date = time.strftime(config.date_format) 9 | logger = Logger("backup.log") 10 | 11 | 12 | def os_check(): 13 | """Check if the script is running on a unix based operating system""" 14 | if platform.startswith('linux') or platform == 'darwin': 15 | return True 16 | else: 17 | return False 18 | 19 | 20 | def mysql_backup(): 21 | logger.log("INFO", "Starting backup for MySQL database...") 22 | tmp_check = os.system(f"cd {config.backup_location}") 23 | if tmp_check == 0: 24 | mysql_backup_file_name = f"{get_file_name('mysql_backup')}.sql" 25 | create_backup = os.system( 26 | f"cd {config.backup_location} && mysqldump -u {config.mysql_user} -p '{config.mysql_password}'" 27 | f" --all-databases > {mysql_backup_file_name}" 28 | ) 29 | if create_backup == 0: 30 | logger.log("SUCCESS", "MySQL database backup created successfully") 31 | else: 32 | logger.log("ERROR", "MySQL database backup failed") 33 | os.system(f"cd {config.backup_location} && rm {mysql_backup_file_name}") 34 | else: 35 | logger.log("ERROR", "Mount not exits") 36 | 37 | 38 | def backup(): 39 | logger.log("INFO", f"Starting backup for {len(config.backup_dirs)} directories...") 40 | if len(config.backup_dirs) == 0: 41 | logger.log("INFO", "No directories to backup") 42 | else: 43 | exclude_str = "" 44 | for file in config.exclude: 45 | exclude_str += f"--exclude '{file}' " 46 | 47 | for index, folder in enumerate(config.backup_dirs): 48 | backup_file_name = get_file_name(f"backup{index + 1}.tar.gz") 49 | logger.log("INFO", f"Starting backup for {folder}...") 50 | status = os.system( 51 | f"cd {config.backup_location} && tar {exclude_str} -czvf {backup_file_name} {folder}" 52 | ) 53 | if status == 0: 54 | logger.log("SUCCESS", f"Backup for {folder} created successfully") 55 | else: 56 | logger.log("ERROR", f"Failed to backup {folder}") 57 | 58 | 59 | def clear_backups(): 60 | logger.log("INFO", "Cleaning backup dir...") 61 | for file in os.listdir(config.backup_location): 62 | if os.path.isfile(file): 63 | os.remove(file) 64 | elif os.path.isdir(file): 65 | os.rmdir(file) 66 | else: 67 | logger.log("ERROR", f"{file} can't be deleted!") 68 | logger.log("SUCCESS", "Successfully deleted old backup files") 69 | 70 | 71 | def get_file_name(name): 72 | file_name = config.backup_name_format 73 | file_name = file_name.replace('%date%', date) 74 | file_name = file_name.replace('%backup_name%', name) 75 | logger.log("INFO", f"Name for backup file: {file_name}") 76 | return file_name 77 | 78 | 79 | if os_check(): 80 | if os.path.exists(config.backup_location): 81 | if config.clear_backups: 82 | clear_backups() 83 | if config.mysql_backup: 84 | mysql_backup() 85 | backup() 86 | else: 87 | logger.log("ERROR", "Failed to create backup") 88 | logger.log("ERROR", f"{config.backup_location} does not exist") 89 | else: 90 | logger.log("ERROR", "Sorry, this script is only for Linux or macOS") 91 | 92 | logger.close_file() 93 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | # Locations to back up 2 | backup_dirs = ["/home"] 3 | 4 | # Exclude files or directories from backup 5 | exclude = ["__pycache__", "venv"] 6 | 7 | # Location for final backup 8 | backup_location = "/media/backup" 9 | 10 | # File name for final backup 11 | backup_name_format = "%date%_%backup_name%" 12 | 13 | # Date format for file name 14 | date_format = "%Y-%m-%d_%H-%M" 15 | 16 | # Delete old backups? 17 | clear_backups = False 18 | 19 | # MySQL 20 | mysql_backup = False 21 | mysql_user = "root" 22 | mysql_password = "" 23 | -------------------------------------------------------------------------------- /logger.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | 4 | class Logger: 5 | def __init__(self, file_name): 6 | self.file = open(file_name, "a") 7 | 8 | def log(self, log_level, message): 9 | log_msg = f"[{datetime.now()}] {log_level}: {message}" 10 | self.file.write(f"{log_msg}\n") 11 | print(f"\n{log_msg}\n") 12 | 13 | def close_file(self): 14 | self.file.close() 15 | --------------------------------------------------------------------------------