#!/bin/bash # Use forgejo dump to make a backup of Forgejo # Also restore from a previously made backup # https://docs.gitea.io/en-us/backup-and-restore/ set -eu set -o pipefail IFS="$(printf '\n\t')" PROGRAM="${0##*/}" INSTALL_DIR=/usr/local/bin TMP_DIR={{ forgejo_run_dir }}/tmp WORK_DIR={{ forgejo_run_dir }} DATA_DIR={{ forgejo_data_dir }} LOG_DIR={{ forgejo_log_dir }} REPO_DIR={{ forgejo_run_dir }}/forgejo-repositories/ CONFIG_FILE={{ forgejo_conf_dir }}/app.ini DUMP_DIR={{ forgejo_run_dir }}/forgejo-dumps MYSQL_USER={{ forgejo_db_user }} MYSQL_DB={{ forgejo_db_name }} MYSQL_PW={{ forgejo_db_pass }} {% raw %} if [ "$USER" != git ]; then echo "You must run this as user 'git'" && exit 1 fi print_help() { cat <<-_EOF $PROGRAM Usage: $PROGRAM {backup|restore |prune } Commands: backup Create a backup. Will save to $DUMP_DIR. restore Restore a previously created backup, given on the command line: , absolute path or relative to $PWD. prune Remove previously dumped backups and keep backups. Options: -h Print this help message and quit. _EOF } do_backup() { echo "Backing up Forgejo..." mkdir -p "$DUMP_DIR" mkdir -p "$TMP_DIR" stop_service output_dump_file="$DUMP_DIR/forgejo-dump-$(date +'%Y%m%d').tar" mysql_dump_file="$DUMP_DIR/forgejo-db.sql" cd "$INSTALL_DIR" || exit 1 ./forgejo dump -f "$output_dump_file" -c "$CONFIG_FILE" -t "$TMP_DIR" --skip-lfs-data -w "$WORK_DIR" --type tar mysqldump -u"$MYSQL_USER" -p"$MYSQL_PW" "$MYSQL_DB" > "$mysql_dump_file" restart_service cd "$DUMP_DIR" || exit 1 tar --delete -f "$output_dump_file" forgejo-db.sql tar --append -f "$output_dump_file" "$(basename $mysql_dump_file)" rm "$mysql_dump_file" chmod 640 "$output_dump_file" # Make the file readable by group for scp to different host by different user gzip "$output_dump_file" echo "Done." } do_restore() { echo "Restoring Forgejo backup..." start_dir="$PWD" tar_file="$1" tar_dir="${tar_file%.tar.gz}" # Remove file extension chmod 600 "$tar_file" # Backup has changed permissions, restore them here echo "Extracting $tar_file..." && mkdir "$tar_dir" && tar xvzf "$tar_file" -C "$tar_dir" && echo " OK." cd "$tar_dir" || exit 1 rm app.ini echo -n "Restoring $DATA_DIR..." && rsync -avz --delete data/ "$DATA_DIR" && rm -rf data && echo " OK." echo -n "Restoring $LOG_DIR..." && rsync -avz log/ "$LOG_DIR" && rm -rf log && echo " OK." echo -n "Restoring $REPO_DIR..." && mkdir -p "$REPO_DIR" && rsync -avz --delete repos/ "$REPO_DIR" && rm -rf repos && echo " OK." echo -n "Changing ownership..." && chown -R git:git "$CONFIG_FILE" "$WORK_DIR" && echo " OK." echo -n "Restoring MySQL database..." && mysql --default-character-set=utf8mb4 -u"$MYSQL_USER" -p"$MYSQL_PW" "$MYSQL_DB" < forgejo-db.sql && rm forgejo-db.sql && echo " OK." cd "$start_dir" || exit 1 rmdir "$tar_dir" restart_service regenerate_hooks echo "Done." } do_prune() { echo "Pruning Forgejo backups and keeping $1 of them..." dumps=("$DUMP_DIR"/forgejo-dump-*.tar.gz) nb_of_dumps="${#dumps[@]}" nb_to_keep="$1" nb_to_prune=$((nb_of_dumps - nb_to_keep)) if [ "$nb_to_prune" -gt "$nb_of_dumps" ]; then echo "There are only $nb_of_dumps backups, quitting." && exit 1 fi if [ "$nb_to_prune" -le 0 ]; then echo "Nothing to do" && exit 1 else for ((i=0; i < nb_to_prune; i++)); do echo -n "Removing ${dumps[$i]}..." && rm "${dumps[$i]}" && echo " OK." done fi } cleanup() { rm "${DUMP_DIR}/forgejo-db.sql" 2>/dev/null && echo "Removed leftover database dump" || echo "No leftover database dump" rm "$DUMP_DIR"/forgejo-dump-*.tar 2>/dev/null && echo "Removed leftover backup archive" || echo "No leftover backup archive" } regenerate_hooks() { echo "Regenerating hooks..." cd "$INSTALL_DIR" || exit 1 ./forgejo admin regenerate hooks --config "$CONFIG_FILE" && echo "Done." } stop_service() { echo -n "Stopping service..." && sudo systemctl stop forgejo.service && echo " OK." } restart_service() { echo -n "Restarting service..." && sudo systemctl restart forgejo.service && echo " OK." } [ "$#" = 0 ] || [ "$1" = '-h' ] && print_help && exit 1 if [ "$#" = 2 ]; then if [ "$1" = restore ]; then echo "STARTING restore" do_restore "$2" echo "DONE restore" elif [ "$1" = prune ]; then echo "STARTING prune" do_prune "$2" echo "DONE prune" else print_help && exit 1 fi elif [ "$#" = 1 ]; then if [ "$1" != backup ]; then print_help && exit 1 fi echo "STARTING backup" cleanup do_backup echo "DONE backup" else print_help && exit 1 fi exit 0 {% endraw %}