TL;DR — Résumé Rapide

Maitrisez les services systemd sur Linux: anatomie des fichiers unit, exemples Node.js et Python, politiques de redemarrage, limites de ressources et securite.

SYSTEMD — GESTION DES SERVICES LINUX nginx.service active (running) myapp.service active (running) backup.timer active (waiting) worker.service active (running) Gerez tous les processus de votre serveur Linux depuis un seul systeme init

Maintenir des processus a longue duree de vie sur un serveur Linux necessitait autrefois des scripts SysVinit complexes, des configurations supervisor ou des hacks shell fragiles. systemd a tout change. En tant que systeme init par defaut sur toutes les principales distributions Linux — Ubuntu, Debian, RHEL, Fedora, Arch — systemd offre une maniere unifiee et declarative de definir exactement comment tout processus doit demarrer, s’arreter, redemarrer, journaliser et interagir avec le reste du systeme.

Ce guide couvre tout ce dont vous avez besoin pour creer des services systemd personnalises prets pour la production: l’anatomie d’un fichier unit, des exemples concrets pour Node.js et Python, les types de service, les politiques de redemarrage, les limites de ressources, les directives de securite, l’activation par socket, les unites de minuterie comme alternative a cron, et comment deboguer les pannes avec journalctl.


Prerequis

Avant de commencer, assurez-vous d’avoir:

  • Un systeme Linux avec systemd (Ubuntu 16.04+, Debian 8+, CentOS 7+, RHEL 7+, Fedora 15+ ou toute distribution moderne)
  • Un terminal avec acces sudo ou root
  • Une familiarite basique avec la ligne de commande et un editeur de texte (nano ou vim)
  • Une application a executer en tant que service (Node.js, Python, binaire Go, etc.)

Verifiez que systemd est en cours d’execution:

systemctl --version
# Doit afficher: systemd 249 (ou numero de version similaire)

Anatomie du Fichier Unit

Chaque service gere par systemd est decrit par un fichier unit — un fichier de configuration en texte brut au format INI. Les fichiers unit de service personnalises se trouvent dans /etc/systemd/system/. Le nom du fichier se termine par .service.

Un fichier unit complet comporte trois sections:

[Unit]
Description=Mon Service d'Application
Documentation=https://exemple.com/docs
After=network.target
Wants=network-online.target

[Service]
Type=simple
User=monapp
Group=monapp
WorkingDirectory=/opt/monapp
ExecStart=/usr/bin/node /opt/monapp/server.js
Restart=on-failure
RestartSec=5s
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

La Section [Unit]

Directive Objectif
Description= Nom lisible affiche dans la sortie de systemctl status
After= Demarre cette unite apres que les unites listees sont actives
Wants= Dependance souple — les unites listees demarrent, mais leur echec est tolere
Requires= Dependance forte — si l’unite listee echoue, celle-ci echoue aussi
BindsTo= Comme Requires= mais arrete aussi cette unite quand la dependance s’arrete

La Section [Service]

Directive Objectif
Type= Modele de cycle de vie du processus (simple, forking, oneshot, notify)
User= / Group= Execute le processus en tant que cet utilisateur/groupe
ExecStart= La commande a executer (doit etre un chemin absolu)
ExecStartPre= Commandes a executer avant ExecStart
Restart= Quand redemarrer automatiquement
Environment= Definit des variables d’environnement en ligne
EnvironmentFile= Charge des variables d’environnement depuis un fichier
StandardOutput= Ou envoyer la sortie standard (journal, file:, null)

La Section [Install]

Directive Objectif
WantedBy= Quelle cible active ce service (generalement multi-user.target)
Alias= Noms supplementaires pour cette unite

Creer un Service Node.js

Supposons que vous ayez une API Node.js dans /opt/monapi/server.js ecoutant sur le port 3000.

Etape 1: Creer un utilisateur dedie

sudo useradd --system --no-create-home --shell /usr/sbin/nologin nodeapi
sudo chown -R nodeapi:nodeapi /opt/monapi

Etape 2: Creer le fichier unit

sudo nano /etc/systemd/system/monapi.service
[Unit]
Description=Mon Service API Node.js
After=network.target
Wants=network-online.target

[Service]
Type=simple
User=nodeapi
Group=nodeapi
WorkingDirectory=/opt/monapi
EnvironmentFile=/etc/monapi/environment
ExecStart=/usr/bin/node /opt/monapi/server.js
ExecStartPre=/usr/bin/node --check /opt/monapi/server.js
Restart=on-failure
RestartSec=5s
TimeoutStopSec=10s
StandardOutput=journal
StandardError=journal
SyslogIdentifier=monapi
MemoryMax=512M
CPUQuota=50%
LimitNOFILE=65536
NoNewPrivileges=true
ProtectSystem=strict
PrivateTmp=true
ReadWritePaths=/opt/monapi/logs /var/lib/monapi

[Install]
WantedBy=multi-user.target

Etape 3: Creer le fichier d’environnement

sudo mkdir -p /etc/monapi
sudo nano /etc/monapi/environment
NODE_ENV=production
PORT=3000
DATABASE_URL=postgresql://utilisateur:motdepasse@localhost/mabd
JWT_SECRET=votre-secret-ici
sudo chmod 600 /etc/monapi/environment

Etape 4: Activer et demarrer

sudo systemctl daemon-reload
sudo systemctl enable monapi.service
sudo systemctl start monapi.service
sudo systemctl status monapi.service

Creer un Service Python

Pour un worker Python dans /opt/worker/worker.py:

[Unit]
Description=Worker Python en Arriere-plan
After=network.target redis.service
Requires=redis.service

[Service]
Type=simple
User=pyworker
Group=pyworker
WorkingDirectory=/opt/worker
ExecStart=/opt/worker/venv/bin/python -u worker.py
EnvironmentFile=/etc/worker/environment
Restart=on-failure
RestartSec=10s
StartLimitIntervalSec=60s
StartLimitBurst=3
StandardOutput=journal
StandardError=journal
MemoryMax=256M
CPUQuota=25%
NoNewPrivileges=true
ProtectSystem=strict
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Le flag -u sur la commande Python desactive la mise en tampon de sortie pour que les journaux apparaissent immediatement dans journald.


Types de Service

Type Quand l’utiliser Comment systemd suit la disponibilite
simple La plupart des apps modernes Considere l’unite demarree des qu’ExecStart fait un fork
exec Comme simple, mais attend que exec reussisse Attend que le binaire s’execute avec succes
forking Daemons traditionnels qui font un fork Attend que le processus parent se termine
oneshot Scripts qui s’executent une fois et se terminent Attend qu’ExecStart se termine avant de marquer comme actif
notify Apps qui envoient une notification de disponibilite Attend la notification avant de marquer comme actif

Politiques de Redemarrage et Limites de Ressources

Politiques de Redemarrage

Restart=always        # Redемarre a chaque terminaison du service
Restart=on-failure    # Redемarre uniquement en cas d'echec
Restart=on-abnormal   # Redемarre en cas d'echec + timeout watchdog + signaux anormaux
Restart=no            # Ne redемarre jamais

Avec limitation du taux pour eviter qu’un service defaillant ne surcharge le systeme:

Restart=on-failure
RestartSec=5s
StartLimitIntervalSec=60s
StartLimitBurst=5

Limites de Ressources

MemoryMax=1G          # Limite stricte de memoire
MemoryHigh=800M       # Limite souple de memoire
MemorySwapMax=0       # Desactiver le swap pour ce service
CPUQuota=200%         # Limiter a 2 coeurs CPU complets
LimitNOFILE=65536     # Nombre maximum de descripteurs de fichiers ouverts
LimitNPROC=512        # Nombre maximum de processus/threads

Durcissement de la Securite

[Service]
NoNewPrivileges=true          # Empeche l'acquisition de nouveaux privileges
ProtectSystem=strict          # Monte /usr, /boot, /etc en lecture seule
PrivateTmp=true               # /tmp prive pour ce service
DynamicUser=true              # Utilisateur dynamique sans privileges
ProtectHome=true              # Bloque l'acces aux repertoires /home
SystemCallFilter=@system-service  # Filtre les appels systeme
ProtectKernelTunables=true    # Empeche l'ecriture dans les variables du noyau
ProtectKernelModules=true     # Empeche le chargement de modules du noyau

Analysez le score de securite de tout service en cours d’execution:

systemd-analyze security monapi.service

Unites de Minuterie: systemd comme Alternative a Cron

sudo nano /etc/systemd/system/sauvegarde-nocturne.service
[Unit]
Description=Sauvegarde Nocturne de la Base de Donnees

[Service]
Type=oneshot
User=backup
ExecStart=/usr/local/bin/backup-db.sh
StandardOutput=journal
sudo nano /etc/systemd/system/sauvegarde-nocturne.timer
[Unit]
Description=Lancer la Sauvegarde Nocturne a 2h du matin

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=300

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now sauvegarde-nocturne.timer
systemctl list-timers --all

systemd vs Autres Gestionnaires de Processus

Fonctionnalite systemd SysVinit / init.d supervisord PM2
Inclus avec l’OS Oui (toutes distros) Oui (legacy) Non (pip install) Non (npm install)
Ordre des dependances Graphe complet Ordre manuel Limite Non
Activation par socket Oui Non Non Non
Limites ressources cgroup Oui (natif) Non Non Non
Sandbox niveau noyau Oui (etendu) Non Non Non
Journaux centralises journald (structure) syslog / fichiers Fichiers seulement Fichiers PM2
Jobs planifies Oui (unites timer) Non Non Oui (style cron)
Integration Node.js Bonne Mauvaise Bonne Excellente
Courbe d’apprentissage Moderee Faible Faible Tres faible

Scenario Reel

Vous avez un serveur de production avec une application Python FastAPI qui traite des travaux depuis une file Redis. Le service doit redemarrer automatiquement en cas de panne et ne jamais consommer plus de 512 Mo de RAM.

[Unit]
Description=FastAPI Job Worker
After=network.target redis.service
Requires=redis.service
StartLimitIntervalSec=120s
StartLimitBurst=4

[Service]
Type=simple
User=appuser
Group=appuser
WorkingDirectory=/opt/fastapi-worker
ExecStart=/opt/fastapi-worker/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000 --workers 2
EnvironmentFile=/etc/fastapi-worker/environment
Restart=on-failure
RestartSec=8s
TimeoutStartSec=30s
TimeoutStopSec=15s
StandardOutput=journal
SyslogIdentifier=fastapi-worker
MemoryMax=512M
CPUQuota=100%
LimitNOFILE=32768
NoNewPrivileges=true
ProtectSystem=strict
PrivateTmp=true
ReadWritePaths=/opt/fastapi-worker/data

[Install]
WantedBy=multi-user.target

Pieges et Cas Particuliers

ExecStart doit etre un chemin absolu. Vous ne pouvez pas utiliser des built-ins shell, des pipes ou des redirections directement dans ExecStart. Encapsulez les commandes complexes dans un script.

Expansion des variables d’environnement. systemd developpe $VAR dans ExecStart quand la variable est definie via Environment= ou EnvironmentFile=, mais ne charge PAS les fichiers d’initialisation du shell. Votre ~/.bashrc n’est jamais charge.

Signes de pourcentage dans les fichiers unit. Dans les fichiers unit, % est un caractere specificateur. Pour utiliser un signe pourcentage litteral, echappez-le en %%.

DynamicUser et permissions de fichiers. Avec DynamicUser=true, l’UID alloue change entre les redemarrages. Utilisez des directives comme StateDirectory= ou LogsDirectory= pour que systemd gere correctement les repertoires persistants.

After= vs Requires=. After= ne controle que l’ordre — il ne cree pas de dependance. Requires= cree la dependance mais ne controle pas l’ordre. Vous voudrez presque toujours les deux ensemble.


Depannage

Le service ne demarre pas

sudo systemctl status monapi.service
journalctl -u monapi.service -b
journalctl -u monapi.service --since "10 minutes ago"
journalctl -u monapi.service -f

Le service demarre mais plante immediatement

journalctl -u monapi.service -n 100 --no-pager
ls -la /usr/bin/node
sudo -u nodeapi /usr/bin/node /opt/monapi/server.js

Reinitialiser un service en echec

sudo systemctl reset-failed monapi.service
sudo systemctl start monapi.service

Verifier l’exposition de securite

systemd-analyze security monapi.service
systemd-analyze verify /etc/systemd/system/monapi.service

Resume

  • Les fichiers unit se trouvent dans /etc/systemd/system/ et ont trois sections: [Unit], [Service] et [Install]
  • Executez toujours systemctl daemon-reload apres avoir modifie un fichier unit
  • Utilisez Type=simple pour la plupart des apps modernes; utilisez Type=notify pour les apps qui signalent leur disponibilite
  • Stockez les secrets dans un EnvironmentFile= separe avec les permissions 600, pas directement dans le fichier unit
  • Configurez les politiques de redemarrage avec Restart=on-failure et StartLimitBurst pour survivre aux pannes transitoires
  • Appliquez les directives de securite a chaque service de production
  • Remplacez les cron jobs par des unites de minuterie pour de meilleurs journaux
  • Deboguez avec journalctljournalctl -u nom-du-service -f est votre premier recours en cas de panne

Articles Connexes