Gymterview
middle

Как запустить Java-приложение как systemd-сервис?

Создание systemd-сервиса позволяет Java-приложению запускаться автоматически при загрузке, перезапускаться при сбоях и управляться стандартными инструментами.

Шаг 1. Подготовка

Пример
# Создать пользователя для приложения (без оболочки)
sudo useradd -r -s /usr/sbin/nologin appuser

# Создать каталог и скопировать приложение
sudo mkdir -p /opt/myapp
sudo cp application.jar /opt/myapp/

# Установить права
sudo chown -R appuser:appuser /opt/myapp

Шаг 2. Создание unit-файла

Полный unit-файл /etc/systemd/system/myapp.service
[Unit]
Description=My Spring Boot Application
Documentation=https://example.com
After=network.target postgresql.service
Wants=postgresql.service

[Service]
Type=simple
User=appuser
Group=appuser
WorkingDirectory=/opt/myapp

# Файл с переменными окружения
EnvironmentFile=/opt/myapp/.env

# Команда запуска
ExecStart=/usr/bin/java ${JAVA_OPTS} -jar /opt/myapp/application.jar

# Корректная остановка (SIGTERM -> Spring Boot graceful shutdown)
ExecStop=/bin/kill -SIGTERM $MAINPID
SuccessExitStatus=143

# Перезапуск при сбоях
Restart=on-failure
RestartSec=10

# Таймауты
TimeoutStartSec=60
TimeoutStopSec=30

# Логирование в journald
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myapp

# Безопасность
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/myapp/logs

[Install]
WantedBy=multi-user.target

Шаг 3. Запуск и управление

Пример
sudo systemctl daemon-reload      # Перечитать конфигурацию systemd
sudo systemctl start myapp        # Запустить
sudo systemctl status myapp       # Проверить статус
journalctl -u myapp -f            # Посмотреть логи
sudo systemctl enable myapp       # Включить автозапуск

Ключевые параметры

  • SuccessExitStatus=143 — код 143 = 128 + 15 (SIGTERM). Spring Boot завершается с этим кодом при корректной остановке. Без этого systemd считает это ошибкой
  • Restart=on-failure — перезапуск только при аварийном завершении (не при systemctl stop)
  • ProtectSystem=strict — файловая система только для чтения, кроме ReadWritePaths
  • NoNewPrivileges=true — процесс не может повысить привилегии

На собеседовании: это практический вопрос, который показывает опыт деплоя. Ключевое — знать SuccessExitStatus=143 и Restart=on-failure. Частая ошибка — запускать приложение от root или забыть daemon-reload после изменения unit-файла.