feat: systemd timery + skripty pro udrzbu serveru

Skripty (4):
- update.sh: apt update + upgrade + restart kdyz nutny + Telegram
- docker-update.sh: docker compose pull + up -d pro vsechny sluzby
- docker-zalohy.sh: tar.zst zaloha data/ adresaru na NAS
- server-report.sh: denni Telegram report (uptime, RAM, disk, Docker)

Systemd (8 - 4x service + 4x timer):
- docker-update: kazdou sobotu 18:00
- docker-zalohy: kazde utery 20:00
- server-report: kazdy den 09:30
- update-rpi: kazdy patek 18:00

Konfigurace:
- conf/telegram.conf.example: sablona pro Telegram credentials
- vsechny skripty ctou z /home/<user>/.telegram.conf (chmod 600)

Poznamka:
- vsechny cesty (/home/mates) a hostname jsou pevne v service souborech
- pro jineho uzivatele uprav User=, WorkingDirectory=, ExecStart=
- zadne IP adresy, tokeny ani PII v gitu
This commit is contained in:
2026-08-01 22:26:40 +02:00
commit fba29e5171
16 changed files with 827 additions and 0 deletions
+122
View File
@@ -0,0 +1,122 @@
#!/bin/bash
#
# docker-update.sh - aktualizace Docker Compose projektu na tomto serveru
# (docker compose pull + up -d) + Telegram notifikace.
#
# Spust jednou rucne: bash docker-update.sh
# Spust automaticky: systemd timer docker-update.timer (kazdou sobotu 18:00)
#
# Konfigurace: /home/mates/.telegram.conf
# Log: /home/mates/skripty/update-docker-script/docker-update.log
#
set -euo pipefail
# === KONFIGURACE ===
USER_NAME="mates"
WORK_DIR="/home/$USER_NAME"
ZAKLADNI_SLOZKA="$WORK_DIR/docker"
LOG="$WORK_DIR/skripty/update-docker-script/docker-update.log"
CONFIG_FILE="$WORK_DIR/.telegram.conf"
DATUM=$(date '+%Y-%m-%d %H:%M:%S')
HOST=$(hostname)
# Seznam sluzeb k aktualizaci (uprav podle potreby)
AKTUALIZOVAT=(
audiobookshelf
calibre-web
glance
homeassistant
jswiki
plex
portainer
rustdesk
speedtest
vaultwarden
nginx
)
# === TELEGRAM KONFIGURACE ===
if [[ -f "$CONFIG_FILE" ]]; then
# shellcheck disable=SC1090
source "$CONFIG_FILE"
fi
TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-}"
TELEGRAM_CHAT_ID="${TELEGRAM_CHAT_ID:-}"
# === TELEGRAM HELPER ===
send_msg() {
local TEXT="$1"
if [[ -z "$TELEGRAM_BOT_TOKEN" || -z "$TELEGRAM_CHAT_ID" ]]; then
echo "$DATUM ⚠️ Telegram neni nakonfigurovan, preskakuji" >> "$LOG"
return 0
fi
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-d chat_id="${TELEGRAM_CHAT_ID}" \
-d text="$TEXT" \
-d parse_mode="Markdown" \
--max-time 10 \
--retry 3 > /dev/null || echo "$DATUM ⚠️ Telegram chyba" >> "$LOG"
}
# === HLAVNI LOGIKA ===
echo "$DATUM === docker-update.sh spusten ===" >> "$LOG"
send_msg "🔄 *[$HOST]* Spoustim aktualizaci Docker kontejneru..."
# Vytvor log adresar pokud neexistuje
mkdir -p "$(dirname "$LOG")"
AKTUALIZOVANO=()
CHYBY=()
for SLUZBA in "${AKTUALIZOVAT[@]}"; do
SLUZBA_PATH="$ZAKLADNI_SLOZKA/$SLUZBA"
if [[ ! -d "$SLUZBA_PATH" ]]; then
echo "$DATUM SKIP: $SLUZBA (slozka neexistuje)" >> "$LOG"
continue
fi
if [[ ! -f "$SLUZBA_PATH/docker-compose.yml" ]]; then
echo "$DATUM SKIP: $SLUZBA (docker-compose.yml chybi)" >> "$LOG"
continue
fi
echo "$DATUM === Aktualizuji: $SLUZBA ===" >> "$LOG"
cd "$SLUZBA_PATH"
# Stahnout nove image
if docker compose pull 2>>"$LOG"; then
# Restart s novym image
if docker compose up -d 2>>"$LOG"; then
AKTUALIZOVANO+=("$SLUZBA")
echo "$DATUM OK: $SLUZBA aktualizovan" >> "$LOG"
else
CHYBY+=("$SLUZBA (up)")
echo "$DATUM CHYBA: $SLUZBA - up -d selhalo" >> "$LOG"
fi
else
CHYBY+=("$SLUZBA (pull)")
echo "$DATUM CHYBA: $SLUZBA - pull selhalo" >> "$LOG"
fi
done
# === SOUHRN ===
POCET_OK=${#AKTUALIZOVANO[@]}
POCET_CHYB=${#CHYBY[@]}
if [[ $POCET_CHYB -eq 0 ]]; then
send_msg "✅ *[$HOST]* Docker aktualizace dokoncena.
Aktualizovano: $POCET_OK sluzeb
Seznam: ${AKTUALIZOVANO[*]}"
else
send_msg "⚠️ *[$HOST]* Docker aktualizace dokoncena s chybami.
Aktualizovano: $POCET_OK
Chyby: ${CHYBY[*]}"
fi
echo "$DATUM === docker-update.sh dokoncen ===" >> "$LOG"
exit 0
+108
View File
@@ -0,0 +1,108 @@
#!/bin/bash
#
# docker-zalohy.sh - zaloha Docker Compose projektu a jejich dat (./data adresaru)
# na NAS (nebo jiny backup disk) + Telegram notifikace.
#
# Spust jednou rucne: bash docker-zalohy.sh
# Spust automaticky: systemd timer docker-zalohy.timer (kazde utery 20:00)
#
# Konfigurace: /home/mates/.telegram.conf
# Log: /home/mates/zalohy/docker/docker.log
#
set -euo pipefail
# === KONFIGURACE ===
USER_NAME="mates"
WORK_DIR="/home/$USER_NAME"
SOURCE_DIR="$WORK_DIR/docker"
BACKUP_DIR="$WORK_DIR/zalohy/docker"
LOG_FILE="$BACKUP_DIR/docker.log"
CONFIG_FILE="$WORK_DIR/.telegram.conf"
# Seznam sluzeb k zalohovani (uprav podle potreby)
APP_DIRS=(
audiobookshelf
calibre-web
flatnotes
homeassistant
jswiki
miniflux
nginx
plex
speedtest
vaultwarden
wiki
glance
)
DATE_DIR=$(date +"%Y%m%d")
TIMESTAMP=$(date +"%H%M%S")
HOST=$(hostname)
# === TELEGRAM KONFIGURACE ===
if [[ -f "$CONFIG_FILE" ]]; then
# shellcheck disable=SC1090
source "$CONFIG_FILE"
fi
TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-}"
TELEGRAM_CHAT_ID="${TELEGRAM_CHAT_ID:-}"
# === TELEGRAM HELPER ===
send_msg() {
local TEXT="$1"
if [[ -z "$TELEGRAM_BOT_TOKEN" || -z "$TELEGRAM_CHAT_ID" ]]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Telegram neni nakonfigurovan, preskakuji" >> "$LOG_FILE"
return 0
fi
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-d chat_id="${TELEGRAM_CHAT_ID}" \
-d text="$TEXT" \
-d parse_mode="Markdown" \
--max-time 10 \
--retry 3 > /dev/null || echo "[$(date '+%Y-%m-%d %H:%M:%S')] ⚠️ Telegram chyba" >> "$LOG_FILE"
}
# === HLAVNI LOGIKA ===
mkdir -p "$BACKUP_DIR/$DATE_DIR"
START_TIME=$(date +%s)
ZALOHOVANO=()
CHYBY=()
for APP in "${APP_DIRS[@]}"; do
APP_PATH="$SOURCE_DIR/$APP"
if [[ ! -d "$APP_PATH" ]]; then
continue
fi
cd "$APP_PATH"
# Pokud existuje data/ adresar, zalohuj ho
if [[ -d "./data" ]]; then
BACKUP_FILE="$BACKUP_DIR/$DATE_DIR/${APP}-${TIMESTAMP}.tar.zst"
if tar --zstd -cf "$BACKUP_FILE" -C "$APP_PATH" data 2>>"$LOG_FILE"; then
ZALOHOVANO+=("$APP ($(du -h "$BACKUP_FILE" | cut -f1))")
else
CHYBY+=("$APP")
fi
fi
done
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
if [[ ${#CHYBY[@]} -eq 0 ]]; then
send_msg "✅ *[$HOST]* Docker zalohy dokonceny (${DURATION}s).
Zalohovano: ${#ZALOHOVANO[@]} sluzeb
Adresar: \`$BACKUP_DIR/$DATE_DIR\`"
else
send_msg "⚠️ *[$HOST]* Docker zalohy dokonceny s chybami.
Zalohovano: ${#ZALOHOVANO[@]}
Chyby: ${CHYBY[*]}"
fi
exit 0
+132
View File
@@ -0,0 +1,132 @@
#!/bin/bash
#
# server-report.sh - denni report stavu serveru na Telegram.
# Obsahuje: uptime, load, RAM, disk, teplota CPU, Docker kontejnery,
# Docker update log, zalohy, sitovy traffic.
#
# Spust jednou rucne: bash server-report.sh
# Spust automaticky: systemd timer server-report.timer (kazdy den 09:30)
#
# Konfigurace: /home/mates/.telegram.conf
#
set -euo pipefail
# === KONFIGURACE ===
USER_NAME="mates"
WORK_DIR="/home/$USER_NAME"
CONFIG_FILE="$WORK_DIR/.telegram.conf"
DOCKER_ROOT="$WORK_DIR/docker"
DOCKER_UPDATE_LOG="$WORK_DIR/skripty/update-docker-script/docker-update.log"
DOCKER_BACKUP_DIR="$WORK_DIR/zalohy/docker"
HOST=$(hostname)
INTERFACE="eth0" # nastav podle sveho serveru
# Prahy pro upozorneni
DISK_WARN=80
DISK_CRIT=90
TEMP_WARN=70
TEMP_CRIT=80
# === TELEGRAM KONFIGURACE ===
if [[ -f "$CONFIG_FILE" ]]; then
# shellcheck disable=SC1090
source "$CONFIG_FILE"
fi
TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-}"
TELEGRAM_CHAT_ID="${TELEGRAM_CHAT_ID:-}"
send_msg() {
local TEXT="$1"
if [[ -z "$TELEGRAM_BOT_TOKEN" || -z "$TELEGRAM_CHAT_ID" ]]; then
echo "Telegram neni nakonfigurovan, preskakuji"
return 0
fi
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-d chat_id="${TELEGRAM_CHAT_ID}" \
-d text="$TEXT" \
-d parse_mode="Markdown" \
--max-time 10 \
--retry 3 > /dev/null || echo "⚠️ Telegram chyba"
}
# === SYSTEMOVE STATISTIKY ===
UPTIME=$(uptime -p | sed 's/^up //')
LOAD=$(awk '{print $1" "$2" "$3}' /proc/loadavg)
RAM_USED=$(free -h | awk '/^Mem:/ {print $3}')
RAM_TOTAL=$(free -h | awk '/^Mem:/ {print $2}')
DISK_USED_HUMAN=$(df -h / | awk 'NR==2 {print $3}')
DISK_TOTAL_HUMAN=$(df -h / | awk 'NR==2 {print $2}')
DISK_PERCENT_RAW=$(df -P / | awk 'NR==2 {print $5}' | tr -d '%')
# CPU teplota (pokud je k dispozici)
TEMP_RAW=""
if [[ -f /sys/class/thermal/thermal_zone0/temp ]]; then
TEMP_RAW=$(cat /sys/class/thermal/thermal_zone0/temp 2>/dev/null || echo "")
fi
TEMP_HUMAN=""
if [[ -n "$TEMP_RAW" && "$TEMP_RAW" -gt 0 ]]; then
TEMP_C=$((TEMP_RAW / 1000))
TEMP_HUMAN="🌡️ CPU: ${TEMP_C}°C\n"
fi
# Docker kontejnery
CONTAINERS_RUNNING=$(docker ps -q 2>/dev/null | wc -l | tr -d ' ')
CONTAINERS_TOTAL=$(docker ps -aq 2>/dev/null | wc -l | tr -d ' ')
CONTAINERS_STOPPED=$((CONTAINERS_TOTAL - CONTAINERS_RUNNING))
# Sitovy traffic (pokud je dostupny)
NETWORK_RX=$(cat /sys/class/net/$INTERFACE/statistics/rx_bytes 2>/dev/null || echo "0")
NETWORK_TX=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes 2>/dev/null || echo "0")
NETWORK_RX_HUMAN=$(awk "BEGIN {printf \"%.2f GB\", $NETWORK_RX/1073741824}")
NETWORK_TX_HUMAN=$(awk "BEGIN {printf \"%.2f GB\", $NETWORK_TX/1073741824}")
# Posledni Docker update a zaloha
LAST_UPDATE="zatim neprobehla"
if [[ -f "$DOCKER_UPDATE_LOG" ]]; then
LAST_UPDATE=$(grep -E "=== (docker-update|update.sh) (spusten|dokoncen)" "$DOCKER_UPDATE_LOG" | tail -1 | awk '{print $1, $2}')
fi
LAST_BACKUP="zatim neprobehla"
if [[ -d "$DOCKER_BACKUP_DIR" ]]; then
LAST_BACKUP=$(ls -t "$DOCKER_BACKUP_DIR"/*/ 2>/dev/null | head -1 | xargs -I {} basename {} 2>/dev/null || echo "neni")
fi
# === SESTAVENI REPORTU ===
ALERTS=""
if [[ $DISK_PERCENT_RAW -ge $DISK_CRIT ]]; then
ALERTS="${ALERTS}🚨 *DISK KRITICKY: ${DISK_PERCENT_RAW}%*\n"
elif [[ $DISK_PERCENT_RAW -ge $DISK_WARN ]]; then
ALERTS="${ALERTS}⚠️ *DISK: ${DISK_PERCENT_RAW}%*\n"
fi
if [[ -n "$TEMP_RAW" && "$TEMP_RAW" -gt 0 ]]; then
TEMP_C=$((TEMP_RAW / 1000))
if [[ $TEMP_C -ge $TEMP_CRIT ]]; then
ALERTS="${ALERTS}🚨 *CPU KRITICKY: ${TEMP_C}°C*\n"
elif [[ $TEMP_C -ge $TEMP_WARN ]]; then
ALERTS="${ALERTS}⚠️ *CPU: ${TEMP_C}°C*\n"
fi
fi
# === ODESLANI ===
REPORT="${ALERTS}📊 *[$HOST]* Denni report
⏱️ Uptime: \`$UPTIME\`
📈 Load: \`$LOAD\`
🧠 RAM: $RAM_USED / $RAM_TOTAL
💾 Disk: $DISK_USED_HUMAN / $DISK_TOTAL_HUMAN (${DISK_PERCENT_RAW}%)
${TEMP_HUMAN}🌐 Sit ($INTERFACE):
RX: $NETWORK_RX_HUMAN | TX: $NETWORK_TX_HUMAN
🐳 Docker:
Bezi: $CONTAINERS_RUNNING | Celkem: $CONTAINERS_TOTAL
Stopped: $CONTAINERS_STOPPED
📅 Posledni Docker update: \`$LAST_UPDATE\`
💾 Posledni zaloha: \`$LAST_BACKUP\`"
send_msg "$REPORT"
exit 0
+96
View File
@@ -0,0 +1,96 @@
#!/bin/bash
#
# update.sh - aktualizace systemu (apt update + upgrade) + restart pokud nutny
# + Telegram notifikace o vysledku.
#
# Spust jednou rucne: sudo bash update.sh
# Spust automaticky: systemd timer update-rpi.timer (kazdy patek 18:00)
#
# Konfigurace: /home/mates/.telegram.conf (nebo nastav TELEGRAM_BOT_TOKEN a TELEGRAM_CHAT_ID v env)
#
set -euo pipefail
# === KONFIGURACE ===
CONFIG_FILE="/home/mates/.telegram.conf"
USER_NAME="mates"
WORK_DIR="/home/$USER_NAME"
LOG_FILE="$WORK_DIR/update.log"
HOST=$(hostname)
RESTART_REQUIRED="/var/run/reboot-required"
# === TELEGRAM KONFIGURACE ===
if [[ -f "$CONFIG_FILE" ]]; then
# shellcheck disable=SC1090
source "$CONFIG_FILE"
fi
TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-}"
TELEGRAM_CHAT_ID="${TELEGRAM_CHAT_ID:-}"
# === TELEGRAM HELPER ===
send_msg() {
local TEXT="$1"
if [[ -z "$TELEGRAM_BOT_TOKEN" || -z "$TELEGRAM_CHAT_ID" ]]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Telegram neni nakonfigurovan, preskakuji notifikaci" >> "$LOG_FILE"
return 0
fi
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-d chat_id="${TELEGRAM_CHAT_ID}" \
-d text="$TEXT" \
-d parse_mode="Markdown" \
--max-time 10 \
--retry 3 > /dev/null || echo "[$(date '+%Y-%m-%d %H:%M:%S')] ⚠️ Telegram chyba" >> "$LOG_FILE"
}
# === PROMENNE ===
START_TIME=$(date +%s)
# === CHYBA HANDLER ===
on_error() {
local exit_code=$?
local end_time=$(date +%s)
local duration=$((end_time - START_TIME))
echo "[$(date '+%Y-%m-%d %H:%M:%S')] CHYBA: update.sh skončil s chybou (exit code $exit_code)" >> "$LOG_FILE"
send_msg "❌ *[$HOST]* Aktualizace systému selhala (${duration}s).
Zkontroluj log:
\`$LOG_FILE\`"
exit "$exit_code"
}
trap on_error ERR
# === HLAVNI LOGIKA ===
echo "[$(date '+%Y-%m-%d %H:%M:%S')] === update.sh spusten ===" >> "$LOG_FILE"
# Notifikace o zacatku
send_msg "🔄 *[$HOST]* Spoustim aktualizaci systemu..."
# Aktualizace baliku
echo "[$(date '+%Y-%m-%d %H:%M:%S')] apt update..." >> "$LOG_FILE"
sudo apt-get update -qq 2>>"$LOG_FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] apt upgrade..." >> "$LOG_FILE"
sudo apt-get upgrade -y -qq 2>>"$LOG_FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] apt autoremove..." >> "$LOG_FILE"
sudo apt-get autoremove -y -qq 2>>"$LOG_FILE"
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
# Restart?
if [[ -f "$RESTART_REQUIRED" ]]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Restart required" >> "$LOG_FILE"
send_msg "⚠️ *[$HOST]* Aktualizace systemu dokoncena (${DURATION}s).
**Restart serveru je nutny!** Reboot bude proveden za 1 minutu."
# Naplanovany restart za 1 minutu (at muzes kanclovat)
sudo shutdown -r +1 "Systemovy restart po update"
else
send_msg "✅ *[$HOST]* Aktualizace systemu dokoncena (${DURATION}s).
Restart nutny neni."
fi
echo "[$(date '+%Y-%m-%d %H:%M:%S')] === update.sh dokoncen (${DURATION}s) ===" >> "$LOG_FILE"
exit 0