Il backup delle configurazioni è un’attività fondamentale, come abbiamo spesso ribadito, anche per gli apparati di rete. Disporre di una copia aggiornata della configurazione consente di ripristinare più rapidamente un dispositivo in caso di guasto, reset o perdita accidentale delle impostazioni.
AP Zyxel AX1800
Gli access point Zyxel della serie AX1800 espongono una CLI accessibile tramite SSH, che permette di eseguire comandi amministrativi e, tra le altre operazioni, ottenere la configurazione corrente del dispositivo.
Configurazione dell’AP
Da Configuration > User si consiglia di creare un utente dedicato al backup.
L’utente deve disporre dei privilegi amministrativi necessari per eseguire show running-config.
L’accesso SSH deve essere abilitato da Configuration > System.
Una volta abilitato il servizio, è possibile verificare l’accesso alla CLI col comando:
ssh backup@10.0.5.20 -p 19222
I comandi disponibili sono i seguenti, visibili digitando ?:
Router>
<cr>
apply
atse
configure
copy
daily-report
debug
delete
diag
diaginfo
dir
disable
enable
exit
iperf
no
nslookup
packet-trace
ping
ping6
psm
reboot
release
rename
renew
run
setenv
show
shutdown
ssh
sshcon
tcpping
telnet
tracepath
tracepath6
traceroute
traceroute6
wds
wizard
wlan-report
write
Script di backup
Lo script zyxel_ax1800_config_backup.sh è stato predisposto in /opt/ap-backup e utilizza sshpass per fornire la password SSH contenuta in un file separato zyxel_ax1800.pass.
#!/bin/bash
(
# Exit immediately if a command exits with a non-zero status, or if an unset variable is referenced
set -euo pipefail
umask 077
########################################
# CONFIGURATION
########################################
readonly ZYXEL_AP_IP=""
readonly SSH_PORT="19222"
readonly SSH_USER=""
readonly SSH_PASSWORD_FILE="zyxel_ax1800.pass"
readonly BACKUP_DIR="backups"
readonly LOG_DIR="logs"
readonly TIMESTAMP=$(date '+%Y-%m-%d_%H-%M-%S')
readonly LOG_FILE="$LOG_DIR/backup_zyxel_$(date '+%Y-%m-%d').log"
readonly BACKUP_FILE="$BACKUP_DIR/ax1800-$TIMESTAMP.conf"
readonly TMP_FILE=$(mktemp)
readonly HOSTNAME="$(hostname -f)"
readonly FROM=""
readonly TO=""
# Create directories if they don't exist
mkdir -p -- "$BACKUP_DIR" "$LOG_DIR"
chmod 700 "$BACKUP_DIR" "$LOG_DIR"
########################################
# FUNCTIONS
########################################
# Cleanup and send status notification on exit
cleanup() {
local exit_code=$?
if [[ -f "$TMP_FILE" ]]; then
shred -uz "$TMP_FILE" 2>/dev/null || rm -f -- "$TMP_FILE"
fi
if [[ $exit_code -eq 0 ]]; then
echo "Zyxel AX1800 backup completed successfully." | \
mail -s "$HOSTNAME: Zyxel AX1800 backup completed" -r "$FROM" "$TO"
else
echo "Zyxel AX1800 backup failed. Check the logs." | \
mail -s "$HOSTNAME: ERROR - Zyxel AX1800 backup failed" -r "$FROM" "$TO"
fi
}
# Set trap for cleanup on exit or error
trap cleanup EXIT INT TERM
# Log function (appends to log file with timestamp)
log() {
local message="$1"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $message" >> "$LOG_FILE"
}
remove_old_log_file() {
find "$LOG_DIR" -type f -name "*.log" -mtime +10 -exec rm -f {} \;
}
########################################
# PRE-CHECKS
########################################
# Check if password file exists
if [[ ! -f "$SSH_PASSWORD_FILE" ]]; then
log "ERROR: Password file not found: $SSH_PASSWORD_FILE"
exit 1
fi
# Check if password file is readable
if [[ ! -r "$SSH_PASSWORD_FILE" ]]; then
log "ERROR: Password file not readable: $SSH_PASSWORD_FILE"
exit 1
fi
# --- Verify sshpass is now available ---
if ! command -v sshpass &>/dev/null; then
apt install sshpass -y
fi
########################################
# MAIN
########################################
# --- Backup via SSH ---
log "Starting backup for $ZYXEL_AP_IP..."
if ! sshpass -f "$SSH_PASSWORD_FILE" \
ssh -tt \
-o StrictHostKeyChecking=yes \
-o ConnectTimeout=10 \
-o ServerAliveInterval=10 \
-o ServerAliveCountMax=1 \
-p "$SSH_PORT" \
"$SSH_USER@$ZYXEL_AP_IP" <<'EOF' > "$TMP_FILE" 2>/dev/null
show running-config
exit
EOF
then
log "ERROR: SSH command failed"
exit 1
fi
# --- Cleanup BACKUP_FILE ---
# Remove unwanted lines (carriage returns, commands, prompts)
sed \
-e 's/\r$//' \
-e '/^[[:space:]]*show running-config[[:space:]]*$/d' \
-e '/^[[:space:]]*exit[[:space:]]*$/d' \
-e '/^[[:space:]]*Router>[[:space:]]*show running-config[[:space:]]*$/d' \
-e '/^[[:space:]]*Router>[[:space:]]*exit[[:space:]]*$/d' \
"$TMP_FILE" > "$BACKUP_FILE"
# --- Verify backup is not empty ---
if [[ ! -s "$BACKUP_FILE" ]]; then
log "ERROR: Backup file is empty"
rm -f -- "$BACKUP_FILE"
exit 1
fi
log "Backup saved to: $BACKUP_FILE"
remove_old_log_file
)
Lo script viene eseguito all’interno di una subshell, delimitata dalle parentesi ( ). Questa struttura permette di isolare l’esecuzione dello script dal processo della shell chiamante.
Lo script utilizza set -euo pipefail per rendere più rigorosa la gestione degli errori. Le tre opzioni hanno scopi distinti:
-e: interrompe l’esecuzione quando un comando termina con un codice di errore-u: considera come errore l’utilizzo di una variabile non definitapipefailfa sì che una pipeline venga considerata fallita se uno dei comandi che la compongono termina con un errore, anche quando l’ultimo comando della pipeline termina correttamente
Queste impostazioni permettono di evitare che un errore venga ignorato e che lo script prosegua producendo un backup non valido o incompleto.
Viene inoltre impostato umask 077 per fare in modo che i file creati dal processo non siano accessibili agli altri utenti del sistema.
La configurazione viene acquisita tramite SSH e salvata inizialmente in un file temporaneo, creato tramite mktemp. L’output viene quindi elaborato per rimuovere i comandi e i prompt della CLI, ottenendo un file contenente la configurazione.
Il file temporaneo viene eliminato al termine dell’esecuzione dalla funzione cleanup, che si occupa anche di inviare una notifica via email con l’esito dello script.
La funzione viene associata ai segnali di terminazione tramite:
trap cleanup EXIT INT TERM
I backup vengono salvati nella directory backups, mentre i messaggi di log relativi all’esecuzione vengono registrati nella directory logs. I log più vecchi di dieci giorni vengono rimossi automaticamente.
Parametri di configurazione
Prima dell’esecuzione è necessario configurare l’indirizzo IP dell’access point e l’utente utilizzato per la connessione SSH:
readonly ZYXEL_AP_IP=""
readonly SSH_USER=""
In ZYXEL_AP_IP deve essere inserito l’indirizzo IP dell’AP, mentre SSH_USER deve contenere il nome dell’utente precedentemente creato sull’access point.
Inoltre, per l’invio della mail sullo stato di esecuzione dello script devono essere valorizzate le seguenti variabili:
readonly FROM=""
readonly TO=""
Le email vengono inviate tramite il client SMTP ssmtp, la cui configurazione viene discussa nell’articolo dedicato.
La password dell’utente SSH non viene invece inserita direttamente nello script, ma deve essere salvata nel file zyxel_ax1800.pass. Il file deve contenere esclusivamente la password utilizzata per l’accesso SSH. Eseguire chmod 600 zyxel_ax1800.pass in modo che il file con la password sia leggibile solo dall’utente proprietario.
Automazione con systemd
Per eseguire automaticamente lo script è possibile utilizzare un servizio systemd. Il file /etc/systemd/system/zyxel-backup.service contiene:
[Unit]
Description=Zyxel AX1800 configuration backup
[Service]
Type=oneshot
RemainAfterExit=no
WorkingDirectory=/path/top/ap-backup
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ExecStart=/path/top/ap-backup/zyxel_ax1800_config_backup.sh
StandardOutput=journal
StandardError=journal
NoNewPrivileges=true
PrivateTmp=true
WorkingDirectory consente allo script di utilizzare i percorsi relativi definiti nella configurazione. StandardOutput e StandardError permettono di integrare l’output del processo nel system journal.
NoNewPrivileges=true impedisce al processo di acquisire ulteriori privilegi durante l’esecuzione, mentre PrivateTmp=true fornisce al servizio un ambiente temporaneo isolato.
L’esecuzione viene pianificata tramite zyxel-backup.timer:
[Unit]
Description=Daily timer for Zyxel AX1800 backup
[Timer]
OnCalendar=*-*-* 21:00:00
Persistent=true
Unit=zyxel-backup.service
[Install]
WantedBy=timers.target
Il parametro OnCalendar pianifica l’esecuzione giornaliera alle 21:00. Persistent=true permette a systemd di recuperare un’esecuzione persa, ad esempio nel caso in cui il sistema fosse spento all’orario previsto.
Dopo la creazione o la modifica delle unit è necessario ricaricare la configurazione di systemd:
systemctl daemon-reload
La struttura risultante è:
.
├── backups
│ ├── ax1800-2026-10-03_17-08-17.conf
│ └── ax1800-2026-10-03_17-09-33.conf
├── logs
│ ├── backup_zyxel_2026-10-02.log
│ └── backup_zyxel_2026-10-03.log
├── zyxel_ax1800.pass
└── zyxel_ax1800_config_backup.sh
Switch TL-SG116E
Per lo switch TL-SG116E è stato utilizzato tplink-easysmartbackup, uno script che permette di automatizzare il backup della configurazione degli switch TP-Link Easy Smart.
Questi dispositivi dispongono solo di un’interfaccia web, rendendo difficili i backup automatici. Questo script accede all’interfaccia web e scarica automaticamente i file di configurazione, consentendo di programmare backup regolari.
Configurazione
Dopo aver clonato o scaricato il repository, è necessario copiare switches.conf.example in switches.conf, inserendo i dati dello switch nel formato:
IP_ADDRESS:USERNAME:PASSWORD:DESCRIPTION
Lo script deve quindi essere reso eseguibile:
chmod 700 tplink-backup.sh
La configurazione consente di gestire più switch attraverso un unico file, rendendo possibile centralizzare i backup degli apparati Easy Smart.
Automazione con systemd
Anche in questo caso l’esecuzione è stata automatizzata tramite un servizio systemd e un relativo timer.
tplink-easysmartbackup.service
[Service]
Type=oneshot
RemainAfterExit=no
WorkingDirectory=/opt/backup/tplink-easysmartbackup
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ExecStart=/opt/backup/tplink-easysmartbackup/tplink-backup.sh
StandardOutput=journal
StandardError=journal
NoNewPrivileges=true
PrivateTmp=true
tplink-easysmartbackup.timer
[Unit]
Description=Daily timer for Switch TL-SG116E backup
[Timer]
OnCalendar=*-*-* 21:00:00
Persistent=true
Unit=tplink-easysmartbackup.service
[Install]
WantedBy=timers.target
Anche per queste unit è necessario ricaricare la configurazione di systemd dopo la loro installazione:
systemctl daemon-reload
La struttura del repository e dei file di backup generati dallo script è la seguente:
.
├── LICENSE
├── README.md
├── backups
│ ├── tplink_10_0_5_10_20261003_164554.cfg
│ └── tplink_10_0_5_10_20261003_164554.info
├── switches.conf
├── switches.conf.example
└── tplink-backup.sh
Notifiche
Al momento non è implementata alcuna forma di notifica all’utente in caso di completamento, errore o mancata esecuzione del backup.
Lo stato dell’esecuzione può essere verificato attraverso attraverso il journal del servizio.