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]

DirectiveObjectif
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]

DirectiveObjectif
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]

DirectiveObjectif
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

TypeQuand l’utiliserComment systemd suit la disponibilite
simpleLa plupart des apps modernesConsidere l’unite demarree des qu’ExecStart fait un fork
execComme simple, mais attend que exec reussisseAttend que le binaire s’execute avec succes
forkingDaemons traditionnels qui font un forkAttend que le processus parent se termine
oneshotScripts qui s’executent une fois et se terminentAttend qu’ExecStart se termine avant de marquer comme actif
notifyApps qui envoient une notification de disponibiliteAttend 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

FonctionnalitesystemdSysVinit / init.dsupervisordPM2
Inclus avec l’OSOui (toutes distros)Oui (legacy)Non (pip install)Non (npm install)
Ordre des dependancesGraphe completOrdre manuelLimiteNon
Activation par socketOuiNonNonNon
Limites ressources cgroupOui (natif)NonNonNon
Sandbox niveau noyauOui (etendu)NonNonNon
Journaux centralisesjournald (structure)syslog / fichiersFichiers seulementFichiers PM2
Jobs planifiesOui (unites timer)NonNonOui (style cron)
Integration Node.jsBonneMauvaiseBonneExcellente
Courbe d’apprentissageModereeFaibleFaibleTres 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