ru
Feedback

Не попадитесь на канал ботавода! Telemetrio находит и помечает такие каналы 👉 Хотите видеть метку — оформите подписку

LinuxSkill - Сводки с прода и Шпаргалки

LinuxSkill - Сводки с прода и Шпаргалки

Открыть в Telegram

Следим за новостями Linux, DevOps и ИБ, чтобы быть готовым к любым факапам. Бонусом — плотные шпаргалки и чеклисты для ежедневной работы в терминале. 📩 По всем вопросам: @chorapov Зеркало в MAX: https://max.ru/LinuxSkill РКН https://vk.cc/cMUwm4

Больше

📈 Аналитический обзор Telegram-канала LinuxSkill - Сводки с прода и Шпаргалки

Канал LinuxSkill - Сводки с прода и Шпаргалки (@linuxskill) языкового сегмента Русский является активным участником. Сейчас сообщество объединяет 10 677 подписчиков, занимая 11 415 место в категории Технологии и приложения и 59 550 место в регионе Россия.

📊 Показатели аудитории и динамика

С момента создания невідомо проект демонстрирует стремительный рост, собрав аудиторию из 10 677 подписчиков.

Согласно последним данным от 16 октября, 2026, канал показывает стабильную активность. За последние 30 дней изменение числа участников составило -47, а за последние 24 часа — -1, при этом общий охват остаётся высоким.

  • Статус верификации: Не верифицирован
  • Уровень вовлечённости (ER): Средний показатель вовлечённости аудитории составляет 11.02%. В первые 24 часа после публикации контент обычно набирает 4.66% реакций от общего числа подписчиков.
  • Охват публикаций: В среднем каждый пост получает 1 177 просмотров. В течение первых суток публикация набирает 498 просмотров.
  • Реакции и взаимодействия: Аудитория активно поддерживает контент: среднее количество реакций на один пост — 9.
  • Тематические интересы: Контент сосредоточен на ключевых темах, таких как docker, linux, bash, devops, скрипт.

📝 Описание и контентная политика

Автор описывает ресурс как площадку для выражения субъективного мнения:
“Следим за новостями Linux, DevOps и ИБ, чтобы быть готовым к любым факапам. Бонусом — плотные шпаргалки и чеклисты для ежедневной работы в терминале. 📩 По всем вопросам: @chorapov Зеркало в MAX: https://max.ru/LinuxSkill РКН https://vk.cc/cMUwm4”

Благодаря высокой частоте обновлений (последние данные получены 17 октября, 2026) канал поддерживает актуальность и высокий уровень охвата публикаций. Аналитика показывает, что аудитория активно взаимодействует с контентом, что делает его важной точкой влияния в категории Технологии и приложения.

10 677
Подписчики
-124 часа
-157 дней
-4730 дней
Архив постов
Найти на сервере скрытых рутов и не поверить проверке, которая их не видит. Найти лишние учётки с нулевым UID

getent passwd | awk -F: '($3 == 0) {print $1}'
Нюанс: в подборках пишут awk -F: '($3 == "0")' — со строковым сравнением. Оно пропускает UID, записанный как 00 или 0000. Проверил: завёл пользователя с -u 00, id показал uid=0(root), то есть для ядра это полноценный рут, а строковая проверка его не увидела. Без кавычек awk сравнивает числа и ловит все варианты. getent вместо cat /etc/passwd нужен, чтобы захватить пользователей из LDAP и SSSD. Убедиться, что root не пускают по SSH

sshd -T | grep -i permitrootlogin
Нюанс, и он главный. grep по /etc/ssh/sshd_config показывает то, что написано, а не то, что действует. Собрал стенд: в основном конфиге PermitRootLogin no, а в /etc/ssh/sshd_config.d/99-cloud.conf — yes. Строка Include стоит выше, drop-in побеждает:

grep     -> PermitRootLogin no
sshd -T  -> permitrootlogin yes
Именно так выглядит типовой облачный образ. sshd -T печатает итоговую конфигурацию после всех включений. Проверить sudoers перед сохранением

visudo -c -f /etc/sudoers.d/devops
visudo без аргументов знают все, а вот -c -f работает с любым файлом и годится для CI или проверки после Ansible. На кривом правиле показывает строку и место ошибки, на нормальном — parsed OK. Заодно sudo -l покажет, что реально разрешено текущему пользователю. Найти SUID-бинарники

find / -xdev -perm /6000 -type f -ls 2>/dev/null
Нюанс: -perm -4000 -user root из чек-листов пропускает SGID. На моей машине разница 9 файлов против 12 — мимо проверки прошли chage, expiry, ssh-agent. Фильтр -user root тоже лишний: чужой SUID опаснее рутового, а он под этот фильтр не попадёт. И -xdev обязателен, иначе find захлебнётся на /proc. Про sudo -i вместо su спорить не буду, но помнить стоит другое: жёсткие правила в sudoers обходятся через less, find, awk и десяток других утилит — у всех есть побег в шелл. Разрешать по одной команде безопаснее, чем кажется, только если это не интерпретатор. А вы root на серверах отключаете совсем или держите для аварийной консоли? #Linux #Security #SSH #sudo #DevOps

Выкинуть из скрипта форки awk и cut и не нарваться на подстановку, которая молчит Разобрать путь без basename и dirname

path="/var/log/nginx/access.log.tar.gz"
name="${path##*/}"   # access.log.tar.gz
dir="${path%/*}"     # /var/log/nginx
Замерил тысячу итераций в цикле: basename — 1107 мс, подстановка — 5 мс. Разница в двести раз, и это не про скорость самой утилиты, а про форк процесса на каждый вызов. Собрать файлы в массив вместо ls

shopt -s nullglob
files=(/var/log/nginx/*.log)
cp -- "${files[@]}" /backup/logs/
Нюанс: без nullglob массив по несуществующей маске не пустой. Проверил — в нём оказался один элемент, сама строка /var/log/nginx/*.nosuch, и cp уедет с несуществующим файлом. shopt -s nullglob заставляет пустой glob разворачиваться в ноль элементов. Сравнить вывод двух команд без временных файлов

diff <(ls -1 dir1) <(ls -1 dir2)
<(...) подставляет путь вида /dev/fd/63, за которым стоит обычный pipe — проверил через ls -l. Нюанс: код возврата команды внутри скобок теряется, diff его не увидит. И это только bash: в dash тот же синтаксис даёт Syntax error, так что для #!/bin/sh не годится. Задать дефолт и проверить обязательные переменные

: "${TIMEOUT:=30}"
: "${DB_USER:?не задана}"
Нюанс: двоеточие в :? обязательно. Вариант ${DB_USER?...} из подборок срабатывает только когда переменная не объявлена вовсе — пустую строку он пропускает, и скрипт идёт дальше с пустым логином. С :? тот же случай падает с кодом 127. То же и с :-: он подставляет дефолт, но не присваивает, переменная остаётся пустой. Собрать тайминги шагов скрипта

PS4='+ ${EPOCHREALTIME} '
set -x
Нюанс: в подборках сюда пишут PS4='+ $(date "+%s.%N") => ' — и это форк date на каждую строку трассировки, в посте про избавление от форков. Встроенная EPOCHREALTIME даёт то же время с микросекундами и без единого процесса. А что вы чаще выносите из скриптов — cut и awk или всё-таки оставляете, потому что читается понятнее? #Linux #Bash #Shell #Scripting #DevOps

Обойти массив путей с пробелами и не получить вместо одной папки три несуществующих. Перебрать элементы, не разорвав их по пробелам

folders=("/var/log/nginx" "/var/log/app with space")
for d in "${folders[@]}"; do
  ls -ld "$d"
done
Кавычки вокруг ${folders[@]} обязательны. Без них тот же цикл на моём тесте выдал четыре итерации вместо двух: путь распался на /var/log/app, with и space. И не путай @ с *: под кавычками "${folders[*]}" склеивает весь массив в одну строку. Посчитать элементы

echo "${#folders[@]}"
Нюанс: ${#folders} без [@] — это не размер массива, а длина первого элемента. У меня вернуло 8 вместо 3, и никакой ошибки. Обойти разреженный массив

for i in "${!sparse[@]}"; do
  echo "$i = ${sparse[$i]}"
done
Нюанс: если удалить элемент через unset, индексы останутся с дырками. Массив с индексами 0, 5, 9 имеет размер 3 — обход по seq 0 2 найдёт один элемент из трёх. Перебирать надо индексы через ${!arr[@]}, а не числа от нуля. Прочитать файл в массив

readarray -t lines < /var/log/app.log
readarray -t lines < <(grep -v '^$' /var/log/app.log)
Нюанс: cat file | readarray -t lines не работает. Пайп запускает readarray в подоболочке, массив заполняется там и умирает вместе с ней. У меня получилось 0 элементов вместо 4, снова без ошибки. Нужен либо редирект, либо подстановка процесса < <(...). Сделать словарь

declare -A ports=([nginx]=80 [php-fpm]=9000)
Нюанс: declare -A не формальность. Без него bash создаёт обычный индексный массив, все строковые ключи считаются нулём, и каждое присваивание перетирает предыдущее. Проверил: ${ports[nginx]} вернуло 9000 — значение от php-fpm. Общее у всех пяти: bash не ругается, а тихо делает не то. Поэтому shellcheck на скриптах с массивами экономит больше времени, чем кажется. А вы конфиги в bash разбираете ассоциативными массивами или сразу отдаёте jq? #Linux #Bash #Shell #Scripting #DevOps

🎥 Вебинар: «LVM без простоя: расширение тома, перенос данных и аварийный откат через snapshot» На открытом уроке разберем, к
🎥 Вебинар: «LVM без простоя: расширение тома, перенос данных и аварийный откат через snapshot» На открытом уроке разберем, как использовать возможности LVM при работе с хранилищем в production-среде. Рассмотрим расширение логического тома, перенос данных на другое блочное устройство и применение snapshot для возврата к предыдущему состоянию системы. О чем поговорим: — Как устроен LVM и какие задачи он помогает решать — Как расширять логические тома при увеличении объема данных — Как перенести данные на другое блочное устройство — Что такое snapshot и как он работает — Как использовать snapshot для отката при возникновении проблем 🧠 Вебинар приурочен к старту курса «Администратор Linux. Продвинутый уровень». Программа постоянно обновляется с учётом современных требований рынка. Занятия проводят практикующие эксперты, которые ежедневно работают с производственной инфраструктурой. Вы изучите востребованные инструменты: Zabbix, Prometheus, Docker, Nginx, PostgreSQL, ELK, Ansible, SELinux, Bash и многие другие. 👉 Для участия зарегистрируйтесь https://otus.pw/T9OrR/ Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru

Прокинуть скрипт и каталог на сервер и не собрать по дороге чужие абсолютные пути Всё проверено на OpenSSH 9.6p1, подключением к живому sshd. Увидеть, какие параметры реально применились

ssh -G user@host
Отдаёт итоговый конфиг после разбора всех Host и Match: порт, пользователя, список шифров, таймауты. Быстрее, чем перечитывать ~/.ssh/config глазами и гадать, какая секция сработала. Если сессия висит — ssh -vvv покажет, на каком этапе. Выполнить локальный скрипт на сервере

ssh user@host bash -s arg1 arg2 < ./script.sh
Нюанс: -s обязателен, если передаёшь аргументы. Без него bash примет arg1 за имя файла и ответит No such file or directory. И второе: интерактивный read внутри такого скрипта работать не будет — stdin уже занят самим скриптом. Убрать устаревший ключ хоста

ssh-keygen -f ~/.ssh/known_hosts -R '[10.0.0.1]:2222'
Нюанс: для нестандартного порта нужен формат [host]:port в кавычках. Просто -R 10.0.0.1 строку не найдёт и молча ничего не сделает. Старый файл сохраняется рядом как known_hosts.old. Забрать каталог без промежуточных файлов

ssh user@host "tar -cf - -C /data ." | tar -xC ~/bak/
Нюанс: -C на удалённой стороне обязателен. Вариант tar -cf - /data утащит в архив весь абсолютный путь, и локально ты получишь ~/bak/data/... вместо содержимого. Проверил — распаковалось именно так. Уйти в фон сразу после авторизации

ssh -f user@host "sleep 300"
Управление вернулось через 181 мс, при этом клиентский процесс продолжает висеть, пока команда не отработает. Удобно для проброса портов: ssh -f -N -L 9998:localhost:15672 user@host. Держать ключ в агенте ограниченное время

ssh-add -t 30 ~/.ssh/id_ed25519
Через 30 секунд ключ уйдёт из памяти агента сам. Нюанс: без запущенного ssh-agent команда просто скажет Could not open a connection to your authentication agent. Про sshpass из подборок: он кладёт пароль в аргументы процесса, где его видно в ps любому пользователю системы. Для закрытого стенда — ладно, дальше стенда лучше ProxyJump и ключи. А чем пробрасываете доступ к внутренним панелям — -L руками или прописываете в конфиг? #Linux #SSH #Networking #DevOps #Terminal

Сервис упал ночью, до утра гигабайт логов. Порядок, в котором в них лезть Начать с ошибок текущей загрузки

journalctl -p err -b
-b отсекает всё, что было до последней перезагрузки, -p err оставляет уровень Error и выше. Цифровой вариант -p 3 делает то же самое, но словом читается лучше. Сузить окно до времени инцидента

journalctl --since "2026-08-13 23:00:00" \
  --until "2026-08-14 01:00:00"
Нюанс: форматы вроде yesterday 23:00:00, которые кочуют по подборкам, systemd не разбирает — получишь Failed to parse timestamp. Проверил на systemd 255: отдельно yesterday работает, -2h работает, 23:00 работает, а вот их комбинация — нет. Надёжнее всегда писать полную дату. Посмотреть, не прибило ли сервис ядро

dmesg -T --level=err,warn
dmesg -T | grep -i oom-killer
-T переводит секунды аптайма в нормальную дату. Фильтр по уровню полезнее грепа: покажет и OOM, и ошибки диска, и отвалившийся сетевой интерфейс. Проверить блокировки SELinux

ausearch -m avc -ts recent
Нюанс: на Debian и Ubuntu команда чаще всего вернёт пустоту — там AppArmor, а не SELinux, и /sys/fs/selinux просто нет. Шаг актуален для RHEL-семейства; на Debian смотри journalctl -t audit и dmesg | grep -i apparmor. Найти, кто сканирует сайт

awk -F'"' '{split($3,a," ");
  if (a[1]==404) print $1}' access.log |
  awk '{print $1}' | sort | uniq -c | sort -rn
Нюанс: ходовой вариант awk '$9 == 404' разваливается, если в URL попал пробел — поле уезжает, и строка молча не считается. У меня из трёх запросов с 404 такой вариант нашёл два. Разбор по кавычкам берёт код ответа там, где он реально лежит. Для пары серверов этого хватает. Когда машин десятки, CLI перестаёт работать и нужен Loki или ELK — но и там первый вопрос будет тот же: какое окно и какой приоритет. А с чего начинаете вы, когда прод упал и надо быстро локализовать причину? #Linux #Logs #journalctl #Troubleshooting #DevOps

Диски гостей раздулись, а внутри места полно. Вернуть его хосту — и не просадить запись Проверить, поддерживает ли диск discard

lsblk --discard
Нюанс: в подборках советуют hdparm -I /dev/sda | grep -i trim. На virtio-диске это не сработает вовсе — у меня вернуло Operation not permitted, потому что hdparm говорит по протоколу ATA, которого у виртуального диска нет. lsblk --discard показывает нужное для любого типа:

NAME  DISC-GRAN DISC-MAX
vda          4K       1G
vdb          0B       0B
Ненулевые DISC-GRAN и DISC-MAX означают, что discard проходит. Нули — гипервизор его не отдаёт, дальше можно не настраивать. Отдать блоки хосту прямо сейчас

fstrim -av --dry-run
fstrim -av
Сначала --dry-run: он делает всё то же самое, но без самого discard. У меня показал 0 B (dry run) trimmed on /dev/vda, а боевой запуск вернул 243.1 GiB trimmed. Настроить регулярный TRIM

systemctl enable --now fstrim.timer
systemctl list-timers fstrim.timer
Нюанс: свой скрипт в /etc/cron.weekly писать не нужно — в пакете util-linux уже лежит готовый fstrim.timer с OnCalendar=weekly и разбросом запуска до 100 минут, чтобы виртуалки не пошли в discard одновременно. Если всё-таки делаешь через cron, помни про две вещи. Скрипт без строки #!/bin/sh не выполнится: run-parts: failed to exec: Exec format error. И файл с точкой в имени, вроде fstrim.sh, run-parts молча пропустит. Не включать онлайн-TRIM в fstab

UUID=xxxx / ext4 defaults,discard 0 1
Опция discard при монтировании шлёт запрос на очистку при удалении каждого файла. Пакетный TRIM раз в неделю делает то же самое, но одним заходом и в спокойное время. Всё это работает, только если discard включён в настройках диска на самом гипервизоре. Иначе гость честно шлёт команды, а хост их игнорирует и продолжает копить мусор. А вы fstrim по таймеру гоняете или руками, когда место кончилось? #Linux #Virtualization #Proxmox #fstrim #DevOps

🎥 Вебинар: Первый веб-сервер на Linux: Nginx, Apache и проверка доступности На открытом уроке разберем, как устроен веб-серв
🎥 Вебинар: Первый веб-сервер на Linux: Nginx, Apache и проверка доступности На открытом уроке разберем, как устроен веб-сервер на Linux и какие компоненты нужны для публикации веб-приложения. Рассмотрим базовую настройку Nginx и Apache, проверку доступности сервиса и принцип работы обратного прокси. О чем поговорим: — Из каких сервисов состоит базовая конфигурация веб-сервера — Чем отличаются задачи Nginx и Apache — Как установить и выполнить первичную настройку веб-сервера — Как проверить, что сервис запущен и доступен по сети — Как работает обратный прокси и для чего он используется 🧠 Вебинар приурочен к старту курса «Администратор Linux. Базовый уровень». Вы освоите Bash, TCP/IP, Nginx, Apache, MySQL, Docker, Git, Prometheus, Grafana и ELK. На живых занятиях с практикующими экспертами научитесь настраивать веб-серверы, работать с сетью, контейнерами, мониторингом и фильтрацией трафика. 👉 Для участия зарегистрируйтесь https://otus.pw/nUFb/ Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru

Как достать пароль из kdbx, когда графика легла и буфер обмена недоступен Всё проверено на keepassxc-cli 2.7.6 из репозитория Ubuntu 24.04. Посмотреть, что вообще есть в базе

keepassxc-cli ls -R database.kdbx
Нюанс: без -R увидишь только верхний уровень. Вложенные записи в группах не покажет — легко решить, что база пустая. Вытащить конкретный пароль в терминал

keepassxc-cli show -a Password database.kdbx "Production/DB"
Нюанс: обычный show без ключей выводит Password: PROTECTED вместо значения. Флаг -s раскрывает все поля, -a Password отдаёт только пароль одной строкой — удобно подставлять в скрипт. Открыть базу с файлом ключей

keepassxc-cli ls -k keyfile.key database.kdbx
Тот же -k работает во всех подкомандах. Если пароля на базе нет вообще, добавь --no-password, иначе утилита будет ждать ввода. Найти запись, когда не помнишь путь

keepassxc-cli search database.kdbx "DB"
Вернёт полный путь вида /Production/DB, который дальше подставляется в show. Забрать всю базу разом

keepassxc-cli export -f csv database.kdbx
Отдаёт в stdout все записи вместе с паролями открытым текстом. Полезно при переезде, но перенаправлять это в файл на общей машине — плохая идея. Про clip, который советуют для копирования пароля в буфер. Именно в сценарии «GUI лёг» он и не работает: без графической сессии команда отвечает All clipping programs failed. Tried xclip. Смысл в нём есть только в живой графике, где он же и чистит буфер через 10 секунд. И про совет закрыть GUI перед работой в консоли. Проверил: при открытой базе KeePassXC создаёт рядом файл .kdbx.lock. Утилита о нём знает, так что «гарантированного повреждения» не будет — но менять базу из двух мест одновременно всё равно не стоит, последняя запись затрёт чужие правки. А вы держите пароли в локальных kdbx или переехали на self-hosted Vaultwarden? #Linux #KeePass #Security #CLI #DevOps

Если гоняешь ansible по сотне серверов, SSH каждый раз делает хендшейк заново Переиспользовать одно TCP-соединение

# ~/.ssh/config
Host *
  ControlMaster auto
  ControlPath ~/.ssh/sockets/%C
  ControlPersist 10m
Замерил на локальном sshd: первое подключение 0.22 секунды, второе и третье — по 0.01. Разница в двадцать раз, и это на loopback, где сети как таковой нет. На реальном канале с задержкой выигрыш будет больше. Каталог ~/.ssh/sockets надо создать заранее, сам он не появится. Не упереться в лимит длины пути Нюанс: %C тут не для красоты. Классический %r@%h:%p на длинных именах хостов выходит за предел, и ssh отказывается работать:

ControlPath too long ('/root/.ssh/sockets/xxx...
  -root@127.0.0.1:2222' >= 108 bytes)
Проверил на пути в 109 байт — ровно на границе. %C даёт хеш фиксированной длины и снимает вопрос совсем. Проверить, жив ли мастер

ssh -O check user@host
Отвечает Master running (pid=924). Пригодится, когда непонятно, идёт ли новая сессия через кеш или поднимает соединение с нуля. Сбросить залипшую сессию

ssh -O exit user@host
Печатает Exit request sent. и удаляет файл сокета. Нужно, когда на сервере поменялись ключи или конфиг, а мастер держит старую сессию. Нюанс: если мастер-процесс умер не сам, а был убит, файл сокета остаётся сиротой. Прибил мастера через kill -9 — -O check стал отвечать Connection refused, но новое подключение прошло нормально: ssh увидел мёртвый сокет и поднял соединение заново. Честный минус: ноутбук ушёл в сон с активным сокетом — при пробуждении получишь висящую сессию и таймаут вместо мгновенного входа. Лечится тем же -O exit, но сначала надо догадаться, что дело в нём. А вы ControlPersist держите глобально на Host * или включаете точечно? #Linux #SSH #Ansible #DevOps #Terminal

Пробросить TCP через WebSocket мимо DPI и не собрать по дороге утечку сокетов websocat — консольный клиент вебсокетов на Rust, авторства Виталия Шукелы. Соединение начинается с обычного HTTP-рукопожатия Upgrade, поэтому фильтр видит легитимный веб-трафик. Проверял на версии 1.14.0, скачанной статическим бинарником с релизов. Пробросить локальный TCP-порт в вебсокет

websocat --binary -E \
  tcp-l:127.0.0.1:8080 ws://example.com/socket
Нюанс: без -E websocat печатает предупреждение про утечку сокетов при обслуживании нескольких клиентов. У меня оно вылезало на каждом запуске туннеля, с флагом лог чистый. Держать сессию живой на нестабильной сети

websocat -t --ping-interval 10 \
  - autoreconnect:ws://example.com/socket
Нюанс: autoreconnect: требует двух аргументов. Вариант с одним, который ходит по подборкам, падает: Specify ws:// or wss:// URI to connect to a websocket. Первым аргументом идёт источник данных — - для stdin или tcp-l: для туннеля. Проверил разрыв: поднял клиент раньше сервера, в логе Reconnecting failed, процесс жив. Сервер появился — соединение поднялось само. Отправить одно сообщение и выйти

echo "get_metrics" | websocat -1 ws://example.com/socket
Отправляет ровно один фрейм из stdin и закрывает сессию. Удобно дёргать из скрипта. Локальный эхо-сервер вернул get_metrics и завершился с кодом 0. Пробить туннель на тестовый сервер с самоподписанным TLS

websocat -k wss://staging.example.com/socket
Флаг -k отключает проверку сертификата. Для стенда годится, дальше стенда — нет: MITM на таком туннеле не отличить от обычной работы. Из полезного при отладке: websocat -t ws-l:127.0.0.1:1234 mirror: поднимает локальный эхо-сервер, на котором можно проверить свою команду, не выходя наружу. Честный минус — синтаксис. Аргументы это цепочки специферов вида overlay:addrtype:address, и с непривычки половина попыток заканчивается Invalid command-line parameters. Плюс инкапсуляция в кадры съедает скорость, а на больших объёмах приходится крутить -B вручную. А чем вы пробиваете туннель, когда наружу открыт только 443? #Linux #websocat #Networking #Tunneling #DevOps

🎥 Вебинар: «Nftables без потери SSH: безопасно настраиваем firewall на удаленном сервере» На открытом уроке разберем, как на
🎥 Вебинар: «Nftables без потери SSH: безопасно настраиваем firewall на удаленном сервере» На открытом уроке разберем, как настроить сетевую фильтрацию на удаленном Linux-сервере и не потерять доступ по SSH. Рассмотрим основные принципы работы nftables, его отличия от привычного iptables, совместимость инструментов и подход к постепенному переходу на новую систему фильтрации трафика. О чем поговорим: — Почему nftables приходит на смену iptables — Как устроена фильтрация сетевого трафика в nf_tables — Как составлять и применять базовые правила firewall — Как менять настройки на удаленном сервере, не потеряв доступ по SSH — Что учитывать при совместимости и переходе с iptables на nftables 🧠 Вебинар приурочен к старту курса «Администратор Linux. Продвинутый уровень». Программа постоянно обновляется с учётом современных требований рынка. Занятия проводят практикующие эксперты, которые ежедневно работают с производственной инфраструктурой. Вы изучите востребованные инструменты: Zabbix, Prometheus, Docker, Nginx, PostgreSQL, ELK, Ansible, SELinux, Bash и многие другие. 👉 Для участия зарегистрируйтесь https://otus.pw/eQjk/ Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru

Закрыть системные файлы от правки и не получить молча сломанный useradd Запретить правку файла даже руту

chattr +i /etc/passwd
Нюанс: useradd после этого выдаёт cannot open /etc/passwd и завершается с кодом 0. Пользователь не создаётся, скрипт не падает, мониторинг молчит. Снял атрибут — создался. Разрешить логу только дозапись

chattr +a /var/log/secure
Нюанс: ротация делается переименованием, а его атрибут не пускает. Запустил logrotate на таком файле:

error: failed to rename: Operation not permitted
rc=0
Снова ноль на выходе. Файл не ротировался, cron считает, что всё прошло, логи растут до конца места. Найти файлы с SUID и SGID

find / -xdev -perm /6000 -type f -ls 2>/dev/null
Нюанс: без -xdev поиск по корню вернул ноль файлов и код 1 — захлебнулся на /proc. С ним нашлось 16 штук. Пустой вывод легко принять за чистую систему. Старый синтаксис +6000 GNU find уже не понимает, отвечает invalid mode. Выдать права одному пользователю

setfacl -m u:lisa:rw file
setfacl -b file
Единственное место без подвоха. После первой команды в ls -l появляется плюс: -rw-rw-r--+, после сброса исчезает — по нему и замечают ACL. Поставить наблюдение за файлом

auditctl -w /etc/passwd -p wa -k pwd_change
Нюанс: правило живёт до перезапуска auditd. Постоянные пишутся в /etc/audit/rules.d/audit.rules. Закрыть входящий трафик, оставшись в сессии

iptables -A INPUT -m conntrack \
  --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -P INPUT DROP
Порядок именно такой: политика последней. iptables -P INPUT DROP первой командой на удалённом сервере обрывает соединение сразу. И два уточнения: -m state до сих пор принимается, но актуален -m conntrack --ctstate, а iptables -V на 24.04 отвечает v1.8.10 (nf_tables) — правила уезжают в nftables. У двух худших находок общее одно: команда не сработала, а код возврата ноль. Мониторингом такое не ловится. А вы chattr +i на боевых конфигах ставите или считаете это ловушкой для самого себя? #Linux #Security #Hardening #iptables #DevOps

Посмотреть, какие интерфейсы подняты, и не принять погасший порт за живой Краткий статус интерфейсов

ip -4 -br address show up
Нюанс: up фильтрует по состоянию линка, а не по наличию адреса. Погасил eth0 — с ключом он пропал из вывода совсем, без ключа виден как DOWN со всеми адресами на месте. Пустая строка тут не значит «адреса нет». Второй адрес без алиасов вида eth0:1

ip address add 10.0.0.50/24 dev eth0
ip address del 10.0.0.50/24 dev eth0
Второй адрес встаёт рядом с первым, при удалении линк не дёргается. Узнать, куда реально пойдёт пакет

ip route get 8.8.8.8
# 8.8.8.8 via 192.0.2.1 dev eth0 src 192.0.2.2
Не читает таблицу, а спрашивает у ядра готовое решение вместе с исходящим адресом. Для локального ответит local 192.0.2.2 dev lo. Увидеть все таблицы маршрутизации

ip route show table all
Обычный show дал одну строку, table all — шесть, включая local с broadcast и host-маршрутами. С VPN и контейнерами разница уходит в десятки строк. Посмотреть, кто есть в сети рядом

ip -4 neigh show
ip -6 neigh show
Нюанс: ip neigh — не ARP-таблица, как пишут в шпаргалках, а таблица соседей: ARP плюс IPv6 NDP. Без ключа -4 или -6 получишь обе вперемешку. arp -n показывал только первую, отсюда и путаница. Сбросить кэш соседей

ip -s -s neigh flush dev eth0
Нюанс: без -s -s команда молчит и отдаёт код 0 — не отличишь «очистил десять записей» от «там было пусто». С ключом печатает удалённые записи и итог *** Round 1, deleting 1 entries ***. Дать интерфейсу второе имя без даунтайма

ip link property add dev eth0 altname eno2
altname eno2 появляется в ip link show eth0, и по новому имени интерфейс находится: ip address show dev eno2 отдаёт eth0. Есть с ядра 5.8 и iproute2 5.8, на RHEL 7 синтаксис не разберётся. Всё, что пишет, требует CAP_NET_ADMIN — в контейнере без --cap-add=NET_ADMIN упадёт. А вы ip route get в отладке применяете или сразу лезете в show? #Linux #iproute2 #Networking #DevOps #Debug

Ходовой набор для отладки bash-скрипта известен всем: set -euo pipefail сверху, set -x вокруг мутного места и ловушка DEBUG с read, чтобы останавливаться перед каждой командой. Прогнал этот набор на Ubuntu 24.04, bash 5.2. Три вещи из него ведут себя не так, как ожидаешь. Сначала то, что работает без оговорок:

# падаем на ошибке, пустой переменной и в пайпах
set -euo pipefail
pipefail не декорация: false | true без него даёт код 0, с ним 1. А set -u ловит то, до чего не доберётся проверка синтаксиса:

echo "путь: /${UNSET_VAR}/data"
# bash: UNSET_VAR: unbound variable
Но `set -e` замолкает в условиях. Вызвал функцию через if — код возврата внутри перестал что-либо значить:

check() { false; echo "функция продолжила"; }
if check; then :; fi
# echo выполнился, rc=0
Трассировка. Обычно пишут просто set -x, но дефолтный PS4 печатает голый плюс — в скрипте на 300 строк не поймёшь, где ты:

PS4='+ ${BASH_SOURCE}:${LINENO}: '
set -x
do_something_risky
set +x
Теперь в каждой строке трассировки видно файл и номер:

+ g.sh:4: mkdir -p /tmp/zz
Пошаговый режим. Типовой рецепт — функция с read и ловушка DEBUG:

dbg() { read -p "$BASH_SOURCE:$LINENO? " _; }
trap 'dbg' DEBUG
В нём три поломки, и каждая тихая. Первая: $LINENO и $BASH_SOURCE внутри функции указывают на саму функцию. На всех командах печаталось line=3 — строка, где стоит read. Реальные 6 и 7 не появились ни разу. Координаты надо передавать аргументами:

dbg() { read -r -p "[$1:$2] $3? " _; }
trap 'dbg "$BASH_SOURCE" "$LINENO" "$BASH_COMMAND"' DEBUG
Вторая: ловушка не заходит внутрь функций. Без set -T виден только вызов work, а команды в её теле пропадают — как раз там, где обычно и прячется баг.

set -T
Третья самая злая. read в ловушке читает тот же stdin, что и скрипт. Подал в цикл три строки — дошла одна:

printf 'alpha\nbeta\ngamma\n' | bash f.sh
получил: beta
Две строки съела отладка — отладчик изменил поведение отлаживаемого. Плюс при неинтерактивном stdin приглашение read -p не печатается вовсе, и скрипт молча проносится мимо пауз. Лечится перенаправлением:

dbg() { read -r -p "$1? " _ < /dev/tty; }
С ним прошли все три строки, паузы работали даже при stdin из /dev/null. И про bash -n, который советуют как «проверку перед запуском». Он про синтаксис и только: незакрытый if поймал с кодом 2, а несуществующую команду и rm -rf /$UNSET_VAR/data пропустил с кодом 0. Прогонял на двух машинах, bash 5.2.21 и 5.2.37 — поведение одинаковое. А вы set -T вообще используете или обходитесь set -x? #Linux #Bash #Debug #DevOps #Автоматизация

🎥 Вебинар: Почему сервер тормозит: первая диагностика Linux для начинающего администратора На открытом уроке разберем, как о
🎥 Вебинар: Почему сервер тормозит: первая диагностика Linux для начинающего администратора На открытом уроке разберем, как определить, из-за чего Linux-сервер начал работать медленнее: процессор, оперативная память, дисковая подсистема или отдельный процесс. Познакомимся с базовыми инструментами мониторинга и посмотрим примеры диагностики проблем производительности. О чем поговорим: — Какие ресурсы сервера чаще всего становятся причиной снижения производительности — Как оценивать состояние системы с помощью top, htop, iotop, sysstat и vmstat — На какие показатели обращать внимание при первичной диагностике — Как последовательно искать источник нагрузки — Примеры разбора типовых проблем на Linux-сервере 🧠 Вебинар приурочен к старту курса «Администратор Linux. Базовый уровень». Вы освоите Bash, TCP/IP, Nginx, Apache, MySQL, Docker, Git, Prometheus, Grafana и ELK. На живых занятиях с практикующими экспертами научитесь настраивать веб-серверы, работать с сетью, контейнерами, мониторингом и фильтрацией трафика. 👉 Для участия зарегистрируйтесь https://otus.pw/D2in/ Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru

Попалась заметка про reptyr — утилиту, которая забирает уже запущенный процесс в новую сессию терминала. Команды из ходовых инструкций прогнал сам, на двух машинах с Ubuntu 24.04. Ситуация: запустил в ssh дамп базы, а он затянулся. Надо было сразу в tmux, но уже поздно. Сначала отвязываем процесс от текущей оболочки:
# Ctrl-Z, потом
bg
jobs -l
disown %1
Вот тут первая шероховатость. В инструкциях пишут disown top, по имени команды. Оно работает, но ровно пока такой job один. Проверил: один sleep снимается нормально, два — ambiguous job spec и выход с кодом 1. Пиши %1 или PID, не имя. Дальше открываем новую сессию в tmux и забираем процесс:
# PID берём из вывода jobs -l
reptyr 7972
Работает. Прогнал на top из одной tmux-сессии в другую: нулевой дескриптор сменился с /dev/pts/0 на /dev/pts/2, вывод продолжился в новом окне. При этом reptyr напечатал [-] Timed out waiting for child stop. — и всё равно перенёс. Причём это вылезло на обеих машинах и на разных версиях, так что предупреждение можно игнорировать. А вот чего в инструкциях обычно нет. По умолчанию в Debian и Ubuntu kernel.yama.ptrace_scope равен 1: подцепиться можно только к своему потомку. Процесс из старой ssh-сессии новой оболочке не потомок. Запустил от обычного пользователя — получил отказ:
Unable to attach to pid 2162:
  Operation not permitted
Дальше reptyr сам подсказывает посмотреть ptrace_scope — за это спасибо автору. Лечится так:
cat /proc/sys/kernel/yama/ptrace_scope

# 0 — классические правила ptrace
sysctl -w kernel.yama.ptrace_scope=0
С нулём тот же скрипт перенёс процесс на /dev/pts/5. Но это ослабление защиты: любой процесс под тем же uid сможет подцепиться к любому другому. Держать так постоянно на боевой машине я бы не стал. Под root, кстати, всё работает и при единице — CAP_SYS_PTRACE обходит yama. Есть флаг -T: крадёт весь терминальный сеанс и по описанию должен выручать, когда у процесса есть дети. Взял конвейер sleep 400 | cat, натравил reptyr -T — и ничего. Ни ошибки, ни переноса: лог пустой, tty прежний. В чём подвох, не разобрался. И про версии. На одной машине приехал reptyr 0.9.0-1, на другой при той же Ubuntu 24.04 — 0.8.0. Флаги в обеих одинаковые, но длинных опций нет ни там, ни там: reptyr --help отвечает invalid option. А вы reptyr вообще применяли в бою или проще перезапустить и не рисковать? #Linux #Bash #tmux #reptyr #DevOps

Чек-лист как проверить софт из чужой подборки На Хабре попалась подборка «Стек российского сисадмина в 2026». Идея хорошая, а вот что с ней делать дальше — вопрос. Такие списки выходят каждый год, и половина позиций в них кочует по инерции. Автор списал у прошлогоднего автора, а проект уже год как не двигается или тихо переехал на несвободную лицензию. Вот шесть проверок, которые снимают вопрос за десять минут. До того, как ты выкатишь это в прод. 1. Паспорт репозитория

R=zabbix/zabbix
curl -s "https://api.github.com/repos/$R" \
  | jq '{pushed_at, archived, license: .license.spdx_id}'
Три поля решают почти всё. archived: true — проект заморожен официально, дальше можно не смотреть. 2. Сколько на самом деле прошло с последнего пуша

P=$(curl -s "https://api.github.com/repos/$R" \
     | jq -r .pushed_at)
echo $(( ($(date +%s) - $(date -d "$P" +%s)) / 86400 ))
Глазами дату читать бесполезно — «2024-03-11» не выглядит страшно, пока не увидишь рядом число 881. 3. Bus factor

S=$(date -u -d '90 days ago' +%Y-%m-%d)
curl -s "https://api.github.com/repos/$R/commits\
?since=$S&per_page=100" \
  | jq -r '[.[] | (.author.login // "?")]
      | group_by(.) | map("\(length) \(.[0])") | .[]' \
  | sort -rn | head -5
Если весь список — один ник, проект держится на одном человеке. Это не приговор, но знать надо заранее, а не когда он выгорит. Тут спрятаны грабли, на которые я сам наступил. Без скобок вокруг .author.login // "?" конвейер молча теряет коммиты, у которых автор не привязан к аккаунту GitHub. На макете из пяти коммитов jq вернул четыре. Оператор `//` в jq применяется ко всему потоку, а не к каждому элементу — скобки обязательны. 4. Лицензия В первом же запросе смотри на spdx_id. Значение NOASSERTION означает, что GitHub не смог сопоставить файл лицензии ни с одной стандартной. Чаще всего это BSL, SSPL или самописный текст с ограничениями на коммерческое использование. Открывай LICENSE руками. 5. Есть ли пакет в репах твоего дистрибутива

for p in netdata zabbix-server-pgsql; do
  v=$(apt-cache madison "$p" 2>/dev/null | head -1)
  printf '%-22s %s\n' "$p" "${v:-НЕТ В РЕПАХ}"
done
Проверял на Ubuntu 24.04: netdata нашёлся в noble/universe, zabbix-server-pgsql — нет, ставить придётся из репозитория вендора. Отдельная засада: apt-cache madison и apt-cache policy возвращают код 0, даже когда пакета не существует, просто печатают пустоту. Конструкция apt-cache policy X || echo "нет" не сработает никогда — проверяй пустоту переменной, как выше. 6. Помни про лимит Анонимно GitHub API даёт 60 запросов в час на IP, и на общем адресе они кончаются мгновенно — я на этом словил 403 посреди проверки. С персональным токеном лимит 5000:

curl -s -H "Authorization: Bearer $GH_TOKEN" \
  https://api.github.com/rate_limit | jq .rate
Честный минус метода: API показывает активность, а не качество. Проект может коммитить каждый день и при этом быть непригодным, а может годами лежать без изменений, потому что он просто дописан. Так что это фильтр первого уровня, а не вердикт. #Linux #DevOps #GitHub #jq #Чеклист

🔬 Дали root и разрешили ломать. Сервис, который я хотел создать Постоянные читатели знают, что у меня есть бот @gradeliftbot, в котором больше 200 задач по Linux. Работает он просто: кусок лога и вопрос по нему. Песочницы нет вообще. Всё скатывается в механику заданий вопрос-ответ. Кейсы генерит нейросеть, и местами это заметно, хотя там содержится достаточно много материала, чего стоит только полный гайд от Docker на 1195 страниц и 8500 страниц с командами Linux и их подробным описанием. Изначально идея была создать песочницу с заданиями, где нужно было выполнять задания, но я так и не смог придумать, как адаптировать её под мобильный формат Telegram-бота. Поэтому получилась очень упрощённая версия от изначальной идеи. На днях наткнулся на izzylab.ru — тренажёр по Linux и DevOps, где терминал живёт прямо в браузере. Открыл первую задачу «создай пользователя john» и вместо useradd набрал разведку. Интереснее было понять, куда меня пустили и насколько там можно наглеть. uname -r; nproc; free -m | head -2 id; sudo -n true; echo $? 4.19.0-gvisor, 2 ядра, 256 МБ, uid=0. Под тобой не хост и не виртуалка, а gVisor — юзерспейсное ядро от Google, которое перехватывает системные вызовы и разбирает их само. Отсюда и щедрость: тебе спокойно дают root и разрешают крушить систему, потому что до настоящего ядра ты всё равно не дотянешься. У каждой задачи свой контейнер, сброс откатывает всё начисто. Больше всего я боялся увидеть чекер, который сверяет введённую строку с эталоном. Проверил в лоб. Задание «закодируй /root/data.bin в base64» решил не той утилитой: openssl base64 -A -in /root/data.bin \ -out /root/data.b64 Засчитано, хотя штатный base64 ломает вывод каждые 76 символов, а openssl -A пишет одной строкой. Проверка смотрит на результат, а не на способ. Обмануть тоже не вышло: подложил валидный base64 от постороннего текста — поймал и написал, какой критерий не сошёлся, решение при этом не выдал. На момент, когда я смотрел сервис, уже было 437 заданий, что значительно больше чем в @gradeliftbot. 87 лёгких, 276 средних, 74 сложных. Разбивка не самая ожидаемая — Git 39, регулярки 30, скрипты 29, SQLite 25, Kubernetes 20, диагностика 20. Redis и Postgres поднимаются руками и отвечают, apt install работает, сеть наружу есть. А дальше пошли находки, ради которых стоило лезть. ss -s возвращает get_sockstat: No such file or directory, при этом ip -br a работает нормально. Причина в netlink: gVisor держит NETLINK_ROUTE, но не NETLINK_SOCK_DIAG, на котором стоит ss. Я сам писал «netstat мёртв, бери ss» — вот вам среда, где канон переворачивается. Со strace то же самое, только тоньше. Запуск программы под трейсом работает, а attach к чужому PID — нет: ptrace(PTRACE_SEIZE, 261): Operation not permitted PTRACE_TRACEME есть, PTRACE_SEIZE нет. Ещё ping даёт 100% потерь, а curl https://ya.ru возвращает 302 — ICMP не проброшен, TCP ходит. Я такие штуки люблю: за час разведки узнал про gVisor больше, чем за все статьи о нём. Теперь честно. Если вы хотите просто научиться внимательно читать логи, что важно на собесах или когда за кем-то исправляешь ошибки, тогда подходит @gradeliftbot. А если цель — именно практика в живом терминале, то формат izzylab.ru на мой взгляд, подходит лучше. Что скажете насчёт идеи живой песочницы в браузере телефона? Тут в MAX ботов разрешили создавать самозанятым, можно будет попробовать перенести бота из телеги в MAX. #Linux #DevOps #gVisor #strace #Практика

🎥 Вебинар: Kubernetes + CI/CD + GitOps — делаем стабильный деплой без выхода из кластера 📌 На уроке вы узнаете: - Как настр
🎥 Вебинар: Kubernetes + CI/CD + GitOps — делаем стабильный деплой без выхода из кластера 📌 На уроке вы узнаете: - Как настроить конвейер CI/CD для автоматизации развертывания приложений в Kubernetes. - Что такое GitOps, и как с его помощью управлять инфраструктурой и релизами через декларативные манифесты. - Использование Kubernetes для построения стабильных и безопасных процессов развёртывания приложений. - Лучшие практики внедрения, внедрения и управления изменениями прямо из кластера. 🎯 После вебинара вы: - Вы поймёте, как интегрировать Kubernetes, CI/CD и GitOps для создания стабильных и автоматизированных процессов развертывания. - Освоите изменение и оптимизацию конвейеров CI/CD для работы в Kubernetes-кластерах. - Изучите подходы к мониторингу, организации тестирования и управлению релизами через GitOps, повышению доступности и безопасности процессов. ⚠️ Открытый урок проходит в преддверии старта курса «Инфраструктурная платформа на основе Kubernetes». 👉 Для участия зарегистрируйтесь: https://vk.cc/d0aUej Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru