15%

Збережіть 15% на всі хостинг-послуги

Перевірте свої навички і отримайте Знижку на будь-який план хостингу

Використовуй код:

Skills
Почати
10.11.2023

Як увімкнути автозавантаження скриптів в Ubuntu: три готових до використання методи

Увімкнення автозавантаження скриптів в Ubuntu означає налаштування операційної системи для автоматичного виконання одного або кількох shell-скриптів чи сервісів під час запуску системи, без будь-якого ручного втручання. Це досягається за допомогою трьох основних механізмів: застарілого каталогу /etc/init.d/ на основі SysVinit, сумісного шару /etc/rc.local та сучасного фреймворку сервісних юнітів systemd — останній є авторитетним, рекомендованим підходом у всіх випусках Ubuntu починаючи з 15.04.

Для системних адміністраторів, які запускають робочі навантаження в середовищі VPS Хостингу, автоматизація запуску — це не зручність, а вимога надійності. Неправильно налаштований або відсутній запис автозапуску означає, що критичні демони, агенти моніторингу, скрипти резервного копіювання або користувацькі мережеві конфігурації мовчки не запускаються після перезавантаження, спричиняючи перебої в роботі сервісів, які важко діагностувати після факту.

Чому автоматизація скриптів запуску важлива на серверах Ubuntu

Кожен виробничий сервер Ubuntu з часом накопичує операційні скрипти: процедури попереднього прогріву бази даних, тригери ротації логів, ініціалізатори VPN-тунелів, завантажувачі правил брандмауера та перевірки стану застосунків. Без структурованого механізму автозавантаження ці скрипти повністю залежать від ручного виконання — один пропущений крок після оновлення ядра або аварійного перезавантаження може призвести до простою.

Екосистема автоматизації запуску Ubuntu значно еволюціонувала:

  • SysVinit (до Ubuntu 15.04): Послідовний, повільний, на основі скриптів. Кожен сервіс блокував наступний.
  • Upstart (Ubuntu 6.10–15.04): Подієво-орієнтований, швидший, але тепер застарілий.
  • systemd (Ubuntu 15.04+): Паралельна активація сервісів, графи залежностей, активація сокетів, контроль ресурсів на основі cgroup та структуроване журналювання через journald.

Розуміння того, з яким рівнем ви працюєте — і чому — запобігає розгортанню робочого рішення в тестовому середовищі, яке мовчки ламається у виробництві.

Метод 1: Використання каталогу /etc/init.d/ (SysVinit / LSB-скрипти)

Як це працює

Каталог /etc/init.d/ є традиційним місцем для init-скриптів Linux Standard Base (LSB). Кожен скрипт у цьому каталозі є shell-скриптом, який відповідає на стандартизовані команди: start, stop, restart, status та опціонально reload. Утиліта update-rc.d створює символічні посилання в каталогах рівнів запуску /etc/rcN.d/, визначаючи коли і в якому порядку скрипт виконується під час послідовностей завантаження та вимкнення.

На сучасних системах Ubuntu, що працюють на systemd, ці скрипти все ще підтримуються через рівень сумісності під назвою systemd-sysv-generator, який автоматично перетворює LSB init-скрипти на тимчасові юніти systemd. Це означає, що ваші скрипти /etc/init.d/ все одно запускатимуться, але вони обгортаються systemd, а не виконуються безпосередньо SysVinit.

Покрокова реалізація

Крок 1: Створіть свій скрипт

Напишіть свій скрипт і переконайтеся, що він відповідає угоді заголовків LSB. Мінімальний, безпечний для виробництва приклад:

#!/bin/bash
### BEGIN INIT INFO
# Provides:          examplescript
# Required-Start:    $remote_fs $syslog $network
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Example autoload script
# Description:       Runs a custom initialization task at boot
### END INIT INFO

case "$1" in
  start)
    echo "Starting examplescript..."
    /usr/local/bin/examplescript.sh &
    ;;
  stop)
    echo "Stopping examplescript..."
    pkill -f examplescript.sh
    ;;
  restart)
    $0 stop
    $0 start
    ;;
  status)
    pgrep -f examplescript.sh > /dev/null && echo "Running" || echo "Stopped"
    ;;
  *)
    echo "Usage: $0 {start|stop|restart|status}"
    exit 1
    ;;
esac
exit 0

Крок 2: Розмістіть скрипт у /etc/init.d/

sudo cp examplescript /etc/init.d/examplescript

Крок 3: Зробіть його виконуваним

sudo chmod +x /etc/init.d/examplescript

Крок 4: Зареєструйте його в системі рівнів запуску

sudo update-rc.d examplescript defaults

Аргумент defaults реєструє скрипт для запуску на рівнях запуску 2, 3, 4 та 5, і зупинки на рівнях запуску 0, 1 та 6 — стандартна поведінка для більшості серверних демонів.

Крок 5: Перевірте реєстрацію

ls -la /etc/rc2.d/ | grep examplescript

Ви повинні побачити символічне посилання S01examplescript, що вказує назад на /etc/init.d/examplescript.

Критична помилка

Найпоширенішою помилкою з цим методом є пропуск блоку заголовка LSB. Без нього update-rc.d не може визначити порядок залежностей, і systemd-sysv-generator може призначити неправильний порядок виконання відносно доступності мережі або монтування файлових систем. Завжди явно визначайте залежності Required-Start.

Щоб видалити скрипт з автозапуску без його видалення:

sudo update-rc.d examplescript disable

Щоб повністю видалити його:

sudo update-rc.d examplescript remove

Метод 2: Використання /etc/rc.local (сумісний шар)

Як це працює

/etc/rc.local — це застарілий механізм, який виконує shell-скрипт один раз, після того як усі стандартні сервіси багатокористувацького рівня запуску стартували. Це найпростіший можливий метод автозапуску — без управління сервісами, без оголошень залежностей, без логіки перезапуску. На Ubuntu 18.04 та пізніших версіях підтримка rc.local забезпечується юнітом systemd rc-local.service, який вимкнений за замовчуванням і повинен бути явно увімкнений.

Коли використовувати

Використовуйте /etc/rc.local лише для:

  • Одноразових команд ініціалізації, які не потребують управління як сервіси
  • Швидкого прототипування або тестування перед формалізацією юніту systemd
  • Простого експорту змінних середовища або налаштування параметрів ядра

Не використовуйте /etc/rc.local для тривалих демонів. Оскільки він працює в блокуючому, послідовному режимі без нагляду за процесами, зависла команда в rc.local затримає або перешкодить завершенню послідовності завантаження.

Покрокова реалізація

Крок 1: Перевірте, чи існує /etc/rc.local

ls -la /etc/rc.local

Якщо він не існує, створіть його:

sudo bash -c 'cat > /etc/rc.local << EOF
#!/bin/bash
exit 0
EOF'
sudo chmod +x /etc/rc.local

Крок 2: Увімкніть юніт systemd rc-local (Ubuntu 18.04+)

sudo systemctl enable rc-local
sudo systemctl start rc-local

Крок 3: Додайте свою команду перед exit 0

sudo nano /etc/rc.local

Вставте свою команду вище рядка exit 0:

#!/bin/bash
/usr/local/bin/examplescript.sh >> /var/log/examplescript.log 2>&1 &
exit 0

& в кінці є обов’язковим для будь-якої тривалої команди — він переводить процес у фоновий режим, щоб rc.local не блокувався.

Крок 4: Перевірте виконання

sudo systemctl status rc-local

Критична помилка

На Ubuntu 20.04 та 22.04 rc-local.service має жорстко закодований тайм-аут 30 секунд. Якщо ваш скрипт виконується довше 30 секунд, systemd позначить сервіс як такий, що завершився з помилкою, і наступні команди в rc.local не виконаються. Явно перенаправляйте виведення та переводьте тривалі процеси у фоновий режим.

Метод 3: Використання сервісних юнітів systemd (рекомендовано)

Чому systemd є правильним підходом для виробництва

systemd — це не просто заміна SysVinit, це повноцінний менеджер системи та сесій, який забезпечує вирішення залежностей, паралельний запуск, активацію сокетів та D-Bus, запуск сервісів на вимогу, нагляд за процесами з автоматичним перезапуском, ізоляцію ресурсів на основі cgroup та структуровану агрегацію логів через journald. Для будь-якого робочого навантаження, що працює на Виділеному Сервері або виробничому VPS, юніти systemd є єдиним відповідним механізмом для управління автозавантажуваними скриптами.

Анатомія файлу юніту systemd

Файл юніту .service поділений на три обов’язкові секції:

  • [Unit]: Метадані, опис у зрозумілому для людини форматі та оголошення залежностей (After=, Requires=, Wants=).
  • [Service]: Параметри виконання — бінарний файл або скрипт для запуску, тип сервісу, політика перезапуску, змінні середовища та параметри пісочниці безпеки.
  • [Install]: Визначає, який цільовий юніт systemd активує цей юніт (WantedBy=multi-user.target є стандартом для серверних демонів).

Покрокова реалізація

Крок 1: Підготуйте свій скрипт

Переконайтеся, що ваш скрипт є виконуваним і розташований за стабільним шляхом:

sudo cp examplescript.sh /usr/local/bin/examplescript.sh
sudo chmod +x /usr/local/bin/examplescript.sh

Крок 2: Створіть файл юніту

sudo nano /etc/systemd/system/examplescript.service

Файл юніту виробничого рівня з посиленням безпеки:

[Unit]
Description=Example Autoload Script
Documentation=https://your-internal-wiki/examplescript
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/examplescript.sh
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
StandardOutput=journal
StandardError=journal
SyslogIdentifier=examplescript
User=nobody
Group=nogroup
NoNewPrivileges=true
ProtectSystem=strict
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Крок 3: Перезавантажте демон systemd

Після створення або зміни будь-якого файлу юніту необхідно перезавантажити індекс конфігурації демона:

sudo systemctl daemon-reload

Крок 4: Увімкніть сервіс для автозапуску

sudo systemctl enable examplescript.service

Це створює символічне посилання в /etc/systemd/system/multi-user.target.wants/, що вказує на ваш файл юніту.

Крок 5: Запустіть сервіс негайно

sudo systemctl start examplescript.service

Крок 6: Перевірте статус та логи

sudo systemctl status examplescript.service
sudo journalctl -u examplescript.service -f

Розуміння типів сервісів systemd

Директива Type= в секції [Service] є одним з найбільш неправильно зрозумілих параметрів. Вибір неправильного типу призводить до того, що systemd неправильно повідомляє про готовність сервісу, що спричиняє збої залежностей.

ТипПоведінкаВипадок використання
simpleПроцес, запущений ExecStart, є основним процесом. Systemd вважає його готовим негайно.Скрипти та прості демони, які не розгалужуються
forkingПроцес розгалужується і батьківський завершується. Systemd відстежує дочірній через PID-файл.Традиційні Unix-демони (наприклад, Apache з PidFile)
oneshotПроцес виконується до завершення і виходить. Systemd чекає перед запуском залежних юнітів.Одноразові задачі ініціалізації, скрипти налаштування
notifyПроцес сигналізує про готовність через sd_notify().Демони з нативною інтеграцією systemd
idleВиконання відкладається до того, як усі активні завдання будуть відправлені.Фонові задачі з низьким пріоритетом

Для скрипту, який запускається один раз під час завантаження і завершується, використовуйте Type=oneshot з RemainAfterExit=yes, щоб зберегти юніт у стані “активний” після завершення скрипту.

Розширено: Упорядкування залежностей з After= та Wants=

Поширена виробнича помилка виникає, коли скрипт, що потребує мережевого з’єднання, запускається до повної ініціалізації мережевого стеку. Правильний ланцюг залежностей для скриптів, що залежать від мережі:

After=network-online.target
Wants=network-online.target

Це відрізняється від After=network.target, який лише гарантує, що мережеві інтерфейси були налаштовані — але не те, що вони фактично онлайн і доступні. Залежність network-online.target вимагає від systemd-networkd-wait-online.service або еквівалента підтвердження з’єднання.

Порівняння: Усі три методи на перший погляд

Функція/etc/init.d//etc/rc.localЮніт systemd
Рекомендовано для виробництваНіНіТак
Підтримка паралельного запускуНіНіТак
Нагляд за процесами / автоперезапускНіНіТак
Управління залежностямиОбмежено (заголовки LSB)ВідсутнєПовне
Структуроване журналюванняНіНіТак (journald)
Пісочниця безпекиНіНіТак
СкладністьНизькаДуже низькаСередня
Підтримується на Ubuntu 22.04+Через рівень сумісностіЧерез rc-local.serviceНативно
Підходить для тривалих демонівЧастковоНіТак
Підходить для одноразових задач ініціалізаціїТакТакТак (oneshot)

Поширені помилки та як їх уникнути

Запуск скриптів від імені root без необхідності. Директиви User= та Group= у файлах юнітів systemd дозволяють знизити привілеї. Скрипт, якому потрібно лише записувати в /var/log/myapp/, не потребує root — створіть виділеного системного користувача та відповідно призначте права власності на каталог.

Відсутність перенаправлення виведення в rc.local. Без перенаправлення виведення будь-який вивід echo або помилки від команд rc.local потрапляє на системну консоль і втрачається. Завжди додавайте >> /var/log/yourscript.log 2>&1.

Непослідовне використання абсолютних шляхів. Сервіси systemd працюють у мінімальному середовищі без PATH користувача. Завжди використовуйте абсолютні шляхи для кожного бінарного файлу, на який посилаєтесь у ExecStart, включаючи інтерпретатори, такі як /usr/bin/python3 або /bin/bash.

Забуття daemon-reload після редагування файлів юнітів. systemd кешує вміст файлів юнітів. Якщо ви редагуєте файл .service і не запускаєте sudo systemctl daemon-reload, systemd продовжуватиме використовувати стару конфігурацію.

Розміщення файлів юнітів у /lib/systemd/system/ для користувацьких скриптів. Каталог /lib/systemd/system/ управляється менеджером пакетів. Користувацькі файли юнітів належать до /etc/systemd/system/, який має пріоритет і зберігається після оновлень пакетів.

Практична матриця рішень: який метод використовувати

Використовуйте цю схему для вибору відповідного методу для вашого конкретного сценарію:

  • Тривалий демон, який повинен перезапускатися при збої — юніт systemd з Restart=on-failure
  • Одноразовий скрипт налаштування, який повинен завершитися до запуску інших сервісів — юніт systemd з Type=oneshot та залежностями Before=
  • Скрипт, що вимагає повного підключення мережі — юніт systemd з After=network-online.target
  • Швидкий однорядковий скрипт для тестування або прототипування/etc/rc.local (тимчасово)
  • Застарілий застосунок, що постачається з LSB init-скриптом/etc/init.d/ з update-rc.d
  • Будь-що, що працює у виробництві — systemd, завжди

Для адміністраторів, що управляють кількома серверами Ubuntu, розгляньте поєднання управління юнітами systemd з інструментами управління конфігурацією, такими як Ansible, який може ідемпотентно розгортати та вмикати файли .service по всьому вашому парку. Якщо вам потрібне кероване середовище з повним root-доступом для реалізації цих конфігурацій, VPS Хостинг з Панеллю керування VPS забезпечує гнучкість для управління сервісами systemd безпосередньо без обмежень.

Для команд, що запускають ресурсоємні робочі навантаження, які потребують скриптів запуску для ініціалізації GPU-драйверів, середовищ CUDA або серверів ML-інференсу, середовища GPU Хостингу особливо виграють від ланцюгів залежностей After= systemd, забезпечуючи повне завантаження драйверів до того, як сервіси застосунків намагаються прив’язатися до апаратних ресурсів.

Якщо ваші автозавантажувані скрипти взаємодіють з конфігураціями веб-сервера або процедурами ініціалізації бази даних, пов’язаними з середовищем панелі керування, установки VPS з cPanel вимагають особливої уваги — cPanel управляє власним рівнем нагляду за сервісами, і користувацькі юніти systemd повинні бути визначені так, щоб уникнути конфліктів з хуками управління сервісами cPanel.

Технічний контрольний список ключових висновків

Перед розгортанням будь-якого скрипту запуску на сервері Ubuntu перевірте наступне:

  • Розташування файлу юніту: Користувацькі скрипти розміщуються в /etc/systemd/system/, а не в /lib/systemd/system/
  • Біт виконання: Підтвердіть за допомогою ls -la /path/to/script.sh — біт x повинен бути встановлений
  • Абсолютні шляхи: Кожен бінарний файл у ExecStart використовує повний шлях; без покладання на $PATH
  • Оголошення залежностей: After=network-online.target для будь-якого скрипту, що залежить від мережі
  • Тип сервісу: Type=simple для постійних демонів, Type=oneshot для скриптів, що запускаються і завершуються
  • Мінімізація привілеїв: User=, Group=, NoNewPrivileges=true, ProtectSystem=strict
  • Налаштоване журналювання: StandardOutput=journal та StandardError=journal для інтеграції з journald
  • Виконано daemon-reload: Завжди запускайте sudo systemctl daemon-reload після створення або редагування файлів юнітів
  • Enable проти start: enable створює символічне посилання автозапуску; start запускає його негайно — обидві команди необхідні
  • Перевірено з journalctl: Підтвердіть успішне виконання за допомогою sudo journalctl -u yourservice.service --since "5 minutes ago"

FAQ

У чому різниця між systemctl enable та systemctl start?

systemctl enable створює символічне посилання, яке змушує сервіс автоматично запускатися при наступному завантаженні. systemctl start запускає сервіс негайно в поточній сесії. Зазвичай вам потрібні обидві команди при першому налаштуванні нового сервісу.

Чому мій сервіс systemd завершується з помилкою “executable not found”, хоча скрипт існує?

Це майже завжди означає, що шлях ExecStart неправильний або скрипту не вистачає біту виконання. Перевірте за допомогою which yourscript та ls -la /path/to/script. Також переконайтеся, що перший рядок вашого скрипту є дійсним shebang (#!/bin/bash або #!/usr/bin/env python3), оскільки systemd за замовчуванням не викликає shell для ExecStart.

Чи можна запустити скрипт при запуску лише один раз, а не при кожному завантаженні?

Використовуйте Type=oneshot з директивою ConditionPathExists=!/var/run/myscript.done в секції [Unit]. Скрипт створює файл-маркер при першому запуску; наступні завантаження пропускають виконання, оскільки умова не виконується.

Чи підтримується /etc/rc.local на Ubuntu 22.04?

Так, але він вимкнений за замовчуванням. Вам потрібно вручну увімкнути юніт rc-local.service за допомогою sudo systemctl enable rc-local та переконатися, що файл існує і є виконуваним. Він підтримується як засіб сумісності, а не рекомендована практика.

Як перевірити, чому скрипт запуску не запустився?

Запустіть sudo journalctl -u yourservice.service -b, щоб переглянути всі записи логів для цього юніту з моменту останнього завантаження. Для збоїв rc.local перевірте sudo systemctl status rc-local.service та перегляньте /var/log/syslog на наявність записів з позначками часу під час послідовності завантаження.

15%

Збережіть 15% на всі хостинг-послуги

Перевірте свої навички і отримайте Знижку на будь-який план хостингу

Використовуй код:

Skills
Почати