Script de PowerShell para sysadmin para descargar regularmente copias de seguridad del servidor al ordenador

Recientemente, una amiga mía se encontró con el problema de que el proveedor de VPS cerró repentinamente sin previo aviso. Desafortunadamente, por ahorrar dinero, eligió un proveedor de nicho, uno que ni siquiera ofrecía descargas de datos. Lo que es peor, ni siquiera tiene el hábito de descargar copias de seguridad regularmente. De la noche a la mañana, su sitio desapareció, junto con todos los datos que contenía.

Conmocionado por esto, escribí un script de Powershell que descargará automáticamente las copias de seguridad de su servidor a su computadora local de forma regular sin tener que comprar ningún servicio adicional de almacenamiento de objetos ni gastar un centavo en otras cosas. Todo lo que necesita es una computadora con Windows que use regularmente (y tenga mucho espacio en el disco duro) y esté conectada a Internet.

El script limpiará automáticamente las copias de seguridad de hace 5 días. Puede configurar el intervalo de copia de seguridad automática y la antigüedad de la copia de seguridad guardada localmente según sus necesidades.


$ssh_port = 22
$ssh_address = "username@your.site"


Write-Output "Starting Discourse backup download task..."
Write-Output '------------------------'
Write-Output "Fetching the latest backup file..."
Write-Output ''

while ($true) {

    $filename = ''

    while ($true) {
        try {
            Write-Output "> ssh -p $ssh_port $ssh_address 'cd /var/discourse/shared/standalone/backups/default/ && ls -t | head -n 1'"
            Write-Output ''
            $filename = ssh -p $ssh_port "$ssh_address" 'cd /var/discourse/shared/standalone/backups/default/ && ls -t | head -n 1'
            break
        }
        catch {
            $filename = ''

            Write-Output "Failed to fetch... Here is the log:"
            Write-Output '-------------'
            Write-Output $_

            $answer = Read-Host "Do you want to re-fetch? (y/N)"
            if ($answer -ne 'y') {
                break
            }
            Write-Output ''
        }
    }


    if ([String]::IsNullOrEmpty($filename)) {
        Write-Output "Error: Failed to fetch file name $filename"
        Write-Output ''
        $answer = Read-Host 'Retry?(y/N)'

        if ($answer -eq 'y') {

        }
        else {

            exit 1
        }

    }
    else {

        Write-Output "Latest backup: $filename"
        Write-Output ''

        $need_download = $true
        if (Test-Path ".\backups\$filename") {
            $answer = Read-Host ".\backups\$filename already exists. Do you want to download it again?(y/N)"
            Write-Output ''
            if ($answer -ne 'y') {
                $need_download = $false
            }
        }
        if ($need_download) {
            Write-Output "Start downloading..."
            Write-Output ''

            while ($true) {
                try {
                    Write-Output "scp -p $ssh_port ${ssh_address}:/var/discourse/shared/standalone/backups/default/$filename .\\backups\\"
                    Write-Output ''

                    scp -p $ssh_port "${ssh_address}:/var/discourse/shared/standalone/backups/default/$filename" .\\backups\

                    Write-Output "Download completed"
                    Write-Output ''

                    break
                }
                catch {

                    Write-Output "Download failed >_<... The following is the log:"
                    Write-Output ''

                    Write-Output $_

                    $answer = Read-Host "Download again? (y/N)"
                    Write-Output ''
                    if ($answer -ne 'y') {
                        break
                    }
                }
            }

        }

        Write-Output "Start trying to clean old backup files..."
        Write-Output ''

        $count = 0
        $backupfiles = Get-ChildItem -Path .\\backups\

        foreach ($file in $backupfiles) {
            if ($file.CreationTime -le (Get-Date).AddDays(-5)) {
                try {
                    Write-Output "Delete old backup file $file ..."
                    Write-Output ''
                    $file.Delete()
                    $count = $count + 1
                } catch {
                    Write-Output "An error occurred while deleting old backup file $file >_<"
                    Write-Output '-------------------'
                    Write-Output $_
                    Write-Output '-------------------'
                }
            }
        }

        if ($count -ge 0) {
            Write-Output "Cleaned $count old backup files"
            Write-Output ''
        }
        else {
            Write-Output 'No old backup files need to clean up'
            Write-Output ''
        }

        Pause

        exit 0


    }


}


Guarde el script anterior como scriptname.ps1 en la ruta donde desea descargar la copia de seguridad. Intente “Ejecutar con Powershell”. Si tiene éxito, puede pasar al siguiente paso.

Para programar una tarea

  1. Busque “Programador de tareas”.
  2. Haga doble clic en Agregar tarea programada. Aparece el Asistente para tareas programadas.
  3. Haga clic en Siguiente y luego en Examinar. Aparece el cuadro de diálogo Seleccionar programa para programar.
  4. Navegue hasta el script que creó, haga clic en él y luego en Abrir. Vuelve al Asistente para tareas programadas.
  5. Proporcione un nombre para la tarea, o mantenga el predeterminado, que es el nombre del archivo, especifique con qué frecuencia ejecutar el script y luego haga clic en Siguiente.
  6. Especifique la hora y la fecha de inicio (si especificó Diaria, Semanal o Mensual, etc.) y la recurrencia, luego haga clic en Siguiente. Este elemento debe coincidir con el ciclo de copia de seguridad automática de su discourse.
  7. Escriba el nombre de usuario y la contraseña de la cuenta que ejecutará el script, luego haga clic en Siguiente.
  8. Si desea configurar propiedades avanzadas, seleccione la casilla de verificación y luego haga clic en Finalizar.
15 Me gusta

Un buen recordatorio de la importancia de tener copias de seguridad remotas. Otro usuario de meta sufrió el mismo problema hace unos meses.

Una de mis instancias utiliza la función de copias de seguridad S3 integrada, las otras utilizan Rclone y una tarea CRON para enviar copias de seguridad a Google Drive. Hay una guía para esto: Use rclone to sync backups to Dropbox or Google Drive

Gracias por compartir tu script Linca :+1:

3 Me gusta

De hecho, un muy buen recordatorio. Sugerí (aquí) que la función de actualización podría verificar y advertir si los archivos de copia de seguridad tienen tiempos de último acceso demasiado lejanos. Actualizamos cada dos o tres meses, por lo que esa verificación no se ejecutaría con demasiada frecuencia, y el momento de una actualización es un buen momento para asegurarse de que haya una copia de seguridad segura. Cualquier medio de copiar un archivo de copia de seguridad a otro lugar debería actualizar la marca de tiempo del último acceso.

3 Me gusta

Buen punto, gracias por el script. Permíteme compartir la versión de rsync :slight_smile: .

En el ejemplo a continuación, sql y attachments se sincronizan por separado. No es necesario incluir attachments en el archivo de copia de seguridad. Tampoco es necesario eliminar copias de seguridad antiguas.

Uso Chocolatey para instalar cwrsync. Después de la instalación, solo es necesario agregar algunas líneas al final del archivo cmd + crear una programación:

C:\ProgramData\chocolatey\lib\rsync\tools\cwrsync.cmd

Por ejemplo:

rsync -rvm --delete --ignore-errors --ignore-existing --size-only --chmod=ugo=rwX -e "ssh -i /cygdrive/c/Users/user1/.ssh/id_rsa" login@host:/var/discourse/shared/standalone/backups/default/ /cygdrive/d/backup/forum/db/

rsync -rvm --delete --ignore-errors --ignore-existing --size-only --chmod=ugo=rwX -e "ssh -i /cygdrive/c/Users/user1/.ssh/id_rsa" login@host:/var/discourse/shared/standalone/uploads/ /cygdrive/d/backup/forum/uploads/

Nota 1: Usa /cygdrive/c/ en lugar de C:, lee el archivo cmd para referencia y sintaxis.

Nota 2: Puedes modificar el comando para usar una contraseña en lugar de una clave ssh (formato PEM)

Nota 3: Si no pones una barra inclinada después de la carpeta dump/, rsync copiará la carpeta, pero si lo haces, solo copiará el contenido de la carpeta.

Nota 4: si chocolatey actualiza cwrsync, crea una copia de seguridad del cmd anterior en la misma carpeta. Necesitas copiar tus comandos al nuevo cmd manualmente para continuar con las copias de seguridad.

Importante: Establece la misma regla en el Programador como escribió el OP. La línea del programador es:

C:\ProgramData\chocolatey\lib\rsync\tools\cwrsync.cmd >> d:\backup\cwrsync.txt 2>&1

Esto agregará la salida al archivo cwrsync.txt. Eso es todo.

3 Me gusta

Tengo la costumbre de configurar rclone para copiar automáticamente las copias de seguridad a un destino remoto (un NAS autoalojado en casa) debido a la paranoia sobre este tipo de cosas que suceden de la nada. Esta publicación sirve muy bien como un recordatorio de que no debemos poner todos los huevos en la misma canasta.

5 Me gusta

Mientras tanto, también deberías obtener una copia de todo en /var/discourse/containers.

4 Me gusta

¡Buena idea! Desplegaré una actualización

3 Me gusta

¿Dónde busco “Tareas programadas”? (Novato pidiendo consejo, gracias)

“Scheduled Tasks” es el Programador de Tareas, en win10 o superior puedes buscarlo directamente presionando la tecla de Windows.

2 Me gusta

Hola. ¿Por qué me sale este error?

Para cualquiera que lea esto, aquí hay instrucciones mejores/más actualizadas ya que tuve algunas dificultades con las instrucciones del OP:

  1. Crea/usa una carpeta donde se almacenará este script. Luego, crea una carpeta llamada backup dentro de esa carpeta.

  2. Copia/pega el script en el Bloc de notas. NOTA: Si usas un VPS, usa el nombre de usuario de tu VPS y la dirección IP pública para la línea $ssh_address = \"username@your.site\". Guarda como cualquiernombre.ps1 y no olvides configurar el menú desplegable en “Todos los archivos”, como se muestra a continuación.
    hhhh

  3. Presiona la tecla de Windows ⊞ y escribe “Tareas”, luego haz clic en “Programador de tareas”.

  4. En el lado derecho, haz clic en “Crear tarea básica”.

  5. Dale cualquier nombre/descripción.

  6. Elige si quieres que sea diario/semanal/anual/etc. Recomiendo Diario.

  7. Establece la fecha y hora en que deseas hacer esto. Mantén Recurrir en 1. Asegúrate de ir a la configuración de Administrador de tu sitio de Discourse > Copias de seguridad. Marca la casilla junto a automatic backups enabled.
    Luego, establece backup frequency a lo que desees. Recomiendo 1, pero la clave aquí es que coincida con la configuración de tu Programador de tareas. Haz que las fechas de copia de seguridad coincidan. Ejemplo: si configuras el Programador de tareas para hacer copias de seguridad Diariamente, establece la configuración de backup frequency de Copia de seguridad de Administrador en 1.

  8. Deja la configuración predeterminada en “iniciar un programa” y haz clic en Siguiente.

  9. Haz clic en Examinar y busca el script que guardaste. Haz clic en Siguiente.

  10. Haz clic en Finalizar.
    Si deseas probarlo, haz clic derecho en el script y elige “Ejecutar con Powershell”.

Nota: Si recibes el mensaje “el sistema no puede encontrar el archivo especificado”, ingresa tu contraseña como se muestra en PowerShell y de todos modos lo encontrará.

1 me gusta

Cuando guardé el script de PS (simplemente edité mi nombre de usuario y la dirección IP en la segunda línea), y hice clic derecho > Ejecutar con PowerShell, no sucede nada.
Ocurre un destello. Y si ya tengo una terminal abierta en mi win11, esa terminal se pone al frente. Nada más. Solo un destello.

Me preguntaba, aunque le di mi nombre de usuario y dirección IP al script, ¿cómo usaría mi clave SSH para iniciar sesión y extraer la copia de seguridad?

¡Gracias!

Intenté tanto la solución de OP como la de 45thj5ej y ninguna me funciona. Al ejecutar el script con Powershell no encuentra “/backups/” ni el elemento secundario. Tampoco logro encontrar dónde OP indica que se supone que debes ingresar tu nombre de usuario y contraseña. Estoy ejecutando Discourse en un VPS.