Uma lâmina de servidor preta fosca e iluminada, num datacenter escuro, transmitindo uma fita de partículas de dados esmeralda para uma réplica em wireframe luminoso de si mesma, selada por um cadeado luminoso
Guia de backup

Fazer backup de um VPS que você realmente consegue restaurar

Quase todo mundo que roda um servidor tem algo que chama de backup. Bem menos gente já restaurou algum, e a distância entre essas duas frases é exatamente onde os dados somem de verdade. Isto é como construir uma cópia que sobrevive às três coisas que realmente destroem servidores — as suas próprias mãos, um comprometimento, e uma conta que você deixa de controlar — sem acoplar silenciosamente uma identidade verificada a uma máquina anônima.

Mantemos três cópias de cada byte que roda esta rede e já restauramos a partir delas, de propósito, numa terça-feira qualquer, mais vezes do que jamais precisamos numa emergência de verdade. Isso não é zelo pelo zelo. É a única forma de saber que aquilo no repositório é um backup, e não uma pasta de ruído criptografado com um nome tranquilizador.

O conselho abaixo é deliberadamente fora de moda. Não envolve um produto de backup com painel, assinatura mensal ou fila de suporte, porque cada uma dessas coisas é uma conta, e uma conta é um nome, um cartão e uma jurisdição — três coisas que você talvez tenha se esforçado bastante para manter longe deste servidor. Envolve uma segunda máquina, umas quarenta linhas de shell, e um hábito que quase ninguém mantém.

Você deve conseguir fazer tudo isto numa noite. As ferramentas seguem o sabor Debian 13 e Ubuntu 24.04; tudo se transporta para derivados de RHEL com as substituições óbvias. Se o seu servidor é novo, faça o hardening da primeira hora antes desta página em vez de depois — fazer backup de uma máquina que já é de outra pessoa é uma forma de preservar o trabalho dela.

O que realmente destrói dados num servidor alugado

Pergunte a qualquer um por que faz backup e a resposta costuma ser “caso o disco morra”. Num VPS moderno isso está entre as coisas menos prováveis de acontecer com você. Seu volume fica em NVMe, num array redundante, com um hypervisor que te migra para fora de um host falhando antes que você perceba; falha de disco é problema do provedor, e é um problema resolvido. Construir toda a sua estratégia de backup em cima disso é como comprar um extintor de incêndio para uma casa que enche d'água.

Eis o que realmente leva os dados das pessoas, mais ou menos em ordem de frequência. Primeiro, e com grande margem: você. Um rm -rf com uma variável que expandiu para nada. Um DROP DATABASE no terminal errado porque duas abas pareciam idênticas. Um script de migração rodado duas vezes. Um docker compose down -v em que o -v saiu na memória muscular. Isso não é exótico; é terça-feira comum.

Segundo, aplicações que apagam os próprios dados. Um upgrade que roda uma migração destrutiva e falha na metade. Um plugin que limpa um diretório de cache que, no fim, não era cache nenhum. Uma rotação de log configurada contra o caminho errado. Terceiro, comprometimento — e note que este é o caso em que um atacante quer que os backups sumam, o que muda o design de formas às quais voltamos mais adiante. Quarto, e fácil de esquecer num host no-KYC: perder a conta. Um saldo que zerou enquanto você estava fora, uma entrada de gerenciador de senhas que você nunca anotou, um e-mail que você abandonou. Nós suspendemos horas depois de um saldo zerado e destruímos sete dias depois, e isso é deliberadamente implacável — é a aritmética que nos permite não perguntar quem você é. Não existe um atendente de suporte capaz de consultar sua identidade e abrir uma exceção, porque não existe identidade nenhuma para consultar.

Essa última categoria é a que separa hospedagem com foco em privacidade da hospedagem convencional, e é ela que deve moldar o seu plano. Todo controle que torna este servidor difícil de atribuir a você também torna difícil para qualquer um — inclusive nós — devolvê-lo a você. O backup é o que transforma essa troca de um risco numa escolha.

Por que um snapshot não é um backup

Snapshots são ótimos e você deve usá-los. Tire um antes de cada upgrade de kernel, cada migração de banco, cada vez que estiver prestes a fazer algo que preferiria poder desfazer. Eles restauram em segundos, custam quase nada, e vão te salvar uma tarde umas doze vezes por ano.

Mesmo assim não são backups, por três razões estruturais que nenhuma quantidade de marketing de provedor muda. Eles vivem dentro da mesma conta: quem quer que consiga logar no seu painel pode apagá-los, e se a conta parar de funcionar, os snapshots deixam de existir junto com ela. Vivem no mesmo domínio de falha: mesmo provedor, mesmo plano de controle, muitas vezes o mesmo cluster de armazenamento, o que significa que um único evento ruim pode plausivelmente levar tanto o original quanto a cópia. E são opacos: um snapshot de uma máquina em execução captura um banco de dados no meio de uma escrita com a mesma fidelidade com que captura tudo o mais, então restaurar o snapshot de um MySQL movimentado te dá um cenário de recuperação de falha, não um banco limpo.

A velha regra 3-2-1 — três cópias, em dois tipos de mídia, uma delas off-site — costuma ser recitada sem que ninguém repare que a cláusula do meio não tem sentido nenhum em infraestrutura alugada. Você não tem dois tipos de mídia. Você tem um dispositivo de bloco virtual, e outro dispositivo de bloco virtual, e os dois são o SAN de alguém. O que sobrevive à tradução para um VPS é a parte que sempre importou de verdade: pelo menos uma cópia precisa estar em algum lugar que um único evento ruim não alcance. Provedor diferente, ou no mínimo região diferente, credenciais diferentes, conta diferente, e — se o motivo de você hospedar offshore é jurídico e não técnico — uma jurisdição diferente, para que uma única ordem judicial não caia sobre as duas cópias ao mesmo tempo.

O destino faz parte do seu modelo de ameaças

Esta é a seção que outros tutoriais de backup não têm, e é a que mais importa se você pagou por este servidor em Monero.

O conselho padrão em qualquer lugar da internet é empurrar (push) seus backups para um object store: Backblaze B2, Amazon S3, Wasabi, um Google Drive via rclone. É barato, é durável, funciona. Também desfaz, num único comando, boa parte do que você vinha construindo. Abrir aquela conta exigiu um cartão e geralmente um documento de identidade. Desde o momento em que o primeiro snapshot sobe, aquele provedor guarda um registro com timestamp associando seu nome e seus dados de pagamento ao endereço IP do seu servidor, atualizado a cada hora, para sempre. Você não verificou sua identidade com a gente; verificou com eles, e depois traçou uma linha entre os dois.

A segunda metade é pior, e é a parte que as pessoas deixam passar. A chave de API que autoriza esses uploads é um arquivo no servidor de produção. Quem quer que consiga root nessa máquina — ou quem adquirir o disco por vias legais — não ganha só os seus dados. Ganha uma credencial que resolve, numa única chamada de API, para uma identidade de cobrança. O servidor anônimo virou uma placa apontando para o seu banco.

Nada disso torna o object storage errado. Torna-o uma decisão, e não um padrão automático. Três saídas, em ordem decrescente de quanto preservam o que você começou:

  • Um segundo VPS no-KYC, de preferência numa jurisdição diferente da produção, pago do mesmo saldo em cripto. O destino herda as propriedades de anonimato da origem em vez de contradizê-las. É o que fazemos, e é o que o resto deste guia assume.
  • Um provedor de armazenamento que aceita cripto sem identidade. Eles existem; são menores; verifique se o caminho de pagamento é realmente livre de identidade antes de confiar no marketing, e verifique o preço de egress antes de descobrir na hora de uma restauração.
  • Uma máquina que você possui fisicamente, puxando via WireGuard de trás da sua própria conexão. Excelente para anonimato, ruim para disponibilidade, e significa que sua velocidade de restauração é a velocidade de upload da sua casa. Razoável como terceira cópia, fraca como única.

Seja qual for sua escolha, a conta que guarda os backups não deve compartilhar credenciais, e-mail ou caminho de recuperação com a conta que guarda a produção. Todo o ponto é que um login comprometido não pode alcançar os dois. É a mesma disciplina de manter identidades separadas em outros lugares, aplicada ao canto menos glamouroso do sistema.

Push, pull, e o motivo pelo qual o ransomware encontra seus backups

Quase todo tutorial de backup produz a mesma arquitetura: um cron job no servidor de produção que se autentica num repositório remoto e escreve nele. É simples, funciona, e tem uma propriedade que ninguém menciona — o servidor de produção guarda uma credencial capaz de apagar o repositório inteiro. Fazer o prune de snapshots antigos exige direito de exclusão, então a chave que roda seu job noturno é também a chave que esvazia o cofre.

Pense no que isso significa durante um comprometimento. Um atacante com root na máquina não precisa procurar seus backups; você já deixou, gentilmente, uma credencial funcional e um arquivo de configuração nomeando o repositório. Enumerar e destruir backups antes de disparar qualquer coisa visível não é um refinamento hipotético — é prática padrão, porque é isso que transforma um incidente numa negociação. Seu job noturno era o reconhecimento.

Existem três desenhos, e a diferença entre eles é inteiramente sobre qual máquina guarda qual chave.

Push simples é o de cima. A produção tem leitura, escrita e exclusão. Conveniente, e falha completamente bem no cenário em que você mais precisa de um backup. Use-o só se a única ameaça que realmente te preocupa forem os seus próprios dedos.

Push append-only mantém a mesma forma, mas remove o verbo perigoso. O repositório é servido por algo que entende o protocolo e recusa exclusões: rest-server --append-only para o restic, ou borg serve --append-only forçado a partir do authorized_keys. A produção pode criar novos snapshots e não pode remover os antigos. O prune acontece depois, de outro lugar, usando uma chave diferente. É uma melhoria enorme por cerca de vinte minutos de trabalho, e para a maioria das pessoas é o ponto certo para parar.

Pull inverte a conexão. O host de backup entra na produção via SSH, copia o que precisa, e roda a ferramenta de backup localmente, no próprio disco. A produção não guarda credencial de backup nenhuma — não há nada naquela máquina para encontrar, porque a máquina não sabe onde seus backups moram. Esse é o arranjo mais forte, e é o que o passo a passo abaixo constrói.

Seja honesto sobre o que o pull custa, porque não é de graça. Você moveu a chave em vez de eliminá-la: o host de backup agora guarda uma chave SSH para dentro da produção, então um comprometimento do host de backup alcança o sistema em produção. É uma troca melhor — o host de backup não roda nada, não expõe nada além de SSH, e é um alvo muito menor que um servidor web público — mas ainda é uma troca, e você fecha a maior parte do que resta forçando essa chave a um comando somente leitura, para que não sirva para nada além de ler arquivos.

Escolhendo a ferramenta: restic, Borg, ou rsync puro

Três ferramentas cobrem essencialmente todos os casos, e a escolha é bem menos angustiante do que os fóruns fazem parecer.

restic criptografa por padrão, deduplica entre snapshots, fala SFTP, S3, REST e mais uma dúzia de backends, e vem como um único binário estático que você derruba em qualquer lugar. Seu formato de repositório é endereçado por conteúdo, então um snapshot sai barato e dados idênticos são armazenados uma única vez, não importa quantas máquinas os enviem. Os custos são reais, mas modestos: ele quer memória proporcional ao índice do repositório, e uma execução interrompida pode deixar um lock obsoleto que a próxima execução se recusa a atravessar até você liberá-lo com restic unlock. É a recomendação padrão, e é o que os passos abaixo usam.

Borg deduplica melhor, comprime melhor, e é visivelmente mais rápido em repositórios com milhões de arquivos pequenos. Sua contrapartida é o acoplamento: o Borg precisa estar instalado nas duas pontas, com versões bem próximas, um repositório é realmente pensado para um único cliente, e não tem backend nativo de object storage sem uma camada auxiliar. Se sua origem é uma caixa de e-mail enorme ou um sistema de arquivos cheio de arquivos pequenos, e você controla as duas máquinas, o Borg vai usar metade do espaço. Seu modo --append-only também é a implementação mais limpa dessa ideia entre as duas ferramentas.

rsync não é uma ferramenta de backup, e fingir o contrário é como as pessoas acabam com uma cópia fielmente espelhada de um diretório corrompido. Não tem versionamento, não tem deduplicação e não tem criptografia em repouso; rsync --delete propaga seu erro para a cópia na velocidade do fio. Ainda assim é a ferramenta certa para mover bytes entre duas máquinas que você controla, que é exatamente o trabalho que ele faz num desenho pull, com o restic fornecendo o versionamento e a criptografia assim que os bytes chegam. Use cada um pelo que ele é.

Uma coisa para não fazer: não invente a sua própria solução com tar e um nome de arquivo com data. Funciona por uns quatro meses, até o dia em que o disco enche porque nada nunca expirou, ou o dia em que você descobre que uma cópia completa todo santo dia de um dataset de 40 GB são 1,2 TB por mês de armazenamento que você está pagando para guardar trinta coisas quase idênticas.

O que incluir — e os bancos de dados que vão te trair

O instinto é fazer backup do sistema de arquivos inteiro. Resista. Um sistema de arquivos raiz é, em sua maior parte, pacotes de distribuição que você reinstala em noventa segundos, e incluí-los custa armazenamento, tempo de transferência e, pior, atenção — um backup de 40 GB que ninguém quer testar é menos útil do que um de 900 MB que é restaurado a cada trimestre.

O que genuinamente não pode ser reconstruído é uma lista curta: /etc (toda a sua configuração, e o motivo pelo qual reconstruir leva uma hora em vez de um fim de semana), /home e /root, /srv e /var/www, o estado de aplicação sob /var/lib/ e /opt/, volumes nomeados do Docker, units de cron e systemd que você escreveu, e os dumps do seu banco de dados. Pule /proc, /sys, /dev, /run, /tmp, /var/cache, arquivos de swap, sockets e /var/lib/docker/overlay2 — esse último é reconstruível a partir do seu arquivo compose e costuma ser o maior diretório sozinho no disco.

Agora a parte que arruína restaurações em silêncio. Copiar o diretório de dados de um banco enquanto ele está rodando produz um conjunto de arquivos com grande chance de ser inutilizável. O motor guarda estado em memória, escreve em vários arquivos numa ordem que importa, e sua cópia percorre essa árvore ao longo de vários minutos, pegando arquivos diferentes em instantes diferentes. O InnoDB às vezes se recupera de uma pane a partir disso, às vezes não; a falha aparece meses depois, durante uma restauração num dia que já estava ruim por conta própria.

Em vez disso, faça o dump pelo motor, e depois faça backup do dump:

# MariaDB / MySQL — InnoDB gets a consistent snapshot from one transaction
mariadb-dump --single-transaction --quick --routines --triggers --events \
  --all-databases | zstd -T0 > /var/backups/db/all-$(date -u +%F).sql.zst

# PostgreSQL — pg_dump is consistent by design; grab roles separately
pg_dumpall --globals-only > /var/backups/db/globals.sql
pg_dump -Fc -Z6 mydb    > /var/backups/db/mydb.dump

# SQLite — never cp a live database; WAL mode makes that a torn file
sqlite3 /var/lib/app/app.db ".backup /var/backups/db/app.db"

Vale a pena guardar duas notas de rodapé. O --single-transaction só te dá consistência para o InnoDB — se alguma tabela ainda for MyISAM, ela é copiada fora da transação e pode ficar inconsistente com o resto, então converta essas tabelas ou trave-as. E, já que você está fazendo dump, exclua o diretório de dados ativo da passada de arquivos. Fazer backup dos dois significa guardar uma cópia grande e rasgada ao lado da boa, e dar a uma restauração futura dois candidatos em que um está silenciosamente errado.

Contêineres não mudam o princípio, só o caminho: rode o dump com docker compose exec -T db mariadb-dump … e faça backup do arquivo resultante, não do volume por baixo dele.

Onde mora a chave de criptografia

A criptografia do lado do cliente é o motivo inteiro pelo qual é aceitável guardar seus dados numa máquina que não é aquela de onde eles vieram. Tanto o restic quanto o Borg criptografam antes que qualquer coisa saia da origem, então o host de backup guarda apenas texto cifrado e pode ser tratado como armazenamento não confiável. Essa propriedade vale exatamente tanto quanto o cuidado que você tem com a chave, e nem um pouco mais.

O modo de falha é deprimentemente comum. A senha do repositório fica em /etc/restic/env no servidor de produção, o que é normal e necessário para a automação. Aí a produção é o que você perde — destruída, apreendida, ou simplesmente perdida junto com a conta — e você se vê diante de várias centenas de gigabytes de blocos criptografados, com a percepção de que a única cópia da chave estava dentro da própria coisa contra cuja perda você estava se protegendo.

Então: a senha no servidor é uma cópia de trabalho, nunca o registro. O registro mora em algum lugar que sobrevive ao servidor — um gerenciador de senhas cujo cofre é, ele mesmo, salvo em outro lugar, ou escrito no papel numa gaveta, ou os dois. Anote a localização do repositório e o comando exato de restauração ao lado, porque uma passphrase sem contexto é um quebra-cabeça que você vai resolver sob estresse daqui a dezoito meses. E gaste cinco minutos para verificar: de uma máquina diferente, usando só o que está no gerenciador de senhas, rode restic snapshots contra o repositório. Se funcionar, você tem um backup. Se precisar de algo que só existe na produção, você tem uma pasta muito cara.

As duas ferramentas suportam múltiplas chaves num único repositório (restic key add), que é a forma limpa de dar acesso ao job de prune ou a um segundo administrador sem compartilhar a passphrase original. E se o disco de produção estiver criptografado com LUKS, mantenha os dois segredos genuinamente separados — guardar a passphrase do restic dentro do volume LUKS, e a passphrase do LUKS dentro do repositório restic, é um laço que falha fechado dos dois lados.

Retenção: a armadilha de guardar só uma semana

Retenção parece uma questão de custo de armazenamento, mas na verdade é uma questão de latência de detecção. O número que importa não é quanto disco você quer gastar; é quanto tempo um problema pode passar despercebido no seu sistema. Seja qual for esse período, seu backup mais antigo precisa ser mais velho do que ele.

Sete snapshots diários parecem generosos e, na prática, são pouco. Uma tabela corrompida que ninguém consulta, uma exclusão lenta causada por um cron job com defeito, uma intrusão que ficou quieta por um mês antes de fazer algo visível — tudo isso rotineiramente leva mais de uma semana para aparecer, e se o seu histórico tem sete dias de profundidade, então todo snapshot que você guarda já está contaminado. O tempo de permanência em intrusões reais costuma ser medido em semanas. Snapshots mensais baratos são a defesa específica contra isso, e a deduplicação os torna realmente muito baratos: um mensal guardado por um ano acrescenta apenas uma fração de uma cópia completa, porque só os blocos que de fato mudaram são armazenados de novo.

restic forget \
  --keep-daily 7 --keep-weekly 5 --keep-monthly 12 --keep-yearly 2 \
  --prune

Essa escada — uma semana de dias, um mês de semanas, um ano de meses, alguns anos de anos — dá cerca de vinte e seis snapshots e, em dados típicos, bem menos que o dobro do tamanho de uma única cópia completa. É o padrão que defenderíamos, a menos que você tenha um motivo específico para fugir dele.

Duas notas operacionais. O forget sem --prune só remove os rótulos, então o espaço não é liberado até você fazer o prune — o que surpreende quem fica observando um disco que não encolhe. E o --prune exige direito de exclusão no repositório, então, num desenho append-only ou pull, ele não roda no servidor de produção. Ele roda no host de backup, ou no seu laptop, com uma chave que a produção nunca viu. Essa separação é o ponto inteiro; não a desfaça por conveniência no último passo.

Automatizando sem a falha silenciosa

O desastre clássico de backup não é um job que trava. É um job que para de rodar e não avisa ninguém, descoberto onze meses depois por alguém que precisava dele. Cada elemento abaixo existe para tornar esse resultado específico impossível.

Use um timer do systemd em vez de cron. Você ganha logs de verdade no journal com status de saída anexado, Persistent=true para que uma execução perdida enquanto a máquina estava desligada aconteça no próximo boot em vez de ser pulada para sempre, e RandomizedDelaySec para que uma frota inteira não estampede o host de backup às 03:00 em ponto. A notificação de falha do cron é um e-mail para uma caixa postal local que, num servidor moderno, não vai a lugar nenhum.

# /etc/systemd/system/backup.timer
[Unit]
Description=Nightly encrypted backup

[Timer]
OnCalendar=*-*-* 03:17:00
RandomizedDelaySec=1800
Persistent=true

[Install]
WantedBy=timers.target

Depois, adicione um dead-man's switch, que é a linha de maior valor deste guia inteiro. Bem no final do script — depois que o backup tiver dado certo, não antes — faça uma requisição HTTPS para um monitor que espera ouvir de você todo dia e alerta quando isso não acontece. Isso inverte a lógica de notificação: em vez de depender de uma falha para gerar uma mensagem, a própria ausência vira o alarme. Um job que está morto há três dias vira uma mensagem na sua caixa de entrada, em vez de uma descoberta no meio de uma crise. Hospede o monitor você mesmo no host de backup se preferir não criar mais uma conta de terceiros; são poucas linhas e um timer próprio.

Por fim, os pequenos riscos operacionais, todos os quais já pegamos pelo menos uma vez. Uma execução interrompida deixa um lock, e toda execução seguinte falha com uma mensagem que você para de ler depois da quarta noite — trate o restic unlock deliberadamente, não por reflexo. Um disco de destino cheio derruba todo job até alguém reparar; alerte sobre espaço livre, não só sobre o status do job. Uma chave SSH com validade, uma host key rotacionada, uma regra nftables adicionada durante um trabalho sem relação nenhuma — cada uma dessas corta o pull silenciosamente. E systemctl enable --now, não só start: um timer que nunca foi habilitado funciona lindamente até o primeiro reboot, e depois nunca mais roda.

O simulado de restauração

Tudo o que vimos até aqui é preparação. Esta é a parte que converte isso num backup de verdade, e é a parte que quase todo mundo pula.

Uma vez por trimestre, suba um VPS novinho — o Starter de $5 é mais que suficiente, e a cobrança é por hora, proporcional ao segundo, então o exercício inteiro custa uns centavos. Restaure nele usando o que você teria num desastre de verdade: o endereço do repositório, a passphrase do seu gerenciador de senhas, e o procedimento escrito. Deliberadamente não use nada da produção, porque no cenário que você está ensaiando, a produção não existe. Suba a aplicação, aponte uma entrada do hosts para o novo IP, clique por aí. Depois destrua a máquina.

# on a throwaway machine, with nothing but the passphrase
export RESTIC_REPOSITORY=sftp:[email protected]:/srv/restic/prod
restic snapshots                      # can you even see the history?
restic restore latest --target /restore
restic check --read-data-subset=10%   # verify stored blocks, not just metadata

O que isso pega nunca é o que você espera. É o arquivo de configuração que estava num diretório que a lista de inclusão não cobria. O dump do banco que está com zero bytes há cinco semanas porque uma senha mudou e o script não checou o status de saída. A aplicação que não sobe porque um segredo mora numa variável de ambiente guardada pelo orquestrador e nunca esteve no sistema de arquivos. O registro de DNS não documentado. O certificado que precisa ser reemitido antes de qualquer coisa responder na 443. Cada um desses é um conserto de dez minutos numa tarde tranquila, e duas horas feias às três da manhã.

Anote quanto tempo o simulado levou, do início ao fim. Esse número — não a frequência do backup — é o seu tempo de recuperação real, e é a única resposta honesta quando alguém perguntar quanto tempo você ficaria fora do ar. Adicione também o restic check --read-data-subset=5% a um timer mensal: ele lê e verifica uma amostra rotativa dos blocos realmente armazenados, e não só o índice, que é como você encontra corrupção silenciosa enquanto ainda existe uma cópia boa para recorrer. Se algum dia você for migrar o servidor inteiro para outro host, uma restauração já ensaiada também é a maior parte da migração já feita.

  1. Faça o inventário do que genuinamente não pode ser reconstruído

    Antes de qualquer ferramenta, escreva a lista. Percorra a máquina e pergunte, de cada diretório: se isso sumisse, eu conseguiria recriar a partir de um gerenciador de pacotes, um repositório git ou um arquivo compose? Se sim, não pertence ao backup. O que sobra costuma ser bem menor do que as pessoas esperam — configuração, dados de usuário, estado de aplicação, dumps de banco de dados.

    # the fast way to find what is actually big and stateful
    du -x -h -d2 / 2>/dev/null | sort -rh | head -30
    docker volume ls    # named volumes are state; overlay2 is not

    Transforme o resultado em dois arquivos explícitos, /etc/restic/include.txt e /etc/restic/exclude.txt. Listas explícitas vencem expressões espertas de find porque são revisáveis, e porque um novo diretório aparecendo no servidor deveria ser uma decisão deliberada, não uma inclusão silenciosa.

  2. Suba o destino do backup numa jurisdição diferente

    Contrate um segundo VPS numa região que não seja a da produção — se a produção está em Paris, coloque a cópia em Reykjavík ou Bucareste. O ponto é que nenhum evento legal ou físico isolado alcance as duas máquinas. Um Starter de $5/mês carrega 80 GB de NVMe, o que, depois da deduplicação, guarda um histórico bem longo de um servidor pequeno típico; o ciclo de cobrança de 12 meses reduz isso pela metade. Pague do mesmo saldo em cripto, para que o destino herde o anonimato da origem em vez de contradizê-lo.

    Dê a ele uma conta separada da produção se você quiser isolamento total de credenciais. Depois, proteja-o exatamente como faria com qualquer outra máquina — SSH somente com chaves, firewall com bloqueio padrão — e não instale mais nada nele. O valor dessa máquina está em ser chata: nenhum servidor web, nenhuma porta aberta além do SSH, nada para explorar a partir da internet.

  3. Crie uma porta somente leitura do host de backup para a produção

    Este é o passo que faz disso um pull. No host de backup, gere uma chave dedicada. Depois instale a metade pública dela na produção, com um comando forçado, para que a chave só consiga fazer exatamente uma coisa: ler arquivos. Ela não consegue abrir um shell, encaminhar uma porta, ou escrever nada.

    # on the backup host
    ssh-keygen -t ed25519 -a 100 -f ~/.ssh/pull_prod -C "pull@backup"
    
    # on production, in /root/.ssh/authorized_keys — one line
    command="/usr/bin/rrsync -ro /",restrict ssh-ed25519 AAAAC3Nz… pull@backup

    O rrsync já vem com o rsync (/usr/bin/rrsync no Debian 13; /usr/share/doc/rsync/scripts/rrsync em versões mais antigas), e o -ro faz ele recusar qualquer coisa que não seja leitura. O restrict desativa encaminhamento de porta, encaminhamento de agente, alocação de PTY e X11 numa palavra só. Verifique se a jaula segura antes de confiar nela — ssh -i ~/.ssh/pull_prod root@production precisa falhar em te dar um shell.

  4. Faça o dump dos bancos na produção, na própria agenda deles

    A produção ainda tem um único trabalho: gerar dumps consistentes num diretório de staging que o pull vai recolher. Isso não exige nenhuma credencial de backup, e é exatamente por isso que o desenho funciona.

    # /usr/local/sbin/dump-db.sh   (chmod 700)
    set -euo pipefail
    D=/var/backups/db; install -d -m 700 "$D"
    mariadb-dump --single-transaction --quick --routines --triggers --events \
      --all-databases | zstd -T0 > "$D/all.sql.zst.tmp"
    mv "$D/all.sql.zst.tmp" "$D/all.sql.zst"

    Note o escrever-em-temp-depois-renomear: isso significa que o pull nunca consegue recolher um dump escrito pela metade, seja qual for o timing. O set -euo pipefail não é decoração — sem ele, um mariadb-dump que falha manda um stream vazio pelo pipe para o zstd, que tem sucesso, e você acaba com um arquivo comprimido válido que não contém absolutamente nada. Essa é a forma mais comum de um backup ser silenciosamente inútil. Rode isso a partir do próprio timer, meia hora antes do pull.

  5. Puxe os dados para o host de backup

    No host de backup, use rsync para trazer a lista de inclusão da produção para uma árvore de staging. Só os blocos alterados atravessam a rede, então, depois da primeira execução, isso fica rápido e barato.

    # /usr/local/sbin/pull.sh   (chmod 700, runs on the BACKUP host)
    set -euo pipefail
    [email protected]
    # -r is spelled out on purpose: with --files-from, -a does NOT imply
    # recursion, and without it you silently copy empty directories.
    rsync -aHAX -r --delete --numeric-ids \
      -e "ssh -i /root/.ssh/pull_prod -o BatchMode=yes" \
      --files-from=/etc/backup/include.txt \
      --exclude-from=/etc/backup/exclude.txt \
      "$SRC:/" /srv/staging/prod/

    -aHAX preserva hardlinks, ACLs e atributos estendidos, e --numeric-ids mantém a titularidade coerente entre máquinas cujos /etc/passwd diferem. O --delete é seguro aqui precisamente porque o staging não é o backup — o histórico versionado mora no repositório restic construído no próximo passo, então uma exclusão que se propaga para o staging ainda é recuperável a partir do snapshot de ontem.

  6. Inicialize o repositório e guarde a chave offline

    Ainda no host de backup, crie um repositório restic local e faça backup da árvore de staging dentro dele. Local significa nenhuma rede no caminho crítico, nenhuma credencial remota para roubar, e uma restauração que roda na velocidade do disco.

    apt install -y restic
    install -d -m 700 /etc/backup
    openssl rand -base64 32 > /etc/backup/pass   # write this into your password manager NOW
    chmod 600 /etc/backup/pass
    
    export RESTIC_REPOSITORY=/srv/restic/prod
    export RESTIC_PASSWORD_FILE=/etc/backup/pass
    restic init

    Copie essa passphrase para um gerenciador de senhas, e ao lado dela anote o caminho do repositório e o comando de restauração. Depois prove que funciona: de uma terceira máquina, usando só o gerenciador de senhas, rode restic -r sftp:backup@…:/srv/restic/prod snapshots. Se isso listar os snapshots, a chave é genuinamente recuperável. Se precisar de qualquer coisa que só exista em um dos dois servidores, resolva isso agora, em vez de descobrir depois.

  7. Agende, e transforme o silêncio num alarme

    Embrulhe o pull, a execução do restic e o prune num único script, e acione-o a partir de um timer do systemd. Note que o forget --prune é seguro de rodar aqui porque o host de backup é o legítimo dono do repositório — a produção nunca guardou uma credencial de exclusão em momento nenhum.

    # tail of /usr/local/sbin/backup.sh
    restic backup /srv/staging/prod --tag nightly
    restic forget --keep-daily 7 --keep-weekly 5 --keep-monthly 12 \
                   --keep-yearly 2 --prune
    curl -fsS -m 10 --retry 3 https://hc.example.net/ping/<uuid>  # only on success
    systemctl daemon-reload
    systemctl enable --now backup.timer
    systemctl list-timers backup.timer     # confirm the next run is where you expect

    O curl só roda se todo comando antes dele tiver dado certo, por causa do set -e. O monitor do outro lado espera um ping diário e alerta na ausência dele, o que transforma um job que parou silenciosamente num e-mail, em vez de numa descoberta arqueológica. enable --now, não só start — um timer que nunca foi habilitado sobrevive exatamente até o primeiro reboot.

  8. Rode o simulado de restauração, e anote quanto tempo levou

    Coloque um lembrete recorrente em algo que você realmente lê, uma vez por trimestre. Suba um Starter descartável, restaure nele usando nada além da passphrase e do procedimento escrito, suba a aplicação, verifique que ela serve dados reais, destrua a máquina. A cobrança por hora faz o simulado inteiro custar uns centavos.

    restic restore latest --target /restore
    zstd -dc /restore/var/backups/db/all.sql.zst | mariadb
    systemctl start nginx app
    curl -H 'Host: example.com' http://127.0.0.1/health

    Registre o tempo decorrido e cada surpresa que você encontrou, e depois conserte as surpresas no script de backup, não na sua memória. Esse tempo decorrido é o seu verdadeiro objetivo de recuperação; até você medi-lo uma vez, qualquer número que você citar é um chute.

Comparação

Onde colocar a cópia

Cada destino diante das quatro perguntas que decidem a escolha: quanto custa ao seu anonimato, quanto custa em dinheiro, quão rápido você recupera seus dados, e o que ele sobrevive.
DestinoCusto de anonimatoDinheiroVelocidade de restauraçãoSobrevive a
Segundo VPS no-KYC, região diferenteNenhum — pago do mesmo saldo em cripto, nenhuma identidade em lugar nenhum$5/mês, reduzido à metade num ciclo de 12 mesesRápida — de datacenter a datacenter, a 1–10 GbpsPerda de conta, comprometimento, uma jurisdição, seus próprios erros
Snapshot do provedorNenhumBaratoSegundosQuase nada — mesma conta, mesmo domínio de falha, morre junto com os dois
Object store (B2 / S3 / Wasabi)Alto — cartão e documento na conta, e a chave de API no seu servidor aponta para elaMuito barato para armazenar, taxas de egress doem na hora de restaurarRápida, se você aceitar a conta de egressComprometimento e perda de conta, ao preço de um nome grudado na máquina
Provedor de armazenamento que aceita criptoBaixo, se o caminho de pagamento for genuinamente livre de identidade — verifique, não presumaModeradoVaria muito — confira os limites de egress antes de precisar delesQuase tudo, com mais risco de contraparte do que um VPS que você controla
NAS doméstico, puxado via WireGuardNenhum — nada sai da sua própria rede sem criptografia ou sem atribuiçãoHardware que você já temLenta — limitada pela sua velocidade de upload residencialTudo, exceto a sua casa; fraca como cópia única, excelente como uma terceira
Nada / “está no git”NenhumGrátisNuncaNada. O git guarda o seu código; ele não guarda o seu banco de dados, seus uploads ou o seu /etc
FAQ

Perguntas que merecem resposta

Um snapshot do provedor já não é um backup?

Não, e a distinção não é uma questão de purismo. Um snapshot vive na mesma conta, sob as mesmas credenciais, no mesmo domínio de falha que o servidor que ele copia — então não sobrevive à perda da conta, e qualquer um que alcance seu painel pode apagá-lo junto com o original. Também é tirado de uma máquina em execução, o que significa que um banco de dados movimentado é capturado no meio de uma escrita. Use snapshots como botão de desfazer antes de mudanças arriscadas; use um repositório criptografado off-site como o backup.

restic ou Borg — qual devo usar?

restic, a menos que você tenha um motivo específico para não usar. Ele criptografa por padrão, não precisa de nada instalado no destino, fala todo backend que vale a pena usar, e vem como um único binário estático. O Borg deduplica e comprime melhor, e é visivelmente mais rápido em sistemas de arquivos com milhões de arquivos pequenos, mas precisa estar instalado e com versão compatível nas duas pontas, e é realmente pensado para um cliente por repositório. Caixa de e-mail enorme e as duas máquinas sob seu controle: Borg. Todo o resto: restic.

De quanto disco o destino do backup precisa?

Para um repositório deduplicado com a escada de retenção deste guia — 7 diários, 5 semanais, 12 mensais, 2 anuais — planeje algo entre duas e três vezes o tamanho dos dados que você realmente está salvando, não do servidor inteiro. Vinte e seis snapshots não significam vinte e seis cópias, porque só os blocos alterados são armazenados de novo. Um site pequeno com 15 GB de estado real cabe confortavelmente no Starter de 80 GB, com anos de histórico de sobra.

Um segundo VPS não dobra a minha conta de hospedagem?

Só se o destino do backup for do mesmo porte da produção, e ele não deveria ser. Ele não roda aplicação nenhuma e não serve tráfego nenhum; precisa de disco, não de CPU. Um Starter de $5 atrás de um servidor de produção de $30 é um sexto da conta, e o ciclo de 12 meses tira 50% disso. Comparado ao custo de perder tudo, é a linha mais barata da fatura — e o destino ainda serve de máquina de ensaio para o simulado de restauração.

Onde a senha do repositório deve morar?

Num gerenciador de senhas cujo cofre é, ele mesmo, salvo em outro lugar, ou no papel, ou nos dois — e ao lado dela, o endereço do repositório e o comando exato de restauração. A cópia em /etc no servidor é uma cópia de trabalho para a automação, nunca o registro. Verifique isso direito: de uma máquina que não seja nem a produção nem o host de backup, usando só o que está no gerenciador de senhas, rode restic snapshots. Se qualquer outra coisa for exigida, você ainda não tem um backup recuperável.

Com que frequência os backups devem rodar?

Pergunte quanto trabalho você está disposto a refazer. Todo dia à noite é o certo para a maioria dos servidores: no máximo um dia é perdido, e uma única execução noturna é fácil de raciocinar. Um banco de dados movimentado quer mais — dumps do banco de hora em hora, mantendo a passada completa de arquivos só à noite, é o formato mais comum. Frequência além desse ponto entrega menos do que o mesmo esforço gasto numa retenção mais longa e num simulado de restauração de verdade, que é onde mora o risco real.

Posso fazer backup de um servidor cujo disco está criptografado com LUKS?

Sim, e os dois são complementares, não redundantes. O LUKS protege o disco enquanto a máquina está desligada; o backup te protege de exclusão, corrupção e da perda total da máquina. Faça backup do sistema de arquivos montado exatamente como faria com um não criptografado — o restic criptografa de novo na saída, então o repositório fica seguro em armazenamento não confiável. Mantenha os dois segredos em lugares genuinamente separados: uma passphrase do LUKS guardada só dentro do repositório restic, ou uma passphrase do restic guardada só dentro do volume LUKS, é um laço que falha fechado dos dois lados.

Se o meu servidor for comprometido, os backups estão seguros?

Isso depende inteiramente de uma decisão que você tomou meses antes. Se o servidor de produção guarda uma credencial com direito de exclusão no repositório, então não — um atacante enumera e destrói os backups primeiro, porque é isso que transforma um incidente numa negociação. Se o repositório é append-only, ou se o host de backup faz o pull e a produção não guarda credencial de backup nenhuma, então o histórico sobrevive e você restaura a partir de um snapshot anterior à intrusão. Esse é o argumento inteiro para o desenho pull, e o motivo para preferi-lo antes de precisar dele.

Deploy your offshore server.

Escolha uma região. Escolha um plano. Cole uma chave. Pague. Os próximos 47 segundos são por nossa conta.