Как да следим промяната на публичното IP в Linux и да получаваме известие в Telegram (Надежден Bash скрипт)

Следенето за промяна на ip адрес linux е важна задача, ако имате домашен сървър, Raspberry Pi, или просто използвате VPS с динамично адресиране. Вероятно ви е нужно да знаете кога външният ви IP адрес се е променил, за да обновите DNS записи или да получите известие. Повечето решения, които ще намерите в интернет…
В това ръководство ще ви покажем най-надеждния метод за промяна на ip адрес linux, който можете да настроите за минути.
Повечето решения, които ще намерите в интернет (или които ChatGPT ще ви генерира за 5 секунди), изглеждат така: правят една заявка, сравняват я с файл и пращат съобщение в Telegram. Проблемът е, че в реалната среда тези "играчки" скриптове се чупят, губят IP адреси при прекъсване на мрежата или изтичат пароли, ако случайно ги качите в публичен Git хранилище.
Днес ще ви покажа как да напишем наистина надежден (production-ready) Bash скрипт, който:
- Пази секретите си сигурно извън кода.
- Не се бърка, ако се стартира едновременно два пъти.
- Валидира истински IPv4 адреси (не просто "четири числа и точки").
- Записва новото IP само ако Telegram успешно е получил известието.
Стъпка 1: Подготовка на средата
Преди да напишем скрипта, трябва да подготвим файловата структура и да вземем нужните данни от Telegram.
1. Създаване на директории:
sudo mkdir -p /etc/check-ip
sudo mkdir -p /var/lib/check-ip
2. Създаване на Telegram бот и вземане на ID-то на чата:
- Отворете Telegram и намерете бота @BotFather. Създайте си нов бот и запазете неговия Token (примерно:
123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11). - За да разберете вашия
CHAT_ID, напишете съобщение на вашия нов бот, след това отворете в браузъра следния адрес (замествайки TOKEN-а с вашия):https://api.telegram.org/bot<TOKEN>/getUpdates - Потърсете в резултата полето
"chat":{"id": 123456789}. Това число е вашиятCHAT_ID`.
Стъпка 2: Сигурно съхранение на секретите
Никога не пишете токени директно в скрипта! Използвайте отделен файл с ограничени права.
Създайте файл /etc/check-ip/secrets.env:
sudo nano /etc/check-ip/secrets.env
Добавете следното съдържание (заместете с вашите реални данни):
TOKEN="ВАШИЯТ_TELEGRAM_BOT_TOKEN"
CHAT_ID="ВАШИЯТ_CHAT_ID"
Защитете файла, така че само root да може да го чете:
sudo chmod 600 /etc/check-ip/secrets.env
sudo chown root:root /etc/check-ip/secrets.env
📖
Стъпка 3: Самият скрипт
Създайте файла на скрипта, например в /usr/local/bin/check_ip.sh:
sudo nano /usr/local/bin/check_ip.sh
Вмъкнете следния код:
#!/usr/bin/env bash
set -euo pipefail
########################################
# Конфигурация
########################################
SECRETS_FILE="/etc/check-ip/secrets.env"
IP_FILE="/var/lib/check-ip/last_ip"
LOCK_FILE="/tmp/check_ip.lock"
LOG_FILE="/var/log/check_ip.log"
CURL_TIMEOUT=10
########################################
# Функция за логване (дефинирана рано)
########################################
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
########################################
# Зареждане на secrets
########################################
if [[ ! -f "$SECRETS_FILE" ]]; then
log "ГРЕШКА: липсва $SECRETS_FILE"
exit 1
fi
# shellcheck source=/dev/null
source "$SECRETS_FILE"
if [[ -z "${TOKEN:-}" || -z "${CHAT_ID:-}" ]]; then
log "ГРЕШКА: TOKEN или CHAT_ID не са зададени"
exit 1
fi
########################################
# Заключване (предотвратява едновременен запуск)
########################################
exec 9>"$LOCK_FILE"
if ! flock -n 9; then
log "Lock зает, пропускам изпълнението."
exit 0
fi
########################################
# Създаване на директория при нужда
########################################
mkdir -p "$(dirname "$IP_FILE")"
########################################
# Валидация на IPv4 (реални граници 0-255)
########################################
valid_ip() {
local ip=$1
[[ $ip =~ ^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$ ]] || return 1
local octet
for octet in "${BASH_REMATCH[@]:1}"; do
(( 10#$octet <= 255 )) || return 1
done
return 0
}
########################################
# Получаване на публичното IP (с fallback)
########################################
get_ip() {
local ip="" service
local services=(
"https://api.ipify.org"
"https://ipv4.icanhazip.com"
"https://checkip.amazonaws.com"
)
for service in "${services[@]}"; do
ip=$(curl --fail -s --max-time "$CURL_TIMEOUT" "$service" 2>/dev/null | tr -d '[:space:]') || {
log "Предупреждение: '$service' не отговори."
continue
}
if valid_ip "$ip"; then
echo "$ip"
return 0
else
log "Предупреждение: '$service' върна невалиден IP: '$ip'"
fi
done
echo ""
return 1
}
CURRENT_IP=$(get_ip) || true
########################################
# Проверка дали IP е валидно
########################################
if [[ -z "$CURRENT_IP" ]] || ! valid_ip "$CURRENT_IP"; then
log "ГРЕШКА: не успях да получа валиден IP от нито един източник."
exit 1
fi
########################################
# Старото IP
########################################
OLD_IP=""
if [[ -f "$IP_FILE" ]]; then
OLD_IP=$(cat "$IP_FILE")
fi
########################################
# Няма промяна
########################################
if [[ "$CURRENT_IP" == "$OLD_IP" ]]; then
exit 0
fi
########################################
# Telegram съобщение (escape на HTML спец. символи)
########################################
html_escape() {
local s=$1
s=${s//&/&}
s=${s//</<}
s=${s//>/>}
echo "$s"
}
HOSTNAME_ESC=$(html_escape "$(hostname)")
MESSAGE="<b>🔔 Промяна на публичното IP</b>
<b>Сървър:</b> <code>${HOSTNAME_ESC}</code>
<b>Старо:</b> <code>${OLD_IP:-Няма}</code>
<b>Ново:</b> <code>${CURRENT_IP}</code>
<i>$(date '+%Y-%m-%d %H:%M:%S')</i>"
########################################
# Изпращане към Telegram
########################################
if curl --fail -s \
-X POST "https://api.telegram.org/bot${TOKEN}/sendMessage" \
-d chat_id="${CHAT_ID}" \
-d parse_mode="HTML" \
--data-urlencode text="$MESSAGE" \
>/dev/null
then
# Атомарен запис на новото IP
echo "$CURRENT_IP" > "${IP_FILE}.tmp"
mv "${IP_FILE}.tmp" "$IP_FILE"
log "IP променено: ${OLD_IP:-няма} -> ${CURRENT_IP}"
else
log "ГРЕШКА: Telegram не прие съобщението. Новото IP НЕ е записано."
exit 1
fi
Направете скрипта изпълним:
sudo chmod +x /usr/local/bin/check_ip.sh
Защо този код е "Production-Ready"? (Анатомия на логиката)
Ако сте начинаещ, част от нещата в скрипта може да ви се страт странни. Ето защо са там:
set -euo pipefail: Това е първото правило на Bash скриптинга. Ако някоя команда гръмне, скриптът спира веднага. Ако ползвате недефинирана променлива – спира. Не позволява на грешките да се "разпространят" тихо надолу по кода.flock -n 9: Представете си, че скриптът се изпълнява презcronна всяка минута, но интернетът е бавен и скриптът се забави с 2 минути. Без това заключване, ще имате 2 едновременно работещи копия, които ще пращат двойни съобщения.flockгарантира, че работи само едно копие.10#$octet <= 255: Повечето хора валидират IP сРегулярни изрази (Regex). Проблемът е, че Regex-ът ще приема999.999.999.999като валиден формат, защото са просто цифри. Записът10#принуждава Bash да го прочете като десетично число и го сравнява с реалната максимална стойност на октет (255).- Атомарен запис (
mv): Защо не правим простоecho "$CURRENT_IP" > "$IP_FILE"? Ако системата рестартира или прекъсне тока точно в милисекундата, в която се пише файлът, той ще се развали. Пишем във.tmpфайл и използвамеmv, което в Linux е атомарна операция (или файлът е стар, или е нов, никога "раз_halfчен"). - Запис след успех: Обърнете внимание на най-долу – новото IP се записва в файла чак след като
curlкъм Telegram върне успех. Ако Telegram е блокиран или ботът ви е спрян, скриптът ще гръмне с грешка. На следващото му пускане, той отново ще види, че има разлика между старото и новото IP и ще опита да прати съобщението. Никога няма да пропуснете известие.
Стъпка 4: Автоматизация
Остава ни само да кажем на Linux да го изпълнява периодично. Отворете crontab на root потребителя:
sudo crontab -e
Добавете следния ред, за да проверявате на всеки 5 минути:
*/5 * * * * /usr/local/bin/check_ip.sh
Забележка: Първото пускане на скрипта (когато файла last_ip все още не съществува) автоматично ще прати съобщение в Telegram с "Старо: Няма", за да ви уведоми, че скриптът работи.
Готово! Вече имате изключително стабилна система за мониторинг на външния ви IP адрес, която можете да оставите да работи с години без намеса.
Намерихте материала за полезен?
Съдържанието на itpraktika.com е безплатно и ще остане такова.
Ако статията ти е помогнала — можеш да подкрепиш сайта с малка доброволна сума.
Всяко дарение помага за поддръжката и развитието на портала.
