Skip to main content

Emergency replica: how to have your home server backed up on a VPS

Rogelio Guerra Riverón
Author
Rogelio Guerra Riverón
Building my own web infrastructure from scratch. Here I document each step: servers, networks, containers and everything that comes along.

Having a server at home has an obvious weak point: if the power goes out, the router fails, or the disk dies, your website disappears. The solution is to have a replica in the cloud ready to activate in minutes.

The architecture
#

[servidor-casa]  →  rsync cada 6h  →  [VPS réplica]
  servicios activos                    réplica en espera
  TTL DNS: 5 min                       Uptime Kuma vigilando

The home server pushes content to the VPS every 6 hours. If the server goes down, I change the DNS and in 5 minutes the VPS serves the site.

Why push and not pull?
#

The home server is behind a residential router (Digi). The router only has ports 80 and 443 open. The VPS cannot connect via SSH to the home server directly.

The solution: the home server pushes to the VPS (it has free outgoing SSH), the VPS only receives.

VPS preparation
#

The VPS (Debian 12, 2 CPUs, 4GB RAM, 30GB disk) already had Docker installed. First, security:

# UFW: solo lo necesario
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

# Fail2ban SSH
sudo apt-get install -y fail2ban
# /etc/fail2ban/jail.local
[DEFAULT]
bantime  = 7d
findtime = 1h
maxretry = 3
ignoreip = 127.0.0.1/8 <IP_PUBLICA_CASA>

[sshd]
enabled = true
# SSH: solo clave pública
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl reload sshd

Traefik as reverse proxy
#

Same Traefik v2.11 as on the home server, with automatic Let’s Encrypt:

services:
  traefik:
    image: traefik:v2.11
    command:
      - --providers.docker=true
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --certificatesresolvers.letsencrypt.acme.email=tu@email.com
      - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
    ports:
      - "80:80"
      - "443:443"

Uptime Kuma: external monitoring
#

Uptime Kuma monitors the home server from outside. If it doesn’t respond, immediate email alert:

  uptime-kuma:
    image: louislam/uptime-kuma:1
    volumes:
      - ./data:/app/data
    labels:
      - traefik.enable=true
      - traefik.http.routers.uptime.rule=Host(`uptime.serviciosrogeliowar.com`)
      - traefik.http.routers.uptime.entrypoints=websecure
      - traefik.http.routers.uptime.tls.certresolver=letsencrypt

Standby replicas
#

The web and blog services are running on the VPS but with traefik.enable=false — Traefik ignores them, they’re not accessible from the internet. They only activate in an emergency:

  web-replica:
    image: nginx:alpine
    labels:
      - traefik.enable=false  # ← cambiar a true en emergencia

Rsync script from the home server
#

#!/bin/bash
# ~/infra/sync-to-vps.sh
VPS="usuario@<IP_PUBLICA_VPS>"
SSH_KEY="~/.ssh/id_ed25519"

rsync -az --delete \
  -e "ssh -i $SSH_KEY -o StrictHostKeyChecking=no" \
  ~/infra/blog/public/ \
  ${VPS}:~/infra/blog/public/

rsync -az --delete \
  -e "ssh -i $SSH_KEY -o StrictHostKeyChecking=no" \
  ~/infra/web/html/ \
  ${VPS}:~/infra/web/html/

Crontab on the home server:

0 */6 * * * ~/infra/sync-to-vps.sh

Emergency failover procedure
#

When the home server goes down:

  1. Edit on the VPS: change traefik.enable=false to traefik.enable=true in web and blog
  2. docker compose up -d in each directory
  3. In the DNS panel, change the A record of your domain from the home server IP to the VPS IP
  4. With a 5-minute TTL, in less than 10 minutes the site is back

When the home server recovers, reverse process: restore DNS, change back to traefik.enable=false on the VPS.

Result
#

  • Uptime Kuma monitoring from outside at uptime.serviciosrogeliowar.com
  • rsync automatic every 6 hours — maximum 6 hours of content lost in a failure
  • Recovery time (RTO): ~5 minutes
  • Maximum data loss (RPO): ~6 hours
  • Additional cost: just the VPS (I already had it)

For a home server, this architecture is more than sufficient.


Recommended equipment#

Affiliate links. No extra cost to you.