Службы и журналы: запуск без открытого терминала
Локальный сервер работает, пока открыт терминал. После выхода он исчезает, а сообщение об ошибке осталось в потерянном окне. Для долгой работы нужен отдельный договор запуска, статуса и диагностики. В Ubuntu эту задачу часто выполняет systemd, но не каждое Linux-окружение поддерживает одинаковый менеджер и пользовательский сеанс.
В прошлой главе вы запустили HTTP-сервер и нашли его порт. Теперь повторим ту же полезную работу через пользовательскую службу. Системные unit-файлы менять не будем. Практика занимает тридцать–сорок минут; отсутствие systemd в конкретной WSL не превращается в необъяснимую ошибку ученика.
Общая подготовка для обоих способов
Подготовьте новый каталог ~/linux-course-service. Если он уже существует, сначала изучите прежнюю учебную работу и не перезаписывайте её автоматически. Каталог содержит только учебную страницу без секретов. Выполняйте следующие блоки в одном Bash-сеансе: определённая здесь функция потребуется в любой ветке.
mkdir -p "$HOME/linux-course-service/site"
printf 'managed linux course\n' > "$HOME/linux-course-service/site/index.html"
wait_http() {
for attempt in 1 2 3 4 5; do
if body=$(curl --noproxy '*' -fsS --connect-timeout 1 --max-time 2 http://127.0.0.1:8765/ 2>/dev/null) && [ "$body" = 'managed linux course' ]; then
return 0
fi
sleep 1
done
printf 'HTTP not ready after five attempts\n' >&2
return 1
}Проверка ограничена пятью попытками с таймаутом запроса и паузой. Она требует ожидаемого содержимого, а не только открытого порта. Остановите прежний сервер на 8765; при занятом порте изучите владельца, не завершайте чужой процесс.
Проверяем возможности среды
ps -p 1 -o comm=
command -v systemctl
systemctl --user list-units --type=service --no-pagerВ VM PID1 обычно systemd. В актуальной WSL его наличие зависит от версии и конфигурации. Даже при systemdPID1 пользовательский manager и bus могут быть недоступны в текущем сеансе. Сообщение о невозможности соединиться с bus не лечится автоматическим добавлением sudo: systemctl --user обращается к другой области управления.
Если третий вызов работает, выполняйте пользовательский опыт ниже. Если нет, переходите прямо к разделу «Переносимый путь без manager»: общая подготовка уже выполнена, создание unit не требуется. Для WSL официальная инструкция Microsoft по systemd описывает требования и restart окружения. Не переписывайте wsl.conf вслепую и не останавливайте чужие сеансы ради курса.
Unit описывает работу
Systemd читает unit — описание управляемого объекта. Service unit задаёт команду, рабочий каталог, правила перезапуска и связи с другими unit. Имя файла становится именем службы. Статусы loaded, active и failed отвечают на разные вопросы; успешный разбор файла не доказывает, что приложение действительно принимает запросы.
Создайте только для этой ветки mkdir -p "$HOME/.config/systemd/user". В системной Ubuntu подтвердите command -v python3; далее предполагается /usr/bin/python3. В новой пользовательской unit-записи:
[Unit]
Description=Linux course local HTTP demo
[Service]
Type=simple
ExecStart=/usr/bin/python3 -m http.server 8765 --bind 127.0.0.1 --directory %h/linux-course-service/site
Restart=no
[Install]
WantedBy=default.targetСохраните её как ~/.config/systemd/user/linux-course.service через редактор. %h — спецификатор домашнего каталога пользователя manager, а не переменная shell. ExecStart не является произвольной командной строкой Bash: конвейер | или redirect не заработают автоматически как в терминале. Предыдущий ручной сервер на 8765 сначала остановите.
Загрузить, запустить, наблюдать
systemctl --user daemon-reload
systemctl --user start linux-course.service
systemctl --user status linux-course.service --no-pager
journalctl --user -u linux-course.service -n 20 --no-pager
if wait_http; then
printf 'Expected HTTP response received\n'
else
systemctl --user status linux-course.service --no-pager
journalctl --user -u linux-course.service -n 20 --no-pager
fiDaemon-reload перечитывает описания, но не является restart приложения. Start запускает службу. Journalctl читает записи журнала; доступ, формат времени и сохранение между перезагрузками зависят от настройки среды. Curl подтверждает отдельный прикладной результат. Если unit active, но HTTP не отвечает, проверьте порт, bind и журнал, а не объявляйте проверку завершённой.
Type=simple сообщает о запуске процесса, а не о готовности HTTP. Первоначальный отказ соединения может быть обычной задержкой старта; ограниченный повтор отделяет её от устойчивого отказа. При занятом порте служба может стать failed; это управляемый отказ. Не включаем автоматический бесконечный restart, который затруднит первый разбор. Также не выполняем enable: запуск при будущем сеансе не требуется для финала. Пользовательская служба без дополнительных правил не обязана переживать выход пользователя или выключение VM.
Переносимый путь без manager
Если пользовательский systemd недоступен, запускайте Python-сервер вручную с явно выбранной папкой, а stdout и stderr направьте в собственный server.log. Для unbuffered Python подходит python3 -u. PID сохраните через $!, проверяйте через curl, завершайте собственный процесс TERM и wait. Это воспроизводит диагностику, но не доказывает автозапуск или свойства systemd.
Пример ручного запуска после остановки прежнего сервера:
python3 -u -m http.server 8765 --bind 127.0.0.1 --directory "$HOME/linux-course-service/site" > "$HOME/linux-course-service/server.log" 2>&1 &
server_pid=$!
if wait_http; then
printf 'Expected HTTP response received\n'
else
cat "$HOME/linux-course-service/server.log"
fi
tail -n 10 "$HOME/linux-course-service/server.log"
kill -TERM "$server_pid"
wait "$server_pid"После TERM команда wait может вернуть 143 (128+15) и оболочка показать Terminated: это ожидаемое завершение своего сервера сигналом. Функция wait_http проверяет готовность и здесь. Если она вернула ошибку, опыт ещё не принят: разбирайте журнал и причину. Ошибку занятого порта разбирайте по журналу; не посылайте сигналы постороннему владельцу сокета.
Самостоятельная лаборатория
Запустите службу либо переносимый вариант, получите HTTP-ответ, прочитайте последние записи и остановите работу. Для systemd используйте systemctl --user stop linux-course.service, затем проверьте отсутствие HTTP-ответа. После изменения Description выполните daemon-reload и объясните, почему приложение не обязано само перезапуститься.
Критерии готовности: в отчёте указан фактически выбранный путь, manager не предполагается без проверки, журналы относятся именно к вашему unit/PID. Вы отличаете статус менеджера от результата HTTP. Завершение оставляет учебный сервис остановленным; автозапуск без необходимости не включён.
Разбор
Unit сохраняет договор запуска отдельно от terminal-сеанса, journal помогает объяснить отказ. Но systemd не заменяет права файлов, сетевой адрес или проверку приложения. В WSL без пользовательского manager успешная ручная демонстрация засчитывает переносимую часть, а systemd остаётся явно непроверенным. Далее сохраним учебные данные так, чтобы восстановление тоже имело проверяемый результат.
Первичные источники: systemd.service, systemctl, journalctl.