{ "name": "💾 Backup Automático Sistema | Local Sem Slack", "nodes": [ { "parameters": { "rule": { "interval": [ { "field": "cronExpression", "value": "0 2 * * *" } ] } }, "id": "cron-backup-trigger", "name": "Trigger Backup 2h", "type": "n8n-nodes-base.cron", "typeVersion": 1, "position": [240, 300] }, { "parameters": { "jsCode": "// Configurar backup automático\nconst today = new Date();\nconst dateString = today.toISOString().split('T')[0].replace(/-/g, '');\nconst timeString = today.toTimeString().split(' ')[0].replace(/:/g, '');\n\nconst backupConfig = {\n backup_date: dateString,\n backup_time: timeString,\n backup_dir: `/backup/${dateString}`,\n timestamp: today.toISOString(),\n backup_label: `backup-${dateString}-${timeString}`,\n retention_days: 30\n};\n\nreturn backupConfig;" }, "id": "setup-backup-config", "name": "Configurar Backup", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [460, 300] }, { "parameters": { "command": "mkdir -p {{$node[\"Configurar Backup\"].json[\"backup_dir\"]}}" }, "id": "create-backup-dir", "name": "Criar Diretório Backup", "type": "n8n-nodes-base.executeCommand", "typeVersion": 1, "position": [680, 300] }, { "parameters": { "jsCode": "// Preparar script de backup completo\nconst config = $node[\"Configurar Backup\"].json;\nconst backupDir = config.backup_dir;\n\nconst backupScript = `\n#!/bin/bash\nset -e\n\n# Variáveis\nBACKUP_DIR=\"${backupDir}\"\nDATE=\"${config.backup_date}\"\nTIME=\"${config.backup_time}\"\nLOG_FILE=\"$BACKUP_DIR/backup.log\"\n\n# Função para log\nlog() {\n echo \"[$(date '+%Y-%m-%d %H:%M:%S')] $1\" | tee -a \"$LOG_FILE\"\n}\n\nlog \"=== INÍCIO DO BACKUP AUTOMÁTICO ===\"\nlog \"Diretório: $BACKUP_DIR\"\nlog \"Data/Hora: ${config.timestamp}\"\n\n# 1. Backup Banco de Dados Krayin\nlog \"1. Fazendo backup do banco Krayin...\"\ndocker exec krayin_db mysqldump -u root -p\\$MYSQL_ROOT_PASSWORD krayin > \"$BACKUP_DIR/krayin_database.sql\" 2>/dev/null || {\n log \"ERRO: Falha no backup do banco Krayin\"\n echo \"error_krayin_db\" > \"$BACKUP_DIR/errors.txt\"\n}\n\n# 2. Backup Banco de Dados BookStack\nlog \"2. Fazendo backup do banco BookStack...\"\ndocker exec bookstack_db mysqldump -u \\$MYSQL_USER -p\\$MYSQL_PASSWORD \\$MYSQL_DATABASE > \"$BACKUP_DIR/bookstack_database.sql\" 2>/dev/null || {\n log \"ERRO: Falha no backup do banco BookStack\"\n echo \"error_bookstack_db\" >> \"$BACKUP_DIR/errors.txt\"\n}\n\n# 3. Backup Volumes Docker\nlog \"3. Fazendo backup dos volumes Docker...\"\ndocker run --rm -v krayin_app_data:/data -v \"$BACKUP_DIR\":/backup alpine tar czf /backup/krayin_app_data.tar.gz -C /data . || {\n log \"ERRO: Falha no backup do volume Krayin\"\n echo \"error_krayin_volume\" >> \"$BACKUP_DIR/errors.txt\"\n}\n\ndocker run --rm -v bookstack_app:/data -v \"$BACKUP_DIR\":/backup alpine tar czf /backup/bookstack_app.tar.gz -C /data . || {\n log \"ERRO: Falha no backup do volume BookStack\"\n echo \"error_bookstack_volume\" >> \"$BACKUP_DIR/errors.txt\"\n}\n\ndocker run --rm -v n8n_data:/data -v \"$BACKUP_DIR\":/backup alpine tar czf /backup/n8n_data.tar.gz -C /data . || {\n log \"ERRO: Falha no backup do volume N8N\"\n echo \"error_n8n_volume\" >> \"$BACKUP_DIR/errors.txt\"\n}\n\ndocker run --rm -v evolution_data:/data -v \"$BACKUP_DIR\":/backup alpine tar czf /backup/evolution_data.tar.gz -C /data . || {\n log \"ERRO: Falha no backup do volume Evolution\"\n echo \"error_evolution_volume\" >> \"$BACKUP_DIR/errors.txt\"\n}\n\n# 4. Backup Configurações\nlog \"4. Fazendo backup das configurações...\"\ncp docker-compose.yml \"$BACKUP_DIR/\" 2>/dev/null || {\n log \"AVISO: docker-compose.yml não encontrado\"\n echo \"warning_docker_compose\" >> \"$BACKUP_DIR/errors.txt\"\n}\n\n# 5. Informações do Sistema\nlog \"5. Coletando informações do sistema...\"\necho \"=== INFORMAÇÕES DO SISTEMA ===\" > \"$BACKUP_DIR/system_info.txt\"\necho \"Data/Hora: $(date)\" >> \"$BACKUP_DIR/system_info.txt\"\necho \"\" >> \"$BACKUP_DIR/system_info.txt\"\necho \"=== ESPAÇO EM DISCO ===\" >> \"$BACKUP_DIR/system_info.txt\"\ndf -h >> \"$BACKUP_DIR/system_info.txt\"\necho \"\" >> \"$BACKUP_DIR/system_info.txt\"\necho \"=== MEMÓRIA ===\" >> \"$BACKUP_DIR/system_info.txt\"\nfree -h >> \"$BACKUP_DIR/system_info.txt\"\necho \"\" >> \"$BACKUP_DIR/system_info.txt\"\necho \"=== CONTAINERS DOCKER ===\" >> \"$BACKUP_DIR/system_info.txt\"\ndocker ps -a >> \"$BACKUP_DIR/system_info.txt\"\necho \"\" >> \"$BACKUP_DIR/system_info.txt\"\necho \"=== VOLUMES DOCKER ===\" >> \"$BACKUP_DIR/system_info.txt\"\ndocker volume ls >> \"$BACKUP_DIR/system_info.txt\"\n\n# 6. Calcular tamanhos\nlog \"6. Calculando tamanhos dos arquivos...\"\necho \"=== TAMANHOS DOS BACKUPS ===\" > \"$BACKUP_DIR/backup_sizes.txt\"\ndu -sh \"$BACKUP_DIR\"/* >> \"$BACKUP_DIR/backup_sizes.txt\"\necho \"\" >> \"$BACKUP_DIR/backup_sizes.txt\"\necho \"TOTAL DO BACKUP: $(du -sh \\\"$BACKUP_DIR\\\" | cut -f1)\" >> \"$BACKUP_DIR/backup_sizes.txt\"\n\n# 7. Limpeza de backups antigos\nlog \"7. Limpando backups antigos (>${config.retention_days} dias)...\"\nfind /backup -type d -name \"20*\" -mtime +${config.retention_days} -exec rm -rf {} + || {\n log \"AVISO: Falha na limpeza de backups antigos\"\n echo \"warning_cleanup\" >> \"$BACKUP_DIR/errors.txt\"\n}\n\n# 8. Verificar erros e finalizar\nif [ -f \"$BACKUP_DIR/errors.txt\" ]; then\n ERROR_COUNT=$(wc -l < \"$BACKUP_DIR/errors.txt\")\n log \"BACKUP CONCLUÍDO COM $ERROR_COUNT PROBLEMAS\"\n echo \"BACKUP_COMPLETED_WITH_ERRORS\" > \"$BACKUP_DIR/status.txt\"\nelse\n log \"BACKUP CONCLUÍDO COM SUCESSO\"\n echo \"BACKUP_COMPLETED_SUCCESS\" > \"$BACKUP_DIR/status.txt\"\nfi\n\nlog \"=== FIM DO BACKUP AUTOMÁTICO ===\"\n\necho \"Backup completo finalizado em: $BACKUP_DIR\"\n`;\n\nreturn {\n script: backupScript,\n script_path: `${backupDir}/backup_script.sh`,\n backup_dir: backupDir\n};" }, "id": "prepare-backup-script", "name": "Preparar Script Backup", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [900, 300] }, { "parameters": { "mode": "write", "fileName": "={{$node[\"Preparar Script Backup\"].json[\"script_path\"]}}", "fileContent": "={{$node[\"Preparar Script Backup\"].json[\"script\"]}}" }, "id": "save-backup-script", "name": "Salvar Script Backup", "type": "n8n-nodes-base.writeFile", "typeVersion": 1, "position": [1120, 300] }, { "parameters": { "command": "chmod +x {{$node[\"Preparar Script Backup\"].json[\"script_path\"]}}" }, "id": "make-script-executable", "name": "Tornar Script Executável", "type": "n8n-nodes-base.executeCommand", "typeVersion": 1, "position": [1340, 300] }, { "parameters": { "command": "{{$node[\"Preparar Script Backup\"].json[\"script_path\"]}}", "options": { "timeout": 3600 } }, "id": "execute-backup", "name": "Executar Backup", "type": "n8n-nodes-base.executeCommand", "typeVersion": 1, "position": [1560, 300] }, { "parameters": { "jsCode": "// Processar resultado do backup\nconst backupResult = $node[\"Executar Backup\"].json;\nconst config = $node[\"Configurar Backup\"].json;\n\nconst success = backupResult.exitCode === 0;\nconst output = backupResult.stdout || '';\nconst errorOutput = backupResult.stderr || '';\n\nconst result = {\n timestamp: new Date().toISOString(),\n backup_date: config.backup_date,\n backup_dir: config.backup_dir,\n success: success,\n exit_code: backupResult.exitCode,\n stdout: output,\n stderr: errorOutput,\n status: success ? 'BACKUP_SUCCESS' : 'BACKUP_FAILED'\n};\n\nreturn result;" }, "id": "process-backup-result", "name": "Processar Resultado", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [1780, 300] }, { "parameters": { "conditions": { "boolean": [ { "value1": "={{$node[\"Processar Resultado\"].json[\"success\"]}}", "value2": true } ] } }, "id": "backup-successful", "name": "Backup Sucesso?", "type": "n8n-nodes-base.if", "typeVersion": 1, "position": [2000, 300] }, { "parameters": { "jsCode": "// Ler informações detalhadas do backup\nconst result = $node[\"Processar Resultado\"].json;\nconst config = $node[\"Configurar Backup\"].json;\n\n// Tentar ler arquivos de status e tamanhos\nconst fs = require('fs');\nlet backupSizes = 'N/A';\nlet systemInfo = 'N/A';\nlet errors = 'Nenhum';\n\ntry {\n backupSizes = fs.readFileSync(`${config.backup_dir}/backup_sizes.txt`, 'utf8');\n} catch (e) {}\n\ntry {\n systemInfo = fs.readFileSync(`${config.backup_dir}/system_info.txt`, 'utf8');\n} catch (e) {}\n\ntry {\n errors = fs.readFileSync(`${config.backup_dir}/errors.txt`, 'utf8');\n} catch (e) {}\n\nconst successLog = {\n timestamp: new Date().toISOString(),\n action: 'BACKUP_COMPLETED_SUCCESS',\n backup_dir: config.backup_dir,\n backup_date: config.backup_date,\n backup_sizes: backupSizes,\n system_info: systemInfo.split('\\n').slice(0, 10).join('\\n'), // Primeiras 10 linhas\n errors: errors,\n status: 'SUCCESS'\n};\n\nreturn successLog;" }, "id": "log-backup-success", "name": "Log Backup Sucesso", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [2220, 200] }, { "parameters": { "jsCode": "// Log de falha no backup\nconst result = $node[\"Processar Resultado\"].json;\nconst config = $node[\"Configurar Backup\"].json;\n\nconst failureLog = {\n timestamp: new Date().toISOString(),\n action: 'BACKUP_FAILED',\n backup_dir: config.backup_dir,\n backup_date: config.backup_date,\n exit_code: result.exit_code,\n stdout: result.stdout,\n stderr: result.stderr,\n status: 'FAILED'\n};\n\nreturn failureLog;" }, "id": "log-backup-failure", "name": "Log Backup Falha", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [2220, 400] }, { "parameters": { "mode": "append", "fileName": "/tmp/backup-log.txt", "fileContent": "={{JSON.stringify($node[\"Log Backup Sucesso\"].json, null, 2)}}\n==========\n" }, "id": "save-success-log", "name": "Salvar Log Sucesso", "type": "n8n-nodes-base.writeFile", "typeVersion": 1, "position": [2440, 200] }, { "parameters": { "mode": "append", "fileName": "/tmp/backup-log.txt", "fileContent": "={{JSON.stringify($node[\"Log Backup Falha\"].json, null, 2)}}\n==========\n" }, "id": "save-failure-log", "name": "Salvar Log Falha", "type": "n8n-nodes-base.writeFile", "typeVersion": 1, "position": [2440, 400] } ], "connections": { "Trigger Backup 2h": { "main": [ [ { "node": "Configurar Backup", "type": "main", "index": 0 } ] ] }, "Configurar Backup": { "main": [ [ { "node": "Criar Diretório Backup", "type": "main", "index": 0 } ] ] }, "Criar Diretório Backup": { "main": [ [ { "node": "Preparar Script Backup", "type": "main", "index": 0 } ] ] }, "Preparar Script Backup": { "main": [ [ { "node": "Salvar Script Backup", "type": "main", "index": 0 } ] ] }, "Salvar Script Backup": { "main": [ [ { "node": "Tornar Script Executável", "type": "main", "index": 0 } ] ] }, "Tornar Script Executável": { "main": [ [ { "node": "Executar Backup", "type": "main", "index": 0 } ] ] }, "Executar Backup": { "main": [ [ { "node": "Processar Resultado", "type": "main", "index": 0 } ] ] }, "Processar Resultado": { "main": [ [ { "node": "Backup Sucesso?", "type": "main", "index": 0 } ] ] }, "Backup Sucesso?": { "main": [ [ { "node": "Log Backup Sucesso", "type": "main", "index": 0 } ], [ { "node": "Log Backup Falha", "type": "main", "index": 0 } ] ] }, "Log Backup Sucesso": { "main": [ [ { "node": "Salvar Log Sucesso", "type": "main", "index": 0 } ] ] }, "Log Backup Falha": { "main": [ [ { "node": "Salvar Log Falha", "type": "main", "index": 0 } ] ] } }, "active": false, "settings": {}, "versionId": "1", "meta": { "instanceId": "backup-noslack" }, "id": "4", "tags": [ "Backup", "Automático", "Local", "Sem Slack", "Sistema" ] }