Sie sind hier : Homepage →  TYPO3 CMS - Info+Install→  Typo3 (4) Server Backup→  typo3 - Copy-Home script

Die Grundidee : die Daten automatisch auf einen entfernten Backup-Server oder eine entfernte NAS Station schicken.

Unsere Backups sollen nicht nur automatisch und sicher laufen. Die Daten müssen auch unbedingt periodisch auf eine "entfernte" Lokation (zum Beispiel zu uns ins Büro) kopiert werden. Darum wird auf jedem Server (im Idelafalle) täglich eine Sicherung aller Typo3 Domains automatisiert auf eine im Server vorhandene separate Backup-Platte kopiert. Das ist hier bereits ausführlich besprochen worden.

Und zur Zeit einmal am Wochende wird Nachts gleichzeitig mit der normalen Sicherung auch ein "scp"-Transfer "auf einen Server weit weg" gestartet.

Und wie wir das gelöst haben, kommt jetzt.

"SCP" ist das sogenannte "secure copy programm".

Dieses Kopierprogramm nutzt die gleichen Verschlüsselungsmechanismen, die auch putty benutzt. Sie können per scp Dateien von SSH-Server zu SSH-Server kopieren. Doch wir wollen es per Cronjob und Shell-Scripten automatisieren und Nachts laufen lassen.

Unsere Grundlagen sind die laufenden TYPO3-Server in unserem Datacenter, bei uns alles auf Linux unter Suse. Und die Ziele sind bei uns autarke lokale Buffalo NAS Boxen auch alles auf Linux mit Terabyte-Platten im lokalen Firmen-EDV-Raum hinter unserer Firewall.
.

Die Vorbereitung zum automatischen scp handshake per SSH.

Mitten in unserem "copyhome" Script befindet sich die Zeile mit dem "scp" (secure copy) Kommando.

Doch Nachts ist niemand da, der das Passwort für die sichere Verbindung eintippt. Um das zu automatisieren, muß man die Schlüssel auf dem Quell-Server erzeugen und auf dem Ziel-Server hinterlegen.

Das machen wir so:

Auf dem Quell-Server (oder Rechner) (bei uns Suse Linux) erzeugt man
als "root" User oder mit "sudo ssh-keygen -t dsa" und 3 x ENTER den Schlüssel und damit erhält man den Keyfile (den Schlüssel) im Verzeichnis "/root/.ssh/id_dsa.pub".

ssh-keygen -t dsa

Generating public/private dsa key pair.
Enter file in which to save the key (/root/.ssh/id_dsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_dsa.
Your public key has been saved in /root/.ssh/id_dsa.pub.
The key fingerprint is:
38:b4:30:16:22:62:f8:47:81:31:c4:bc:f1:08:06:6c root@www51.ipw.net
The key's randomart image is:
+--[ DSA 1024]----+
|B==oo.           |
|=E=o..           |
|oo *+ .          |
|  +.o+ o         |
|   .  + S        |
|       .         |
|                 |
|                 |
|                 |
+-----------------+
damit ist das Programm fertig
[www51] / $

Dieser Schlüssel (also der Inhalt der Datei) muß muss dann (mit winscp oder anderen Hilfsmitteln) auf den Zielrechner (bei uns die Buffalo-Linkstation) in den neu anzulegenden File "/root/.ssh/authorized_keys" kopiert werden. Dieser File "authorized_keys" kann mehrere keys (Schlüssel) sowohl von mehreren Usern und als auch Quell-Servern enthalten (man muß das editieren).

Zum Editieren ist der "joe" nicht so gut geeignet, weil er diese langen Zeilen am Bildschirmende abtrennt und einfach nicht überträgt.)

Der Schlüssel ist an den Hostnamen und Usernamen gebunden. Bei uns laufen alle diese "copyhome" Skripte als "root"! Zum Debuggen kann man SCP mit der Option "-v" aufrufen.

Hier kommt das gesamte "copy-home" Shell-Script Verion 2.8

#!/bin/bash -u

# option "-u" = exit the script if a variable is missing content
# call with option -x to debug
# it must be bash, in order to use arrays
#
# Backup Typo3 Installation, 2009-07-11 Rudolf Reuter
# put script in the target folder and start from there.
# backup 3 folder /fileadmin/, /typo3conf/ and /uploads/ und die global-extensions and gzip
# backup als mysql dump der einzelnen typo3 database
# C3. gzip archive
# FD send activity email, or FTP
#
# possible only with the help of www.tldp.org/LDP/abs/abs-guide.pdf
#   abs = advanced bash scripting
# Version is shown at the log echo .

# 2010-01-04-GR V2.3 die globalen banner-bilder werdenmit gesichert - /typo3/banner-vorlagen
# der scp copy Bereich ist nur noch hier drinnen
#
# 2010-01-19-GR V2.7 - zz ist jetzt zz_log_text und kleine Fehler sind raus
# 2010-01-24-GR V2.8 - alle passwoerter jetzt in Variablen kommen aus server.dat
#
# copy home inklusive backup !!!!!
#

# includefile 1: domain-data file with multi-domain !!! parametern
source domains.dat
element_count=${#ROOT[@]}

# includefile 2: server-data with server name, Linux version, folder path
source server.dat
echo "==== domains.dat und server.dat gelesen ======"

# System setup - hier nichts ändern, nur in Haupt-Script !!
VERSION="2.8 vom 24.01.2010 -rr-gr"
LOCKFILE="/var/lock/bak_typo3_$$.lock"
PRODUCTION=0  # 0= testing, 1= PRODUCTION - dieser mode wird automatisch gesetzt

# wenn in server.dat das Prefix-Webverzeichnis gesetzt ist, dann ist es immer production = 1
# wenn Variable leer, dann lokaler Testmodus

if test -d $PFXWWW; then
  PRODUCTION=1
  echo "==== Produktions-Version = 1 erkannt ======"
 
else
  PFXWWW="/var/lib"  # for testing only
  echo "==== Test-Version = 0 !!!!  erkannt ======"
fi

# todo : jahreszahl abfragen und verzeichnis automatisch erzeugen bzw. abprüfen

if ! test -d $PFXBAK; then
  PFXBAK="/bak-vol"    # for Production - steht aber auch in server.dat !!!
fi

SCPTEMPDIR="/bak-vol/scp-tmp-dir"
mkdir "$SCPTEMPDIR"
   
DATE=$(date +"%Y%m%d")       # e.g. 20090711
NOW=$(date +"%Y%m%d%H%M")   # e.g. 200907111709
MYSQLSERVER=127.0.0.1




#####  SCP Kennwort handshake Initialisierung - wird in diesem Script gebraucht !!
# SCP without password prompt: client: ~/ssh-keygen -t dsa 3xENTER, copy ~/.ssh/id_dsa.pub to server (Buffalo) ~/.ssh/authorized_keys
SCPENA=1  # set to 0 to disable, 1 = enabled
if [ $PRODUCTION -eq "1" ]; then
    # scp geht über die Durchleitung der Fritzbox !!!!!! dort IP des Inhaus-Servers eintragen
    echo "==== Production = 1 - scp home ist aktiviert"
    #  SCPHOST und SCPUSER und SCPTARGET stehen jetzt alle in server.dat !!
    else
    # testversion wird local nach Inhaus-Server gesendet
      SCPHOST="192.168.17.100"
      SCPUSER="root"
      SCPTARGET="/mnt/disk1/share"
    fi
    # In case of an error, send an email to $EMAILADR, takes 2 parameters: 1. command, 2. line number
    function test_error_email() {
    if [ ! "$?" == "0" ]; then
      echo "Folder: $BACKUPDIR, Time: $NOW, $1, LINENO: $2 "  | mail -s "backup-typo3.sh, Fehler auf $RDESERVER" "$EMAILADR1"
    fi
}
#####  SCP Kennwort handshake Ende =================================



function A_bakup_folder() {
  #  ACHTUNG: wir sichern von jetzt an alles mit dem relativen Pfad (ab Version 2.0 !!!)
  #  bei der tar Zeile das  -P nicht vergessen - don't strip leading `/´s from file names

  echo "==== pushd nach $dompath"
  pushd $dompath > /dev/null
  tar -Pzcf $BACKUPDIR/$NOW-$idom-$domainroot-fileadmin.tgz "fileadmin"
  test_error_email 'Error: tar fileadmin' $LINENO
  echo "==== $domainroot == fileadmin gepackt"
  tar -Pzcf $BACKUPDIR/$NOW-$idom-$domainroot-typo3conf.tgz "typo3conf"
  test_error_email 'Error: tar typo3conf' $LINENO
  echo "==== $domainroot == typpo3conf gepackt"
  tar -Pzcf $BACKUPDIR/$NOW-$idom-$domainroot-uploads.tgz "uploads"
  test_error_email 'Error: tar uploads' $LINENO
  echo "==== $domainroot == uploads gepackt"
  popd > /dev/null
  #  echo "==== popd ausgefuehrt"
  echo "==== $domainroot == alle 3 Verzeichnisse gepackt"


#  Typo3 globale Files sichern - wird nur einmal ausgefuehrt - fuer eine typo3 version -muss noch verbessert werden !!
    if test ! -e "$BACKUPDIR/$NOW-typo3-globale-ext.tgz" ; then
    pushd $dompath > /dev/null
    tar -Pzcf $BACKUPDIR/$NOW-typo3-globale-ext.tgz "typo3/ext"
    test_error_email 'Error: tar typo3-global-ext' $LINENO
    echo "==== Hier wurden die globalen Typo3-Extensions gepackt"
    tar -Pzcf   $BACKUPDIR/$NOW-typo3-globale-werbebanner-folder.tgz "typo3/banner-vorlagen"
    cp "$BACKUPDIR/$NOW-typo3"* $SCPTEMPDIR ##  ist ein Klimmzug : es wird nur eine Version bei der ersten Domain mit kopiert
    test_error_email 'Error: tar globale banner-vorlagen' $LINENO
    echo "==== Hier werden die globalen Werbe-Banner-Vorlagen gepackt"
    popd > /dev/null
  fi  
  dummy="dummy"
}






# Funktion B - wird nicht mehr benutzt - wird demnaechst ein eigenes script werden === TEMPLATE only ===
function B_rm_temp() {   
  # delete all files, but not index.html - Not needed, if cache is not emptied
  #rm `find $dompath/typo3temp/GB -type f \( ! -iname "." \) | grep -v index.html`
  #rm `find $dompath/typo3temp/llxml  -type f \( ! -iname "." \) | grep -v index.html`
  #rm `find $dompath/typo3temp/pics -type f \( ! -iname "." \) | grep -v index.html`
  #rm `find $dompath/typo3temp/temp -type f \( ! -iname "." \) | grep -v index.html`
  dummy="dummy"
}




function C_bakup_database() {
# Flush TYPO3 All Caches   === TEMPLATE only ===
#for table in $TABLES
#  do
#    mysql -e 'TRUNCATE TABLE '"$table"'' -h $MYSQLSERVER -D $TYPO3DB -u $TYPO3USER --password=$TYPO3PASS
#    dummy="dummy"
#  done
#mysqldump -h $MYSQLSERVER -u $TYPO3USER -p$TYPO3PASS $TYPO3DB | gzip >$BACKUPDIR/$NOW-$domain-DB-mysql.sql.gz


# Backup databases, ignore all cache_* tables aus Typo3 Version 4.2.6
EX1="--ignore-table=$TYPO3DB.cache_extensions"
EX2="--ignore-table=$TYPO3DB.cache_hash"
EX3="--ignore-table=$TYPO3DB.cache_imagesizes"
EX4="--ignore-table=$TYPO3DB.cache_md5params"
EX5="--ignore-table=$TYPO3DB.cache_pages"
EX6="--ignore-table=$TYPO3DB.cache_pagesection"
EX7="--ignore-table=$TYPO3DB.cache_typo3temp_log"

# Temp-Index databases index search
EX8="--ignore-table=$TYPO3DB.index_fulltext"
EX9="--ignore-table=$TYPO3DB.index_grlist"
EX10="--ignore-table=$TYPO3DB.index_grlist"
EX11="--ignore-table=$TYPO3DB.index_rel"
EX12="--ignore-table=$TYPO3DB.index_section"
EX13="--ignore-table=$TYPO3DB.index_stat_search"
EX14="--ignore-table=$TYPO3DB.index_stat_word"

mysqldump -h $MYSQLSERVER -u $TYPO3USER -p$TYPO3PASS $EX1 $EX2 $EX3 $EX4 $EX5 $EX6 $EX7 $EX8 $EX9 $EX10 $EX11 $EX12 $EX13 $EX14 $TYPO3DB | gzip >$BACKUPDIR/$NOW-$idom-$domainroot-DB-mysql.sql.gz
test_error_email 'Error: mysqldump' $LINENO
echo "==== Gesamte mysql Datenbank fuer $domainroot ist gedumpt und ist gepackt"
# Deny file access to database backups
# chmod 600 -R $BACKUPDIR/
}




function D_scp-copy-home-loop() {
   if [ $SCPENA -eq 1 ]; then  # wenn production - dann secure copy to target storage
              #  tar bakup for scp transfer
              echo "transfer-file wird vorbereitet - Beginn at  : "`date`>>$zz_log_file
              echo "==== Es wird der scp transfer-file vorbereitet at: "`date`
              cp "$BACKUPDIR/$NOW-$idom-$domainroot"* $SCPTEMPDIR
              echo "==== tar files $domainroot nach $SCPTEMPDIR kopiert"
              echo "==== Datenmenge im folder $SCPTEMPDIR = " "`du -s -h $SCPTEMPDIR`"
              ##       ls -l "$SCPTEMPDIR"
              ## read input
              tar -Pcf "$PFXBAK/$NOW-$idom-$domainroot.tar" "$SCPTEMPDIR"*
              ## read input
              echo "==== $domainroot files in transfer-file nach $BACKUPDIR gepackt "
              ## echo "==== Kontrolle :"
              ## ls -l "$PFXBAK"
              rm  "$SCPTEMPDIR"/*.*
              echo "==== Folder $SCPTEMPDIR muss wieder leer sein (4,0K)  ""`du -s -h $SCPTEMPDIR`"
              echo "==== $domainroot == SCP transfer Start at: "`date`
## ---------- hier steht die scp Zeile
##              scp -pq $PFXBAK/$NOW-$idom-$domainroot.tar $SCPUSER@$SCPHOST:$SCPTARGET
## ---------- scp Uebertragung der Inhalte
              ## echo "==="
              ## Find out if scp backup file failed or not
                 if [ "$?" == "0" ]; then
                   echo "==== $domainroot == SCP transfer End   at: "`date`
                   ##          cp -f $PFXBAK/$NOW-$domainroot.tar /tmp
                   rm -f $PFXBAK/$NOW-$idom-$domainroot.tar
                   echo "SCP transfer file wird wieder geloescht at  : "`date`>>$zz_log_file
                   echo "==== $domainroot == SCP transfer file ist wieder geloescht! "
                   # secure copy log file addtitional to TAR archive
                 ## finale scp Aktion Nr 3
                   scp -pq $zz_log_file $SCPUSER@$SCPHOST:$SCPTARGET # # soll hier stehen bleiben, falls Script-Abbruch
                   #          email_body=/tmp/scp.ok
                 else
                   email_body=/tmp/scp.fail
                   echo "Date: $(date)">$email_body
                   echo "Hostname: $(hostname)" >>$email_body
                   echo "Backup Set: $BACKUPDIR" >>$email_body
                   echo "SCP failed" >>$email_body
                   mail  -s "SCP FAILED - Kopiervorgang auf Buffalo Box failed " "$EMAILADR1"  <$email_body
                   rm -f $email_body
                   echo 'Dieser SCP transfer Vorgang failed at: '`date`>>$zz_log_file
              fi
            fi
}



# Funktion E - gepackte Scripte, Logfile und /etc/ in transfer-file packen und übertragen
function E_scp-copy-home-once() {
   if [ $SCPENA -eq 1 ]; then  # wenn production - dann secure copy to target storage
      ## Nachtrag ab Version 2.6: die verwendeten Shell-Scripte müssen auch uebertragen werden !!!
      ## zuerst das /etc/ Verzeichnis senden
      echo "/etc/ Folder und Backup Scripte werden uebertragen - Beginn at  : "`date`>>$zz_log_file
      echo "==== Backup Scripte werden uebertragen - Beginn at  : "`date`
      scp -pq $BACKUPDIR/$NOW-98-www9-folder-etc.tar.gz $SCPUSER@$SCPHOST:$SCPTARGET
      echo "das gesamte $RDESERVER /etc/ Verzeichnis ist übertragen at  : "`date`>>$zz_log_file
##    rm $BACKUPDIR/$NOW-98-www9-folder-etc.tar.gz
      scp -pq $BACKUPDIR/$NOW-97-benutzte-backup-scripte.tar.gz $SCPUSER@$SCPHOST:$SCPTARGET

      echo "Gepackte Backup-Scripte übertragen at  : "`date`>>$zz_log_file
      scp -pq $zz_log_file $SCPUSER@$SCPHOST:$SCPTARGET # finaler Log-file nach letztem scp Transfer                                      
   fi
}   
##### Funktion E Ende







# main routine -------------------------------------------------------------------------------
if [ ! -e $LOCKFILE ]; then
  trap "rm -f $LOCKFILE; exit" INT TERM EXIT
  touch $LOCKFILE
  # make the backup folder, if not yet done - Achtung - der Jahresfolder muss bereits angelegt sein !!!
  BACKUPDIR="$PFXBAK/$DATE"
  if test ! -d "$BACKUPDIR" ; then
    mkdir "$BACKUPDIR"
    test_error_email 'Error: mkdir $BACKUPDIR' $LINENO
  fi


 
  # write start time and infos to a logfile
  zz_log_file="$BACKUPDIR/$NOW-99-backup-log-datei.txt"
  echo 'Sicherungsscript copy-home Backup Start at: '`date` >>$zz_log_file
  test_error_email 'Error: creating log file' $LINENO
  echo 'Script Version:' $VERSION >>$zz_log_file  # take care about version number !
  echo 'user ID       :' $UID >>$zz_log_file
  echo 'Linuxversion  :' $LINUXVERSION >>$zz_log_file  
  echo 'Server        :' $RDESERVER >>$zz_log_file
  echo 'Mail1         :' $EMAILADR1 >>$zz_log_file
  echo 'Mail2         :' $EMAILADR2 >>$zz_log_file


## ein Trick aus kosmetischen Gruenden (Kontrolle der Domain-Sicherungen und Dateinamen)
idom=10   ##  NEU: Domain Zaehler startet zweistellig mit 10 !!!!!
element_count=$[$element_count+9]


  while [ $idom -le $element_count ];  ## die main-routine zaehlt die Domains aus array domain.dat hoch
  do
    domainroot=""
    domainroot="${ROOT[$idom]}"
    domainname="${DOMA[$idom]}"
    dompath="$PFXWWW/$domainroot"
    echo "==== --------------------------------------------------------------------------------"
    echo "==== --------------------------------------------------------------------------------" >>$zz_log_file
    echo "XXXX Main-Loop Nr. $idom == $domainroot - Start at : "`date`
    echo "XXXX Main-Loop Nr. $idom == $domainroot - Start at : "`date` >>$zz_log_file

    if test -d "$PFXWWW/$domainroot"; then   # test if domain folder exists
      UIDROOT=0
      if [ $UID -gt $UIDROOT ]; then   #  echo only if not user root (=cron job)
        echo "Backup of domain-root: $domainroot"
      fi
      TYPO3DB="${DBNA[$idom]}"
      TYPO3USER="${DBUS[$idom]}"
      TYPO3PASS="${DBPW[$idom]}"

      echo 'domain-root   :'$domainroot >>$zz_log_file
      echo 'domain-name   :'$domainname >>$zz_log_file
      echo 'typo3database :'$TYPO3DB >>$zz_log_file
      echo 'typo3user     :'$TYPO3USER >>$zz_log_file
      echo 'typo3password :'$TYPO3PASS >>$zz_log_file
      echo 'typo3version  :'`ls -l $dompath | grep "typo3_src "`>>$zz_log_file  # log typo3 version

## ==================   Aufruf der Unterroutinen
      A_bakup_folder
##    B_rm_temp
      C_bakup_database
      D_scp-copy-home-loop

   fi
   idom=$[$idom+1] # increase index number
  done
## ==================   Ende des Main Loops - Abschluss des Scriptes mit Mail und Logfile




## =============================   write end time to the logfile
  echo 'end at  : '`date`>>$zz_log_file
  echo "==== "
  echo '==== Ende des Main-Loops at: '`date` '- jetzt wird der Logfile geschrieben.'

## read input

##  sichere alle scripte in /etc/backup Verzeichnis
  tar -Pzcf $BACKUPDIR/$NOW-97-benutzte-backup-scripte.tar.gz *
  test_error_email 'Error: save backup-script' $LINENO
  echo "das gesamte $RDESERVER /etc/ Verzeichnis wird gepackt "`date`>>$zz_log_file
  echo "==== das gesamte $RDESERVER /etc/ Verzeichnis wird gepackt "
  ## zuerst das /etc/ Verzeichnis packen
  tar -Pzcf $BACKUPDIR/$NOW-98-www9-folder-etc.tar.gz "/etc"
  echo "==== das gesamte $RDESERVER /etc/ Verzeichnis ist fertig gepackt "


  ## ab Version 2.6: die gepackten Scripte müssen auch uebertragen werden !!!
  E_scp-copy-home-once


  chmod 600 -R $BACKUPDIR/

  # write the contents of the backup directory into the logfile, only the last one.
  ls -l $BACKUPDIR'/'$NOW* >>$zz_log_file


  # send email on success,  in PRODUCTION mode only
  if [ $PRODUCTION -eq 1 ]; then
    cd $BACKUPDIR

echo "==== Jetzt wird die Mail vorbereitet . . . . ==="
## read input

    mail  -s "Der copy-home-Script auf $RDESERVER ist gelaufen und SCP hat funktioniert " "$EMAILADR1"  <$zz_log_file
    echo "Datenmenge im folder = " "`du -s -h $BACKUPDIR`" | mail -s "Der copy-home-Script auf $RDESERVER ist gelaufen (siehe Logfile)" "$EMAILADR1"
    echo "Datenmenge im folder = " "`du -s -h $BACKUPDIR`" | mail -s "Der copy-home-Script auf $RDESERVER ist gelaufen (siehe Logfile)" "$EMAILADR2"

## echo "==== "
echo '==== Beide Mails sind gesendet at : '`date`

  fi
  rm $LOCKFILE  # following another job can start
  trap - INT TERM EXIT

else
  echo "==== a backup_typo3 job is already running - wait until /var/lock/bak_typo3_xxx.lock has finished."
fi

exit 0

Startseite -- © 2001/2022 - Copyright by Dipl.-Ing. Gert Redlich / Germany - D-65191 Wiesbaden - Telefon-Nummer - Impressum