> Полный список статей есть в [llms.txt](https://docs.f3cloud.com/llms.txt). Markdown-версия есть у каждой страницы, достаточно добавить .md к её адресу. Эта страница в Markdown: [https://docs.f3cloud.com/ru/linux/systemd-services.md](https://docs.f3cloud.com/ru/linux/systemd-services.md).

# Службы в Linux – команды systemctl и свой сервис systemd

Службы в Linux и команда systemctl. Как запускать, останавливать, перезапускать и включать автозапуск служб, смотреть их статус и логи, и как сделать свой сервис systemd для бота или скрипта, который сам поднимается после падения и перезагрузки. Проверено на Debian 12.

Веб-сервер, база данных, Docker и SSH работают на сервере постоянно, сами запускаются после перезагрузки и поднимаются снова, если упали. За это отвечает **systemd**, а управляют им командой `systemctl`. В этой статье разберём, как устроены службы, научимся запускать, останавливать и перезапускать их, смотреть статус и логи, а затем сделаем собственную службу для скрипта или бота, чтобы он работал круглосуточно без открытого терминала. Все команды мы проверили на тестовом сервере с Debian 12.

***

## Как systemd управляет службами

Когда сервер включается, ядро Linux запускает самый первый процесс с номером 1. В Debian, Ubuntu и большинстве современных дистрибутивов этим процессом является systemd. Его задача в том, чтобы запустить всё остальное в правильном порядке, а затем следить за запущенным до самого выключения сервера. Всё, чем управляет systemd, описано в небольших текстовых файлах, которые называются **юнитами**. Юнит службы имеет расширение `.service` и сообщает, какую программу запустить, от имени какого пользователя, после каких других служб и что делать, если программа завершилась.

Запустив службу, systemd помещает её процесс и все процессы, которые он породит, в отдельную группу. Благодаря этому система точно знает, какие процессы относятся к службе. Команда остановки завершает их все, а не только главный, и в статусе службы видно, сколько памяти и процессорного времени расходует вся группа целиком. Всё, что программа выводит в консоль, systemd не теряет, а передаёт в системный журнал, из которого его затем можно прочитать командой `journalctl`. Именно поэтому программе, запущенной как служба, не нужен открытый терминал. Она не зависит от того, подключены вы по SSH или нет.

Здесь важно различать два независимых действия. **Запустить** службу значит выполнить её прямо сейчас. **Включить** службу значит сделать так, чтобы systemd запускал её при каждой загрузке сервера. Можно запустить службу, не включая её, и тогда после перезагрузки она не поднимется. Можно включить её, не запуская, и тогда она заработает только после следующей загрузки. На практике чаще всего нужны оба действия сразу, и для этого есть параметр `--now`.

Последнее, что стоит понимать, это перезапуск после сбоя. Если в юните указано `Restart=always`, systemd замечает, что процесс завершился, выжидает заданную паузу и запускает его снова. Мы проверили это на тестовом сервере. Процесс нашей службы был принудительно завершён, и через пять секунд, как и было задано в настройках, systemd поднял его заново.

***

## 1. Посмотрите статус службы

Статус показывает, работает ли служба, включён ли её автозапуск, главный процесс, расход памяти и последние строки лога.

```bash
systemctl status nginx
```

<figure><img src="https://docs.f3cloud.com/img/systemd-status-nginx.png" alt="Вывод systemctl status nginx с состоянием active running, процессами и последними строками журнала"><figcaption><p>Служба nginx работает и включена в автозапуск</p></figcaption></figure>

Самое важное здесь в первых строках.

* **Loaded** показывает, где лежит файл юнита, и после `;` состояние автозапуска, `enabled` или `disabled`.
* **Active** показывает текущее состояние. `active (running)` значит, что служба работает, `inactive (dead)` что остановлена, а `failed` что она упала.
* **Main PID** это номер главного процесса.

Если вывод не помещается на экран, `systemctl` открывает его в программе просмотра, выход из неё по клавише <kbd>q</kbd>.

***

## 2. Управляйте службой

```bash
systemctl start nginx      # запустить
systemctl stop nginx       # остановить
systemctl restart nginx    # перезапустить
systemctl reload nginx     # перечитать настройки без остановки, если служба это умеет

systemctl enable nginx     # включить автозапуск
systemctl disable nginx    # выключить автозапуск
systemctl enable --now nginx   # включить автозапуск и сразу запустить
```

Проверить отдельно, работает ли служба и включена ли она, удобно короткими командами. Они пригодятся и в скриптах.

```bash
systemctl is-active nginx
systemctl is-enabled nginx
```

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

```bash
systemctl list-units --type=service --state=running
systemctl --failed
```

***

## 3. Посмотрите логи службы

Всё, что служба пишет в консоль, хранится в журнале systemd.

```bash
# Последние 50 строк лога службы
journalctl -u nginx -n 50

# Следить за логом в реальном времени, выход по Ctrl+C
journalctl -u nginx -f

# Записи за последний час
journalctl -u nginx --since "1 hour ago"
```

***

## 4. Создайте свою службу

Допустим, у вас есть скрипт на Python, например Telegram-бот, который должен работать круглосуточно. Если запустить его в терминале, он остановится, как только вы отключитесь от сервера. Сделаем для него службу.

1. Создайте для бота отдельного пользователя без права входа на сервер. Так бот не получит лишних прав, даже если в нём найдётся уязвимость.

   ```bash
   useradd -r -s /usr/sbin/nologin appuser
   ```

2. Положите скрипт в папку, например `/opt/mybot/bot.py`, и сделайте этого пользователя её владельцем.

   ```bash
   chown -R appuser:appuser /opt/mybot
   ```

3. Создайте файл юнита.

   ```bash
   nano /etc/systemd/system/mybot.service
   ```

   Вставьте в него следующее содержимое и сохраните файл сочетанием <kbd>Ctrl</kbd> + <kbd>O</kbd>, затем <kbd>Enter</kbd> и <kbd>Ctrl</kbd> + <kbd>X</kbd>.

   ```ini
   [Unit]
   Description=My Telegram bot
   After=network-online.target
   Wants=network-online.target

   [Service]
   User=appuser
   WorkingDirectory=/opt/mybot
   ExecStart=/usr/bin/python3 /opt/mybot/bot.py
   Restart=always
   RestartSec=5

   [Install]
   WantedBy=multi-user.target
   ```

4. Сообщите systemd о новом файле, включите и запустите службу, затем проверьте статус.

   ```bash
   systemctl daemon-reload
   systemctl enable --now mybot
   systemctl status mybot
   ```

<figure><img src="https://docs.f3cloud.com/img/systemd-enable-service.png" alt="Команды systemctl daemon-reload, enable --now и status для новой службы mybot, служба в состоянии active running"><figcaption><p>Своя служба запущена, вывод скрипта уже виден в логе</p></figcaption></figure>

Разберём, что означают строки юнита.

* **After** и **Wants** со значением `network-online.target` откладывают запуск до тех пор, пока на сервере не заработает сеть. Боту без сети делать нечего.
* **User** задаёт пользователя, от имени которого работает скрипт.
* **WorkingDirectory** это папка, в которой скрипт будет искать свои файлы.
* **ExecStart** это команда запуска. Путь к программе указывается полностью, например `/usr/bin/python3`. Узнать его можно командой `which python3`.
* **Restart=always** и **RestartSec=5** перезапускают скрипт через 5 секунд после любого завершения.
* **WantedBy=multi-user.target** нужен для автозапуска при загрузке сервера.

Чтобы убедиться, что автоперезапуск работает, мы принудительно завершили процесс бота. В логе видно, как systemd зафиксировал падение и через пять секунд запустил бота снова.

<figure><img src="https://docs.f3cloud.com/img/systemd-auto-restart.png" alt="Журнал службы mybot, процесс завершён сигналом KILL и через 5 секунд перезапущен systemd"><figcaption><p>Процесс убит в 12:04:50 и снова работает в 12:04:55</p></figcaption></figure>

> **После каждого изменения юнита.**
>
> Если вы поправили файл `.service`, выполните `systemctl daemon-reload`, а затем `systemctl restart mybot`. Без первой команды systemd продолжит пользоваться старой версией файла. Проверить юнит на ошибки можно командой `systemd-analyze verify /etc/systemd/system/mybot.service`.

***

## Частые вопросы

<details>

<summary>status=203/EXEC</summary>

systemd не смог запустить программу из строки `ExecStart`. Мы получили эту ошибку, указав несуществующий путь `/usr/bin/python` вместо `/usr/bin/python3`. Проверьте путь командой `which`, а если запускаете свой скрипт напрямую, проверьте, что у него есть право на выполнение и первая строка вида `#!/usr/bin/env python3`.

<figure><img src="https://docs.f3cloud.com/img/systemd-203-exec.png" alt="Статус службы с ошибкой status=203/EXEC и состоянием activating auto-restart"><figcaption><p>Неверный путь к программе в ExecStart</p></figcaption></figure>

</details>

<details>

<summary>Unit mybot.service could not be found</summary>

systemd не знает о файле. Проверьте, что он лежит в `/etc/systemd/system/` и называется так же, как вы пишете в команде, а после создания файла выполните `systemctl daemon-reload`.

</details>

<details>

<summary>Служба постоянно перезапускается</summary>

Программа запускается и сразу падает, а `Restart=always` поднимает её снова. Причину ищите в логе командой `journalctl -u mybot -n 50`. Чаще всего это ошибка в самом скрипте, отсутствующая библиотека или нехватка прав на файлы. Про права подробно рассказано в статье про [chmod и chown](https://docs.f3cloud.com/ru/linux/linux-permissions.md).

</details>

<details>

<summary>Как полностью удалить свою службу</summary>

```bash
systemctl disable --now mybot
rm /etc/systemd/system/mybot.service
systemctl daemon-reload
```

</details>

***

## Наши ресурсы

**Telegram-канал:** [https://t.me/f3cloud_news](https://t.me/f3cloud_news)\
**Официальный сайт:** [https://f3cloud.com](https://f3cloud.com/ru)
