Bash Days | Linux | DevOps
Авторский блог от действующего девопса Самобытно про разработку, devops, linux, скрипты, сисадминство, техдирство и за айтишную жизу. Автор: Роман Шубин Реклама: @maxgrue MAX: https://max.ru/bashdays Курс: @tormozilla_bot Блог: https://bashdays.ru
Ko'proq ko'rsatish📈 Telegram kanali Bash Days | Linux | DevOps analitikasi
Bash Days | Linux | DevOps (@bashdays) Rus til segmentidagi kanali faol ishtirokchi. Hozirda hamjamiyat 23 806 obunachidan iborat bo'lib, Texnologiyalar & Aralashmalar toifasida 5 710-o'rinni va Rossiya mintaqasida 28 118-o'rinni egallagan.
📊 Auditoriya ko‘rsatkichlari va dinamika
невідомо sanasidan buyon loyiha tez o‘sib, 23 806 obunachiga ega bo‘ldi.
15 Iyun, 2026 dagi oxirgi ma’lumotlarga ko‘ra kanal barqaror faollikka ega. Oxirgi 30 kunda obunachilar soni -195 ga, so‘nggi 24 soatda esa -10 ga o‘zgardi va umumiy qamrov yuqori darajada qolmoqda.
- Tasdiqlash holati: Tasdiqlanmagan
- Jalb etish (ER): Auditoriya o‘rtacha 23.79% darajada jalb etiladi. Nashrdan keyingi dastlabki 24 soatda kontent odatda umumiy obunachilar sonining 11.52% ini tashkil etuvchi reaksiyalarni to‘playdi.
- Post qamrovi: Har bir post o‘rtacha 5 664 marta ko‘riladi; birinchi sutkada odatda 2 744 ta ko‘rish yig‘iladi.
- Reaksiyalar va o‘zaro ta’sir: Auditoriya faol: har bir postga o‘rtacha 25 ta reaksiya keladi.
- Tematik yo‘nalishlar: Kontent bashdays, linux, bash, docker, скрипт kabi asosiy mavzularga jamlangan.
📝 Tavsif va kontent siyosati
Muallif resursni shaxsiy fikrni ifoda etish maydoni sifatida ta’riflaydi:
“Авторский блог от действующего девопса
Самобытно про разработку, devops, linux, скрипты, сисадминство, техдирство и за айтишную жизу.
Автор: Роман Шубин
Реклама: @maxgrue
MAX: https://max.ru/bashdays
Курс: @tormozilla_bot
Блог: https://bashdays.r...”
Yuqori yangilanish chastotasi (oxirgi ma’lumot 16 Iyun, 2026 da olingan) sababli kanal doimo dolzarb va katta qamrovli bo‘lib qoladi. Analitika auditoriya kontent bilan faol hamkorlik qilishini, uni Texnologiyalar & Aralashmalar toifasidagi muhim ta’sir nuqtasiga aylantirishini ko‘rsatadi.
\usepackage{longtable}\setlength{\LTleft}{2em}
\setmainfont{Liberation Serif}
\setsansfont{Liberation Sans}
\setmonofont{Liberation Mono}
\newfontfamily\cyrillicfont{Liberation Sans}
\defaultfontfeatures{Scale=MatchLowercase, Mapping=tex-text}
\usepackage{polyglossia}
\setmainlanguage{russian}
\setotherlanguage{english}
4. Нет возможности печатать некоторые символы UTF.
5. некоторые символы приходится маскировать, чтобы они не понимались, как управляющие.
Единственный плюс - подсветка синтаксиса bash.
В общем, после 19 главы я понял, что моего терпения не хватит закончить работу. Вернулся к libreoffice. За два дня освоил работу со стилями, и все пошло как по маслу. Кстати, экспорт в pdf тоже быстрее, на мой взгляд.
Может и не все получилось, сами знаете - первый блин комом.
Замечания и комментарии приветствуются.
С результатом можно ознакомиться здесь 👇
🅰️🅰️
➡️ https://github.com/tagd-tagd/self-instruction
🅰️🅰️
🛠 #bash #linux #utilites #markdown
—
✅ @bashdays / @linuxfactory / @blogsystemd на кирпичики. Сегодня про кандишены (условия/ситуации).
ㅤ
Директива ConditionPathExists используется в юнит-файлах systemd и позволяет задать условие для запуска юнита: он будет запущен только если указанный файл или директория существует.
Пример:
[Unit]
Description=Special Service
ConditionPathExists=/etc/bashdays-config
[Service]
ExecStart=/usr/local/bin/bashdays-handler
Этот юнит не запустится, если файл /etc/bashdays-config не существует. В статусе сервиса ты увидишь:
ConditionPathExists=/etc/bashdays-config was not met
Если путь НЕ существует, systemd не будет запускать юнит. Вместо этого он будет считаться пропущенным (skipped), а не проваленным.
Нахуя это надо?
1. Например, если bashdays-config существует, запускается сервис с особым поведением.
2. Можно создавать один юнит, который активируется только при наличии определённого модуля или плагина.
3. Иногда это используют в early boot-юнитах, чтобы запускать их только если что-то доступно (например, том LUKS).
Список основных Condition's (нажми на спойлер)
ConditionPathExists — файл или каталог существует ConditionPathIsDirectory — путь существует и это каталог ConditionPathIsMountPoint — путь является точкой монтирования ConditionFileIsExecutable — файл существует и он исполняемый ConditionKernelCommandLine — есть ли параметр ядра с указанным значением ConditionPathExistsGlob — совпадает ли хотя бы один путь по glob-шаблону ConditionPathIsSymbolicLink — является ли путь символической ссылкой ConditionFileNotEmpty — существует ли файл и не пуст ли он ConditionEnvironment — установлена ли переменная окружения ConditionArchitecture — архитектура CPU (например, x86_64, aarch64) ConditionVirtualization — nип виртуализации (например, kvm, docker) ConditionHost — имя хоста ConditionMachineID — cовпадает ли machine-id ConditionControlGroupController — есть ли указанный cgroup controller (например, cpu, memory) ConditionNeedsUpdate — нуждается ли в обновлении (/usr или /etc) ConditionFirstBoot — Первый ли это запуск после установки ConditionACPower — Подключено ли питание от сети (для ноутбуков) ConditionSecurity — Активен ли определённый LSM (например, selinux) ConditionUser — Запускается ли от указанного пользователя ConditionGroup — Запускается ли от указанной группы ConditionCapability — Имеет ли процесс определённую capability ConditionNetwork — Есть ли сеть (online, configured) ConditionMemory — Есть ли минимум указанного объёма памятиДополнительно Если заменить
Condition на Assert, условие не выполнено — юнит считается проваленным, а не пропущенным.
То есть берем к примеру директиву ConditionPathExists и меняем её на AssertPathExists.
AssertPathExists=/etc/bashdays.conf
И получается:
ConditionPathExists — юнит пропускается (не считается ошибкой)
AssertPathExists — юнит падает (считается ошибкой)
Assert полезен, когда ты строго требуешь, чтобы ресурс (например, внешний диск, NFS, или другой том) был смонтирован перед запуском сервиса. Если его нет — это ошибка, а не «ну и похуй».
[Unit]
Description=Start backup script only if /mnt/backup is mounted
AssertPathIsMountPoint=/mnt/backup
[Service]
ExecStart=/usr/local/bin/backup.sh
Если /mnt/backup не смонтирован, systemd выдаст ошибку, и сервис не запустится.
Статус будет такой:
systemd[1]: Starting backup.service...
systemd[1]: backup.service: Failed with result 'assert'.
Ну и все это дело можно комбинировать:
ConditionPathExists=/mnt/backup
AssertPathIsMountPoint=/mnt/backup
Если /mnt/backup не существует — юнит пропускается.
Если существует, но не смонтирован — юнит заваливается.
Короче systemd не такой уж простой, как кажется с первого взгляда. На нём можно прям заебись логику построить и получить желаемое. Так что недооценивать его явно не стоит, это прям заебись комбайн.
🛠 #linux #tricks #debug #systemd #bash
—
✅ @bashdays / @linuxfactory / @blogsystemd не обязательно обладать рутовскими правами или судой-мудой. Да, ты не ослышался, всё можно запускать под обычным юзером.
Делается это так:
systemctl --user enable bashdays.timer
Ключ --user означает, что команда применяется в пользовательском пространстве, а не на уровне всей системы.
ㅤ
Теперь этот юнит будет запускаться каждый раз при старте пользовательской сессии, а таймер начнет тикать.
Эта штука создаёт символическую ссылку в ~/.config/systemd/user/ в директории default.target.wants/
Если тебе нужно разово запустить такой юнит, то enable меняем на start. Вот и вся наука.
А как отлаживать?
➡️ 1. Сначала нужно убедиться что таймер активен:
systemctl --user status bashdays.timer
Если всё ок, то увидишь Active: active (waiting).
➡️ 2. Смотрим расписание запуска
systemctl --user list-timers
- NEXT — когда следующий запуск
- LEFT — сколько осталось времени
- LAST — когда запускался в прошлый раз
- UNIT — имя таймера
➡️ 3. Проверяем выполнялся ли сервис
journalctl --user-unit bashdays.service --since "1 hour ago"
Команда покажет логи выполнения скрипта. Можно сузить диапазон, например так:
journalctl --user-unit bashdays.service --since today
По дебагу это основное. Мелочи вроде синтаксических ошибок и т.п. рассматривать не будем, тут уже от кривизны рук все зависит.
Ну а так всё что нужно тебе знать. То есть у каждого пользователя могут быть свои юниты и сервисы, а не только у рута.
🛠 #linux #tricks #debug #systemd #bash
—
✅ @bashdays / @linuxfactory / @blogtimer, path и socket
Это невидимые юниты systemd, которые могут заменить cron, inotify`и даже `xinetd.
➡️ 1. Timer
Про timer ты наверняка слышал. Это альтернатива crontab. Позволяет запускать сервис по расписанию. Вместо того чтобы писать крон-джобы, ты создаёшь .service и .timer.
Пример:
/etc/systemd/system/backup.service
[Unit]
Description=Backup job
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/backup.sh
/etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
Активируем:
sudo systemctl enable --now backup.timer
Persistent=true гарантирует запуск пропущенной задачи, если система была выключена.
Всё! Никаких тебе легаси кронтабов, все работает на юнитах, запускается бэкапилка, тикает таймер.
➡️ 2. Path
Работает как inotifywait или File Watcher: следит за файлами/папками и запускает сервис при изменении.
Пример:
/etc/systemd/system/upload.path
[Unit]
Description=Watch upload folder
[Path]
PathModified=/var/www/bashdays/upload
Unit=process-upload.service
[Install]
WantedBy=multi-user.target
/etc/systemd/system/process-upload.service
[Unit]
Description=Process uploaded files
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/process-upload.sh
Теперь каждый раз когда в папке /var/www/bashdays/upload что-то меняется, автоматически запускается скрипт process-upload.sh.
Тут уже от твоих предпочтений зависит, как и с чем это скрещивать, но кейсов можно придумать довольно дохуя. Например, проверка антивирусом, или запуск какого-нибудь ffmpeg.➡️ 3. Socket Заменяет ручной
systemctl start, активируя сервис при первом подключении к сокету. Аналог inetd/xinetd
ㅤ
Нихуя не понятно, но на примере сейчас всё прояснится.
Пример:
/etc/systemd/system/echo.socket
[Unit]
Description=Echo socket
[Socket]
ListenStream=12345
Accept=yes
[Install]
WantedBy=sockets.target
/etc/systemd/system/echo@.service
[Unit]
Description=Echo service
[Service]
ExecStart=/usr/bin/nc -l -p 12345 -e /bin/cat
StandardInput=socket
В примере, сервис НЕ работает постоянно, он стартует, только когда кто-то подключается к порту 12345.
Когда ты используешь .socket с Accept=yes, systemd открывает сокет сам и ждёт подключения. А когда подключение приходит — создаёт новый экземпляр сервиса, подставляя туда данные об этом соединении. После завершения — сервис умирает. Всё очень экономно и прозрачно.
Как понять, какой экземпляр стартует?
systemd запускает echo@<ID>.service, где <ID> — уникальный идентификатор подключения (например, PID или номер сокета).
journalctl -u echo@*
Зачем нужны скрытые юниты?
1. Не нужен cron, всё централизовано в systemd.
2. Не нужен inotify-tools.
3. Сервисы не висят без дела, запускаются только когда нужно
4. Журналирование через journalctl
Вот такие пироги. В повседневной работе я применяю timer и path, с сокетами как-то сильно не приходилось париться.
Ну а ты попробуй хотя бы перетащить свои кронджобы в timer и порадоваться бест-практикам.
🛠 #linux #tricks #debug #systemd #bash
—
✅ @bashdays / @linuxfactory / @blog[Service]
Environment="FOO=bar"
ExecStart=/bin/bash /usr/local/sbin/bashdays.sh
Сделал юнит, но в скрипт bashdays.sh не передаётся переменная FOO. Хотя логически всё правильно.
Тут снова приколы.
➡️ 1. Скрипт запускается не напрямую, а через интерпретатор.
Если в ExecStart указан скрипт с shebang’ом (#!/bin/bash), systemd запускает его как отдельный процесс, и переменные окружения передаются.
ㅤ
Но если ты укажешь в ExecStart сам интерпретатор, вот так:
ExecStart=/bin/bash /usr/local/sbin/bashdays.sh
То переменная FOO, заданная через Environment=, не попадёт в подскрипт, потому что ExecStart запускает bash, а уже bash запускает — скрипт, и переменные окружения само собой нихуя не передаются.
Как правильно?
Вот так:
[Service]
Environment="FOO=bar"
ExecStart=/usr/local/sbin/bashdays.sh
А сам скрипт:
#!/bin/bash
echo "FOO is $FOO"
Всё! Теперь переменная из юнита будет корректно передаваться в скрипт.
➡️ 2. Использовать EnvironmentFile=
Если у тебя дохуя переменных, то выносим их в отдельный файл, например сюда /etc/bashdays-service.env.
FOO=bar
BAZ=qux
А в самом юните прописываем:
[Service]
EnvironmentFile=/etc/bashdays-service.env
ExecStart=/usr/local/sbin/bashdays.sh
Всё! Теперь переменные считываются из файла и скрипт их видит.
➡️ 3. Передавать переменные прямо в ExecStart
[Service]
ExecStart=/bin/bash -c 'FOO=bar exec /usr/local/sbin/bashdays.sh'
Тут особо и комментировать нечего, всё очевидно.
Как отладить и задебажить?
А вот так:
systemctl show nginx
Вместо nginx подставляешь свой сервис и наблюдаешь все переменные которые передались. В наших примерах увидишь Environment=FOO=bar.
Справедливо не только для собственных юнитов, но и для других, например для того же nginx или docker.
Как вариант, можешь добавить в скрипт такую хуйню:
env > /tmp/env.log
И смотришь, какие переменные реально передаются в твой скрипт.
Еще одна база выдана, вроде очевидные вещи, но так глубоко в это никто не лезет. Пользуйся.
🛠 #linux #tricks #debug #systemd #bash
—
✅ @bashdays / @linuxfactory / @blogsudo systemctl revert nginx
Эта команда отменяет все локальные изменения юнита nginx и возвращает его к состоянию по умолчанию, заданному в оригинальных unit-файлах, поставляемых системой или пакетом.
Короче достаточно прикольная штука, когда нахуевертил, но не знаешь как откатиться.
Команда удаляем override-файлы в:
/etc/systemd/system/nginx.service.d/
/etc/systemd/system/nginx.service
И следом будет использован оригинальный unit-файл, который обычно расположен в /lib/systemd/system/nginx.service.
Когда это полезно?
Если ты вносил изменения через systemctl edit, вручную правил nginx.service, или добавлял drop-in'ы — и хочешь откатиться к дефолтной конфигурации, revert делает это безопасно.
Наглядные примеры приводить не буду, думаю и так все понятно, что было и что будет.
Ну а ты носи в это в голове и никогда не бойся экспериментировать. Любой факап — твой опыт.
Предыдущие посты на тему systemd ищи по тегу #systemd🛠 #linux #tricks #debug #systemd — ✅ @bashdays / @linuxfactory / @blog
--runtime.
Ключ --runtime — создаёт временное переопределение, которое исчезнет после перезагрузки.Идеально подходит, если ты тестишь, не уверен или не хочешь ничего портить. А вот и сама команда:
SYSTEMD_EDITOR=vim systemctl edit --runtime nginx
Как ты мог заметить, зачастую по умолчанию открывается nano редактор, но у многих с ним проблемы. Поэтому в команде сразу втыкаем нужный редактор, например mcedit или vim.Всё! Теперь правим юнит, тестируем. Временный файл с
override будет создан тут /run/systemd/.
И самое главное — все изменения сохранятся только до следующей перезагрузки системы.
А какая в этом польза?
1. Для временного изменения конфигурации systemd без затрагивания оригинального файла.
2. Для тестов или отладки (например, сменить ExecStart для nginx только на время текущей сессии).
3. Чтобы не создавать перманентные изменения, которые могут повлиять на стабильность после перезагрузки.
Пример с nginx
Хочу временно запустить nginx с другим конфигом! Создаю рантайм.
[Service]
ExecStart=
ExecStart=/usr/sbin/nginx -c /home/user/nginx-bashdays.conf
Перезапускаю nginx и радуюсь результату, теперь nginx запущен с другим конфигом.
А почему ExecStart идет дважды?
Хе брат, это очередная приколюха systemd. Оно очищает предыдущее значение ExecStart из основного юнита. А следующая строка задаёт новое значение.
Без этой хуйни systemd бы просто добавил вторую команду, не заменив первую.
Думаю на этом можно закончить. Я неочевидную базу выдал, а ты стал еще сильнее. Изучай и ничего не бойся!
🛠 #linux #tricks #debug #systemd
—
✅ @bashdays / @linuxfactory / @blogЭто достаточно пиздатый хак, особенно при отладке медленного запуска системы. Ну и изобретать нам ничего не придется, всё уже придумали за нас.Запускаем и смотрим:
systemd-analyze blame
По итогу получаем список юнитов и их время запуска.
17.084s docker.service
10.961s systemd-journal-flush.service
7.595s containerd.service
7.496s cloud-final.service
7.189s cloud-init-local.service
3.260s apt-daily-upgrade.service
2.522s cloud-init.service
2.095s dpkg-db-backup.service
1.991s networkd-dispatcher.service
1.963s chrony.service
В моём примере дольше всего грузится служба с докером.
ㅤ
Отрубаем службу и радуемся приросту в 17 секунд. Но НЕТ! На самом деле тут всё немного сложнее.
Иногда сам юнит стартует достаточно быстро, но сука ждет другой юнит, который «Блиц — скорость без границ».
Смотрим цепочку зависимостей:
systemd-analyze critical-chain
└─docker.socket @13.269s +8ms
└─sysinit.target @13.261s
└─cloud-init.service @10.735s +2.522s
└─systemd-networkd-online.service @12.806s +31ms
└─systemd-networkd.service @12.741s +59ms
Ага, то есть дело тут не только в юните докера, юнит ждет другой юнит, в нашем случае докер ждет пока на сервере поднимется сетка.
То есть docker.service зависит от systemd-networkd-wait-online.service, ну и дальше пошли по цепочке.
Почему так?
Docker по умолчанию может иметь After=network-online.target, а при использовании systemd-networkd это приводит к ожиданию systemd-networkd-wait-online.service.
А чё делать?
sudo systemctl edit docker.service
[Unit]
After=network.target
Wants=network.target
Ну или вообще убрать After=network-online.target, если нет зависимости от сети на старте.
После этого снова смотрим выхлоп через blame:
4.739s cloud-init-local.service
4.041s containerd.service
2.329s dev-sda1.device
Всё блядь! Теперь докер не тормозит загрузку, но после загрузки системы докер исправно работает.
Вот такими хитрыми манипуляциями можно профилировать это говнище. Не скажу что часто этим пользуюсь, но всегда держу на вооружении.
Забирай в копилку, для дебага маст-хев!
🛠 #linux #tricks #debug #systemd
—
✅ @bashdays / @linuxfactory / @blogВ программе: 😶🌫️развертывание n8n в контейнере в облаке через сервис Evolution Container Apps; 😶🌫️пошаговая настройка интеграции Telegram-бота с искусственным интеллектом; 😶🌫️особенности и преимущества бессерверного подхода Cloud․ru Evolution.Вебинар будет полезен всем, кто хочет использовать облако для ускорения бизнес-процессов, создания новых сервисов и решения своих задач. Регистрируйтесь по ссылке🖱
/etc/systemd искать и править его.
Постоянно вижу этот кейс, чёто там ищут по папкам, ебутся. Правят оригинальный файл и все к хуям ломают.А бест-практика уже заложена в
systemctl!
Достаточно выполнить команду:
sudo systemctl edit nginx
Откроется редактор с нужным сервисом. НО, редактировать ты будешь не корневой юнит, а override. То есть прокладку, которая переопределит параметры основного юнита.
ㅤ
В моём случае с nginx будет открыт файл:
/etc/systemd/system/nginx.service.d/override.conf
В нем я переопределяю нужные параметры для сервиса и НЕ трогаю основной файл юнита.
А если я хочу править корневой?
Да похуй, вот тебе команда:
sudo systemctl edit --full nginx
Теперь будет открыт основной файл сервиса, можешь лезть в него своими шаловливыми ручонками и создавать проблемы.
1. Копирует оригинальный юнит-файл из /lib/systemd/system/nginx.service в /etc/systemd/system/nginx.service
2. Открывает его в редакторе.
3. После сохранения — systemd использует именно эту копию в /etc/.
Это безопасный способ редактировать полные юниты, без риска перезаписи при обновлении пакетов. Есть еще ключ --force, но про него погугли сам.Как проверить валидность файла юнита?
systemd-analyze verify /etc/systemd/system/nginx.service
В ответ получишь:
/etc/systemd/system/nginx.service:31: Missing '=', ignoring line.
Ага, ошибочка, правим и только после этого можно делать:
sudo systemctl daemon-reload
sudo systemctl restart nginx
Короче учись работать правильно и всё у тебя будет хорошо!
С пятницей! Хороших тебе предстоящих выходных и береги себя!
🛠 #linux #tricks #debug #systemd
—
✅ @bashdays / @linuxfactory / @blogУ меня раньше телеграм боты в heroku успешно крутились, потом эти письки закрыли бесплатный план и пришлось мигрировать.Принцип работы простой: 1. Пушишь свой код в git 2. Условный «Heroku» это видит через webhook 3. Забирает код и собирает 4. Запускает в изолированном контейнере 5. Маршрутизирует трафик в контейнер Чтобы развернуть всё это дело на своих серверах и никому не платить, можно воспользоваться двумя более-менее хорошими opensource проектами. ➡️ Dokploy и Coolify
Coolify более раскручен, но по сути те же яйца, только с боку.Как всё это дело ставить и запускать, рассказывать не буду. Вся документация есть в официальных гит репозиториях.
Да, можно поднять в докере и не ебать мозги.Но я предпочитаю всё же использовать k3s либо docker compose, потому что Dekploy и Coolify ты вряд ли встретишь в компаниях, они более нишевые. Подойдут для самохостинга и для тех, кому насрать на девопс. А вот если тебе не насрать на девопс, старайся хоть раз в день работать с кубом, манифестами и контейнерами и будешь всегда в рынке.
По себе знаю, если я сделаю паузу в кубе хотя бы на недельку-другую, всё, пезда, начинается деградация, а это уже звоночек.Короче интересные проекты я тебе принес, а дальше тебе самому решать, как этой информацией правильно воспользоваться. Изучай. 🛠 #selfhosting — ✅ @bashdays / @linuxfactory / @blog
Endi mavjud! Telegram Tadqiqoti 2025 — yilning asosiy insaytlari 

