- Posted on
- • Artificial Intelligence
Artificial Intelligence Linux Disaster Recovery
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
AI-Driven Linux Disaster Recovery: Bash-first, Ops-ready
It’s 03:12, the pager screams, and your logs look like static. Disk errors spike, SSH failures bloom, and your team is still rubbing sleep out of their eyes. Minutes matter. This is exactly where a small dose of practical AI, wrapped in battle-tested Bash, can turn “we think” into “we know” — and trigger the right recovery action automatically.
In this article, you’ll build a lightweight AI-assisted disaster recovery (DR) workflow that:
Baselines your system logs and detects anomalies in near real time.
Verifies backups automatically (with actual restore tests).
Watches storage health (SMART) and adapts backup behavior.
Runs fully on Linux using Bash + Python, no external cloud needed.
The goal isn’t hype. It’s signal over noise, fewer false alarms, faster restores.
Why AI here — and why now?
Logs and metrics have outgrown “grep + intuition.” Even small fleets produce enough noise to hide real failures. A tiny unsupervised model can spot weirdness faster than humans scanning screens.
Backups are only as good as your last proven restore. AI can score when to verify and what to test, then run the drills without waiting for a human.
Storage fails gradually, then suddenly. Early hints in SMART data can prompt you to snapshot, back up, and plan a replacement before data loss.
You don’t need a GPU cluster or a PhD — just Python, a few packages, and the Unix philosophy: do one thing well, then glue it together with Bash.
What you’ll build
A Bash script to extract features from logs/metrics.
A small Python model (Isolation Forest) to flag anomalies.
A DR wrapper to auto-verify backups (restic/borg) and test-restore.
A SMART health check that increases backup urgency on risk.
Prerequisites and installation
Below are minimal packages you’ll need. Pick the section for your distro.
- Components:
- Python 3, pip, venv
- restic and/or borgbackup
- jq, rsync
- smartmontools
- a mail utility (mailutils or mailx)
- cron service
Debian/Ubuntu (apt)
sudo apt update
sudo apt install -y \
python3 python3-venv python3-pip \
restic borgbackup rsync jq smartmontools \
mailutils cron git
sudo systemctl enable --now cron
Fedora/RHEL (dnf)
sudo dnf install -y \
python3 python3-virtualenv python3-pip \
restic borgbackup rsync jq smartmontools \
mailx cronie git
sudo systemctl enable --now crond
openSUSE (zypper)
sudo zypper refresh
sudo zypper install -y \
python3 python3-virtualenv python3-pip \
restic borgbackup rsync jq smartmontools \
mailx cron git
sudo systemctl enable --now cron
Create a working directory and Python environment:
sudo mkdir -p /opt/ai-dr /var/lib/ai-dr /etc/ai-dr
sudo chmod 750 /opt/ai-dr /var/lib/ai-dr
sudo python3 -m venv /opt/ai-dr/venv
sudo /opt/ai-dr/venv/bin/pip install --upgrade pip
sudo /opt/ai-dr/venv/bin/pip install scikit-learn pandas numpy joblib
Set up a restic repository (local example; adapt for S3/SFTP/etc.):
sudo mkdir -p /backup/restic-repo
sudo mkdir -p /etc/restic
echo 'change_this_very_secret' | sudo tee /etc/restic/secret >/dev/null
sudo chmod 600 /etc/restic/secret
export RESTIC_REPOSITORY=/backup/restic-repo
export RESTIC_PASSWORD_FILE=/etc/restic/secret
restic init
If you use borg instead:
sudo mkdir -p /backup/borg-repo
borg init --encryption=repokey-blake2 /backup/borg-repo
Step 1: Collect signals with Bash (features from logs/metrics)
We’ll extract simple features from recent logs and system state. Start with journalctl (systemd). If your distro doesn’t use journald, adapt the grep source paths to /var/log/*.
Create /usr/local/sbin/log_features.sh:
#!/usr/bin/env bash
set -euo pipefail
OUT_DIR="/var/lib/ai-dr"
OUT_CSV="$OUT_DIR/features.csv"
WINDOW="5 minutes ago" # sliding window
TS="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
# Use journalctl if available, else tail /var/log/syslog or /var/log/messages
if command -v journalctl >/dev/null 2>&1; then
LOGSRC=$(journalctl --since "$WINDOW" -o short-iso 2>/dev/null || true)
else
# Fallback: gather from common log files (adjust for your distro)
LOGSRC=$( (tail -n 5000 /var/log/syslog 2>/dev/null; tail -n 5000 /var/log/messages 2>/dev/null) || true )
fi
# Basic counts
total_lines=$(printf "%s\n" "$LOGSRC" | wc -l || echo 0)
err_lines=$(printf "%s\n" "$LOGSRC" | grep -Ei 'error|failed|segfault|panic|i/o error|kernel oops|oom' | wc -l || echo 0)
# SSH auth failures (journal or auth.log)
if command -v journalctl >/dev/null 2>&1; then
ssh_fail=$(journalctl -u ssh -u sshd --since "$WINDOW" 2>/dev/null | grep -E 'Failed password|Invalid user' | wc -l || echo 0)
else
ssh_fail=$(grep -E 'Failed password|Invalid user' /var/log/auth.log 2>/dev/null | tail -n 5000 | wc -l || echo 0)
fi
# OOM kills
oom_kills=$(printf "%s\n" "$LOGSRC" | grep -E 'Out of memory|Killed process' | wc -l || echo 0)
# Disk I/O errors
io_err=$(printf "%s\n" "$LOGSRC" | grep -Ei 'I/O error|EXT4-fs error|Buffer I/O error' | wc -l || echo 0)
# Load average snapshot
load_1=$(cut -d ' ' -f1 /proc/loadavg)
# Header if new file
if [ ! -f "$OUT_CSV" ]; then
echo "timestamp,total_lines,err_lines,ssh_fail,oom_kills,io_err,load_1" | sudo tee "$OUT_CSV" >/dev/null
sudo chmod 640 "$OUT_CSV"
fi
echo "$TS,$total_lines,$err_lines,$ssh_fail,$oom_kills,$io_err,$load_1" | sudo tee -a "$OUT_CSV" >/dev/null
sudo install -m 0750 /usr/local/sbin/log_features.sh /usr/local/sbin/log_features.sh
Run it manually once to seed data:
sudo /usr/local/sbin/log_features.sh
Step 2: Train and score anomalies (tiny Python + Isolation Forest)
Create /opt/ai-dr/train_detect.py:
#!/usr/bin/env python3
import os, sys, json
import pandas as pd
from sklearn.ensemble import IsolationForest
from joblib import dump, load
FEATURES_CSV = "/var/lib/ai-dr/features.csv"
MODEL_PATH = "/var/lib/ai-dr/model.joblib"
def main():
df = pd.read_csv(FEATURES_CSV)
# Keep a reasonable window to adapt but not overfit
df = df.tail(2000).reset_index(drop=True)
feature_cols = ["total_lines","err_lines","ssh_fail","oom_kills","io_err","load_1"]
X = df[feature_cols].fillna(0)
# Train/update model when we have enough samples
if len(X) < 50:
print(json.dumps({"ready": False, "reason": "insufficient_data", "count": len(X)}))
return
clf = IsolationForest(
n_estimators=200, contamination=0.02, random_state=42, n_jobs=-1
)
clf.fit(X[:-1]) # train on all but the latest row
# Save model for reuse (optional)
try:
dump(clf, MODEL_PATH)
except Exception:
pass
latest = X.iloc[[-1]]
pred = clf.predict(latest)[0] # -1 anomalous, 1 normal
score = clf.decision_function(latest)[0] # lower = more anomalous
out = {
"ready": True,
"anomalous": (pred == -1),
"score": float(score),
"n_samples": int(len(X))
}
print(json.dumps(out))
if __name__ == "__main__":
sys.exit(main())
sudo install -m 0750 /opt/ai-dr/train_detect.py /opt/ai-dr/train_detect.py
Test it:
sudo /usr/local/sbin/log_features.sh
sudo /opt/ai-dr/venv/bin/python /opt/ai-dr/train_detect.py
You should see JSON output with a score and anomaly flag after enough samples.
Step 3: Wire it to backups and real restore checks
Create an environment file for secrets and repo paths:
/etc/ai-dr/env:
# restic settings
export RESTIC_REPOSITORY=/backup/restic-repo
export RESTIC_PASSWORD_FILE=/etc/restic/secret
# what to back up and test-restore
export BACKUP_SRC="/etc /var/www /home"
export RESTORE_TEST_PATH="/var/tmp/ai-dr-restore"
export DR_ALERT_EMAIL="root@localhost"
sudo chmod 600 /etc/ai-dr/env
Create /usr/local/sbin/ai-dr.sh:
#!/usr/bin/env bash
set -euo pipefail
. /etc/ai-dr/env
VENV="/opt/ai-dr/venv"
FEATURES="/usr/local/sbin/log_features.sh"
PY="/opt/ai-dr/train_detect.py"
send_alert() {
local subject="$1"
local body="$2"
if command -v mail >/dev/null 2>&1; then
echo "$body" | mail -s "$subject" "$DR_ALERT_EMAIL"
elif command -v mailx >/dev/null 2>&1; then
echo "$body" | mailx -s "$subject" "$DR_ALERT_EMAIL"
else
logger -t ai-dr "ALERT: $subject - $body"
fi
}
restic_backup() {
. /etc/ai-dr/env
restic backup $BACKUP_SRC --json | jq -C . || true
}
restic_verify_restore() {
. /etc/ai-dr/env
local tgt="${RESTORE_TEST_PATH}-$(date +%s)"
mkdir -p "$tgt"
# Restore a small but critical slice (adjust includes)
restic restore latest --target "$tgt" --include /etc/hosts --include /etc/fstab
# Basic integrity check
if [ -f "$tgt/etc/hosts" ]; then
logger -t ai-dr "Restore test OK at $tgt"
echo "Restore test OK at $tgt"
else
send_alert "AI-DR restore test FAILED" "Could not find restored files in $tgt"
fi
}
main() {
sudo -n true >/dev/null 2>&1 || true
$FEATURES
local out
out=$(/opt/ai-dr/venv/bin/python "$PY")
echo "$out" | jq -C . || echo "$out"
local ready
ready=$(echo "$out" | jq -r '.ready // false' 2>/dev/null || echo "false")
if [ "$ready" != "true" ]; then
logger -t ai-dr "Model not ready yet"
exit 0
fi
local anomalous
anomalous=$(echo "$out" | jq -r '.anomalous' 2>/dev/null || echo "false")
local score
score=$(echo "$out" | jq -r '.score' 2>/dev/null || echo "0")
if [ "$anomalous" = "true" ]; then
send_alert "AI-DR anomaly detected (score=$score)" "Triggered backup verification and test restore."
# 1) Run a fresh backup (optional but recommended during anomaly)
restic_backup || true
# 2) Verify repo health
restic check --with-cache --read-data-subset=1/20 || send_alert "restic check FAILED" "Repo check failed"
# 3) Perform a targeted test-restore
restic_verify_restore
fi
}
main "$@"
sudo install -m 0750 /usr/local/sbin/ai-dr.sh /usr/local/sbin/ai-dr.sh
Seed an initial backup and a first check:
sudo bash -lc '. /etc/ai-dr/env; restic backup $BACKUP_SRC'
sudo bash -lc '. /etc/ai-dr/env; restic check'
Optional: borg users can add a parallel verify block:
borg create --stats /backup/borg-repo::"$(hostname)-$(date +%F-%H%M)" $BACKUP_SRC
borg list /backup/borg-repo
borg extract --dry-run /backup/borg-repo::"latest" etc/hosts
Schedule via cron (runs every 5 minutes):
echo '*/5 * * * * root /usr/local/sbin/ai-dr.sh >>/var/log/ai-dr.log 2>&1' | sudo tee /etc/cron.d/ai-dr >/dev/null
sudo systemctl restart cron 2>/dev/null || sudo systemctl restart crond 2>/dev/null || true
Step 4: Watch storage health (SMART) and adapt behavior
SMART counters often drift before failure. If they tick up, back up now and plan a swap.
Create /usr/local/sbin/smart_guard.sh:
#!/usr/bin/env bash
set -euo pipefail
. /etc/ai-dr/env
BAD=0
REPORT=""
for d in /dev/sd? /dev/nvme?n1; do
[ -e "$d" ] || continue
out=$(smartctl -A "$d" 2>/dev/null || true)
realloc=$(echo "$out" | awk '/Reallocated_Sector_Ct/ {print $10}' | tail -n1)
pending=$(echo "$out" | awk '/Current_Pending_Sector/ {print $10}' | tail -n1)
offline=$(echo "$out" | awk '/Offline_Uncorrectable/ {print $10}' | tail -n1)
realloc=${realloc:-0}; pending=${pending:-0}; offline=${offline:-0}
if [ "$realloc" -gt 0 ] || [ "$pending" -gt 0 ] || [ "$offline" -gt 0 ]; then
BAD=1
REPORT+="Device $d risk: realloc=$realloc pending=$pending offline=$offline\n"
fi
done
if [ $BAD -eq 1 ]; then
if command -v mail >/dev/null 2>&1; then
echo -e "$REPORT" | mail -s "SMART risk detected" "$DR_ALERT_EMAIL"
elif command -v mailx >/dev/null 2>&1; then
echo -e "$REPORT" | mailx -s "SMART risk detected" "$DR_ALERT_EMAIL"
fi
# Run a priority backup
restic backup $BACKUP_SRC --json | jq -C . || true
fi
sudo install -m 0750 /usr/local/sbin/smart_guard.sh /usr/local/sbin/smart_guard.sh
echo '15 * * * * root /usr/local/sbin/smart_guard.sh >>/var/log/ai-dr.log 2>&1' | sudo tee -a /etc/cron.d/ai-dr >/dev/null
Real-world-style walkthrough
02:08 — Isolation Forest detects a spike in I/O errors and OOM kills against your normal 5-minute baseline.
The ai-dr.sh wrapper sends an alert, takes a fresh restic backup, runs restic check, and performs a targeted restore of /etc/hosts and /etc/fstab into a temp dir to prove the last snapshot is usable.
SMART guard at 03:00 flags Current_Pending_Sector > 0 on /dev/sdb, triggers another backup, and includes a clear report in the alert email.
Your on-call wakes to not only an alert but tangible proof that the restore path is alive. A disk swap is scheduled before business hours.
That is AI delivering clarity and buying you time.
Hardening tips
Protect secrets: keep RESTIC_PASSWORD_FILE mode 600, avoid exporting plain passwords in profiles.
Separate repos for hot and cold backups; store one offsite or immutable (e.g., object storage with write-once).
Prune and check regularly:
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune restic check --read-data-subset=1/10Test restores of representative data weekly. Automate AND randomly sample.
Conclusion and next steps (CTA)
You now have a lean, Linux-first disaster recovery loop:
Bash harvests signals.
A tiny AI model flags “weird.”
Backups are verified with real restore drills.
SMART risks accelerate your protection.
Next steps:
Expand feature extraction (network errors, service restarts, application logs).
Add host tags and centralize scores to prioritize fleet-wide drills.
Include a “full restore rehearsal” in a sandbox VM on a cadence.
If you use borg, mirror the verify/restore steps there as well.
Run a controlled DR drill this week. Time it. Document it. Then let this AI-assisted loop keep watch while you sleep.