Pełny backup danych ze strony WWW dzięki CRON+Bash

Sytuacja z życia wzięta. Poszukiwałem jakiegoś dobrego sposobu, zautomatyzowanego najlepiej do systematycznego wykonywania kopii bezpieczeństwa  plików na serwerze, oraz bazy MySQL. Nic nie znalazłem, więc zacząłem nieco kombinować. W sieci jedyne pomocne rzeczy,  jakie znajdywałem to fakt, że:

  • najlepiej wykorzystać do tego Bash’a;
  • skoro ↑ to potrzeba też CRON’a.

Super – pomyślałem. Korzystam z Linuxpl.com, który stoi na serwerze Debian’owym, mam dostęp do CRON’a, więc wszystko da się zrobić. No ale, przecież nie znam Bash’a. Krótkie studiowanie samego języka, parę porad od (nie)znajomych i oto jest, mój pierwszy skrypt napisany w Bash’u, który zarazem niezmiernie może ułatwić mi życie.

Analiza kodu

#!/bin/bash
AKTUALNY=`date +%F`
WYWAL=`date +%F -d"-XX day"`

Zmienna AKTUALNY wprowadza do skryptu po prostu obecną datę – wykonania skryptu. WYWAL odejmuje od daty wykonania skryptu XX dni.

if [ -e /home/{user}/{katalog}/$WYWAL.7z ]
then
rm /home/{user}/{katalog}/$WYWAL.7z
tar cpvfP /home/{user}/{katalog}/www.tar /home/{user}/
/usr/local/mysql/bin/mysqldump {tabela_bazy} -u{użytkownik} -p{hasło} > /home/{user}/{katalog}/{tabela_bazy}.sql
7z a -mx9 /home/{user}/{katalog}/$AKTUALNY.7z /home/{user}/{katalog}/www.tar /home/{user}/{katalog}/{tabela_bazy}.sql
rm /home/{user}/{katalog}/www.tar /home/{user}/{katalog}/{tabela_bazy}.sql

Jeśli istnieje AKTUALNY – XX dni wtedy, podejmij akcje:

  1. Usuń plik AKTUALNY – XX dni;
  2. Stwórz kopię zapasową katalogu /home/ użytkownika, pakując go bez kompresji, z zachowaniem praw dostępu do pliku www.tar;
  3. Pobierz odpowiednią tabelę bazy danych i zapisz ją;
  4. Spakuj z maksymalną kompresją plik www.tar oraz kopię tabeli bazy danych do pliku AKTUALNY.7z;
  5. Usuń pozostawione zbędne pliki, które są w archiwum *.7z.

Jeśli natomiast na serwerze nie ma pliku AKTUALNY-XX dni podejmij te same akcje, ale nie usuwaj czegoś, czego nie ma i tak na serwerze (linia nr 7 ↑).

else
tar cpvfP /home/{user}/{katalog}/www.tar /home/{user}/
/usr/local/mysql/bin/mysqldump {tabela_bazy} -u{użytkownik} -p{hasło} > /home/{user}/{katalog}/{tabela_bazy}.sql
7z a -mx9 /home/{user}/{katalog}/$AKTUALNY.7z /home/{user}/{katalog}/www.tar /home/{user}/{katalog}/{tabela_bazy}.sql
rm /home/{user}/{katalog}/www.tar /home/{user}/{katalog}/{tabela_bazy}.sql
fi

W praktyce

Działanie skryptu jest bardzo proste. Pakuje wybrany przez nas folder do archiwum, następnie pobiera tabelę bazy MySQL, po czym pakuje obydwa pliki (archiwum i kopia bazy) i usuwa niepotrzebne pliki zostawiając jedno archiwum z kopią.

Ustawienia

W skrypcie (który załączę na końcu wpisu) napisałem, co należy zmienić i mniej więcej co należy posiadać. W razie pytań – komentujcie.

Dla przykładu, ja wykonuję skrypt raz na tydzień, więc nie mogę w polu XX day wpisać 30, ponieważ nie znajdzie mi takiego pliku z racji na fakt, że 7+7+7+7=28, a nie 30. Co daje więc efekt, że skrypt ma usunąć skrypt plik, który w nazwie ma aktualna_data-28dni – jest to jedyne rozwiązanie dla cotygodniowych backupów. Jeśli chcesz robić kopię codziennie, a po tygodniu usuwać stare kopie, to wpisujesz tam 7 – proste 8).

Najważniejsze jednak jest wykonanie prostego polecenia zmieniającego uprawnienia skryptu na wykonanie – bez tego ni rusz:

chmod +x skrypt.sh

Bądź z poziomu klienta FTP zmieniamy uprawnienia na 711.

Licencja

Skrypt udostępniam na licencji GPL v. 3. Co oznacza, że możecie z nim robić, co chcecie, ale zachowajcie dane autora ;). Byłbym niezmiernie wdzięczny za wszelakie sugestie rozwojowe, bo ktoś może mieć większy łeb ode mnie i podsunie jakieś pomysły.

Skrypt – pobieranie

Zaznacz wszystko i zapisz pod dowolną nazwą, z rozszerzeniem sh – a z poziomu CRON’a wpisujesz sh /home/{user}/{katalog}/backup.sh i ma działać. Pamiętaj o uzupełnieniu danych w skrypcie.

#!/bin/bash

# Skrypt wykonujący kopię plików na serwerze oraz wybranej tabeli bazy MySQL na serwerach Uniksowych z dostępem do zadań CRON.
# Autor: Filip (inzaghi89) Cierpich
# URL: http://keepmind.eu
# Mail: filip małpa keepmind dot eu
# Licencja: GPL v. 3

# By skrypt działał poprawnie należy:
# - Zamienić:
# -- XX na ilość dni
# -- {user} na naszą nazwę użytkownika w katalogu /home/ na danym serwerze
# -- {katalog} na folder/katalog, w którym ma być zapisana kopia - katalog MUSI być stworzony ręcznie
# -- {tabela_bazy} na tabelę, którą ma pobrać skrypt
# -- {użytkownik} na nazwę użytkownika, za pośrednictwem której logujemy się do PHPmyAdmin
# -- {hasło} na hasło, za pośrednictwem której logujemy się do PHPmyAdmin
#
# - Posiadać:
# -- Uprawnienia wykonania skryptu na serwerze
# -- Zainstalowaną paczkę p7z-full
# -- Dostęp do zadań CRON na serwerze

# 2010-03-20 modyfikacja skryptu dzięki uwadze JaspEra: http://blog.keepmind.eu/pelny-backup-danych-ze-strony-www-dzieki-cronbash.html#comment-856

AKTUALNY=`date +%F` #odpowiada za nazwę pliku - aktualna data, np. 2010-03-18
WYWAL=`date +%F -d"-XX day"` #odejmuje od aktualnej daty XX dni. Np. 2010-03-18 - 10 = 2010-03-08

if [ -e /home/{user}/{katalog}/$WYWAL.7z ]
then
rm /home/{user}/{katalog}/$WYWAL.7z #jeśli istnieje plik 2010-03-08.7z (czyli aktualna data - xx dni = usuń go)
fi
tar cpvfP /home/{user}/{katalog}/www.tar /home/{user}/ #pakuje katalog /home/{user}/ do pliku www.tar
/usr/local/mysql/bin/mysqldump {tabela_bazy} -u{użytkownik} -p{hasło} > /home/{user}/{katalog}/{tabela_bazy}.sql #pobiera tabelę_bazy, którą zdefiniujemy do pliku tabela_bazy
7z a -mx9 /home/{user}/{katalog}/$AKTUALNY.7z /home/{user}/{katalog}/www.tar /home/{user}/{katalog}/{tabela_bazy}.sql #pakuje z najwyższym stopniem kompresji do formatu 7z - wymagany pakiet p7z-full
rm /home/{user}/{katalog}/www.tar /home/{user}/{katalog}/{tabela_bazy}.sql #usuwa plik www.tar i tabela_bazy.sql, które krok wcześniej spakował

Komentarze

19 odpowiedzi na „Pełny backup danych ze strony WWW dzięki CRON+Bash”

  1. Awatar Piecia

    A projekt automysqlbackup http://sourceforge.net/projects/automysqlbackup/ nie byłby lepszy do backupu baz mysql?

    1. Do zrobienia backupu samej bazy SQL – możliwe, ale ja potrzebowałem backup wszystkiego.

  2. Awatar JaspEr

    A nie byłoby prościej, żeby w między if … fi umieścić kasowanie pliku (jeśli istnieje) a resztę wrzucić poza ten blok, bo i tak jest wykonywana (archiwizacja, mysqldump, kompresja)?

    if [ -e /home/{user}/{katalog}/$WYWAL.7z ]
      then
      rm /home/{user}/{katalog}/$WYWAL.7z #jeśli istnieje plik 2010-03-08.7z (czyli aktualna data - xx dni = usuń go)
    fi #jeśli nie ma
    
    tar cpvfP /home/{user}/{katalog}/www.tar /home/{user}/ #pakuje katalog /home/{user}/ do pliku www.tar
    /usr/local/mysql/bin/mysqldump {tabela_bazy} -u{użytkownik} -p{hasło} > /home/{user}/{katalog}/{tabela_bazy}.sql #pobiera tabelę_bazy, którą zdefiniujemy do pliku tabela_bazy
    7z a -mx9 /home/{user}/{katalog}/$AKTUALNY.7z /home/{user}/{katalog}/www.tar /home/{user}/{katalog}/{tabela_bazy}.sql #pakuje z najwyższym stopniem kompresji do formatu 7z - wymagany pakiet p7z-full
    rm /home/{user}/{katalog}/www.tar /home/{user}/{katalog}/{tabela_bazy}.sql #usuwa plik www.tar i tabela_bazy.sql, które krok wcześniej spakował
    

    Łatwiej potem, jeśli zajdzie potrzeba zmian modyfikować tylko jeden zestaw poleceń. To nie jest kwestia znajomości/nieznajomości basha, tak po prostu zrobiłbym to w jakimkolwiek „języku”.

    1. JaspEr: masz rację. Serdecznie dziękuję :), biorę się za poprawę zaraz.

  3. […] częściowo powstał w oparciu o kod opublikowany przez Filipa Cierpicha na jego […]

  4. Awatar Uruchomienie cron'em a ręcznie
    Uruchomienie cron’em a ręcznie

    Witam.
    Przy uruchomieniu za pomocą crona poniższego pliku ze skryptem jak wyżej:
    58 12 * * * root /root/cron_polecenia_skrypt/kompresja_kasowanie_thunderbird.sh

    skompresowany plik nie zawiera wszystkich plików.

    Po uruchomieniu ręcznie w pisując w terminalu polecenie:
    /./root/cron_polecenia_skrypt/kompresja_kasowanie_thunderbird.sh

    wszystkie dane są prawidłowo zapisane w piku tar i skompresowane za pocą 7z.

    Skrypt mam taki:

    #AKTUALNY5="mozilla-7z_`date +%F_%H.%M.%S`" #odpowiada za nazwę pliku - aktualna data, np. 2010-03-18
    WYWAL6_=thunderbird-7z_`date +%F_%H.%M.%S -d"-03 day"` 
    
    
    if [ -e /arch/Backup/$WYWAL6_.7z ]
    then
    rm /arch/Backup/$WYWAL6_.7z #jeśli istnieje plik 2010-03-08.7z (czyli aktualna data - xx dni = usuń go)
    fi
    tar cpvfP /arch/Backup/thunderbird.tar /home/dariusz/.thunderbird/ 
    #-u{użytkownik} -p{hasło} > /home/{user}/{katalog}/{tabela_bazy}.sql #pobiera #tabelę_bazy, którą zdefiniujemy do pliku 
    ##tabela_bazy
    7z a -mhe=on -pziyjctmmo1! -mx9 /arch/Backup/"thunderbird-7z_`date +%F_%H.%M.%S`".7z /arch/Backup/thunderbird.tar 
    #/home/{user}/{katalog}/{tabela_bazy}.sql pakuje z #najwyższym stopniem kompresji do formatu 7z - wymagany pakiet p7z-full
    rm /arch/Backup/thunderbird.tar 
    #/home/{user}/{katalog}/{tabela_bazy}.sql #usuwa plik www.tar i tabela_bazy.sql, które krok #wcześniej spakował
    
    echo "`date` thunderbird" >> /root/thunderbird.txt

    chmod -R 700 /arch
    chown -R root.root /arch/Backup

    Co z tym zrobić?
    Czy ktoś sie z tym już spotkał?

  5. W ogóle nie rozumiem Twojego wpisu z cron, dlaczego masz jako wykonanie skryptu sh: root /ściezka/skrypt.sh, a nie po prostu „sudo sh…”, albo „sh”.

    Cron dla roota zedytujesz poprzez crontab -e root. Tam dodaj sobie ten skrypt jako zapis:
    sh /root/cron_polecenia_skrypt/kompresja_kasowanie_thunderbird.sh

    Sam skrypt wydaje się być ok. Poza tym sprawdź syslog, czy jakimiś errorami nie pluje.

  6. Awatar Uruchomienie cron'em a ręcznie
    Uruchomienie cron’em a ręcznie

    Nic to nie daje, niestety.
    Szukam rozwiązania co z tym zrobić…

  7. hej,

    a da się wykonać polecenie cron z pominięciem danego katalogu?

    pzrd

    1. Tak, jest taka możliwość. Odpowiada za to „opcja” –exclude w tar. Przykład

      tar cpvfP /backup/home.tar /home/ –exclude /home/katalog

  8. Jak tak stworzoną kopię przywrócić, tzn. zastąpić aktualne pliki wykonaną kopią.

    W skrócie jak z tych kopii zrobić backup?

    1. Rzekłbym – od tyłu :).
      7z x /home/{user}/{katalog}/$AKTUALNY.7z #Gdzie AKTUALNY do data backupu.
      I tutaj polecam np. MidnightCommander żeby wybrać sobie foldery/pliki, które chcesz wypakować i nadpisać z archiwum tar.
      By przywrócić bazę MySQL:
      /usr/local/mysql/bin/mysql {tabela_bazy} -u{użytkownik} -p{hasło} < /home/{user}/{katalog}/{tabela_bazy}.sql

  9. Awatar Przemek

    Proszę o pomoc,

    Jak dokładnie powinien wyglądać plik jeśli nie mam możliwości granie 7z i chciałbym pełny backup zapisywać jako tar ? Oraz dodać przykładowo dwie bazy danych do porabia.

    P.S. Świetny skrypt :)

    1. Jeśli nie masz możliwości instalacji 7z, to usuń po prostu linijkę z 7z (#33), która odpowiada za pakowanie/kompresję. Polecam jednak czymś sobie to skompresować. Rar, zip, cokolwiek.

      W linii 34 znajduje się komenda do zrzutu bazy danych do pliku. Musisz podać login i hasło do bazy danych oraz jej nazwę. Następnie wskazać gdzie plik ma się zapisać.

  10. Awatar Norfear

    Macie może pomysł jak zrobić do tego automatyczne kasowanie staszych plików niz 3 dni?
    I pytanie numer dwa czy można jakoś zamienić tego tara na gzipa?

    AKTUALNY2=”www_`date +%F_%H.%M`”
    WYWAL2=www_`date +%F_%H.%M -d”-03 day”`

    if [ -e /home/xxx/backup/$WYWAL2.tar ]
    then
    rm /home/xxx/backup/$WYWAL2.tar
    fi
    tar -zcvf /home/xxx/backup/”www_`date +%F_%H.%M`”.tar /home/xxx/public_html/

    1. Hej, co do pytań. Masz poprawiony skrypt uwzględniający usuwanie archiwów sprzed 3 dni ;). Dodatkowo atrybut „-z” kompresował archiwum gzipem. Dodałem rozszerzenie tylko.

      AKTUALNY2="www_`date +%F_%H.%M`"
      WYWAL2="www_`date +%F_%H.%M -d --date="3 days ago`"
      
      if [ -e /home/xxx/backup/$WYWAL2.tar ]
      then
      rm /home/xxx/backup/$WYWAL2.tar
      fi
      tar -zcvf /home/xxx/backup/"www_`date +%F_%H.%M`".tar.gz /home/xxx/public_html/
      1. Awatar Norfear

        Dziękuje za poprawiony skrypt.

        1. Czy plik spakowany musi tak się kończyć *.tar.gz nie może być po prostu samo *.gz?

        2. Jednak kasowanie jak nie działało tak nie działa.
        Przykładowe poprzednie nazwy pliku w tym folderze gdzie może kasować i tworzyć pliki to:

        www_2018-03-23_09.42.tar
        www_2018-03-24_14.22.tar
        www_2018-03-25_00.00.tar
        www_2018-03-27_08.15.tar.gz (no i ten nowy poprawiony skrypt)

        1. Teraz jeszcze zerknąłem i źle wkleiłem też w poprzednim komentarzu. Nie dodałem .gz do pozostałych nazw plików. I nie, nie musi się nazywać .tar.gz żeby był skompresowany plik. Może być jak najbardziej samo .tar.

          Poza tym teraz dopiero zauważyłem, że skoro chcesz usuwać poprzednie dni, robisz kopię codziennie, to bez sensu żeby sprawdzało godziny kopii. Ten skrypt będzie usuwał kopie, które powstały dokładnie 3 dni temu.

          AKTUALNY="www_`date +%F`"
          WYWAL="www_`date +%F --date="3 days ago"`"
           
          if [ -e /home/xxx/backup/$WYWAL.tar ]
          then
          rm /home/xxx/backup/$WYWAL.tar
          fi
          tar -zcvf /home/xxx/backup/$AKTUALNY.tar /home/xxx/public_html/

          Możesz również zrobić to w ten sposób:

          AKTUALNY="www_`date +%F`"
          
          find /home/xxx/backup/www\_* -mtime +3 -exec rm {} \;
          tar -zcvf /home/xxx/backup/$AKTUALNY.tar /home/xxx/public_html/

          Wówczas skrypt usunie wszystkie pliki starsze niż 3 dni.

          1. Awatar Norfear

            No no no przyznaje. Ze ten skrypt drugi spełnił moje wymogi w 100% :) Bardzo dziękuje za gotowca

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *