Systemd timer : une alternative moderne à cron

Depuis des années, cron est l’outil par défaut pour planifier des tâches sous Linux. Simple, efficace… mais aussi assez limité dès qu’on veut aller un peu plus loin.

Avec l’arrivée de systemd, une alternative plus moderne existe : les systemd timers. Plus flexibles, mieux intégrés au système, et surtout capables de gérer des cas que cron ne sait pas traiter proprement.

Dans cet article, on va voir pourquoi il peut être intéressant de laisser tomber cron, et comment passer aux systemd timers sans se compliquer la vie.

Avant de rentrer dans le vif du sujet, je vais vous expliquer comment j’en suis arrivé à utiliser les systemd timers. Et comme souvent, ça part d’un cas concret lié à rdr-it.com.

En mars 2026, je me lance dans une refonte du site avec, au passage, un changement d’hébergement. Nouvelle VPS sous Debian 13, je redéploie tranquillement mes conteneurs… jusqu’à arriver sur la stack qui fait tourner Matomo. Pour ceux qui connaissent, il y a une tâche planifiée à mettre en place pour traiter les données. Rien de bien compliqué, en théorie.

Je lance donc mon classique crontab -e… et là, surprise : la commande n’existe pas. Petit moment de flottement 😅 Réflexe immédiat, je m’apprête à installer cron avec un bon vieux apt install cron -y. Et puis je m’arrête.

Je me dis qu’en 2026, si cron n’est même plus installé par défaut, ce n’est probablement pas un hasard. Le système a forcément besoin d’un planificateur pour ses tâches en arrière-plan (mises à jour, rotation des logs, etc.), donc il doit bien y avoir autre chose.

Plutôt que de refaire “comme avant”, je fais une petite recherche sur Internet. Et je tombe sur un article de Stéphane Robert qui présente la planification de tâches avec les systemd timers… et là, ça commence à devenir vraiment intéressant.

Cron vs systemd timer : ce que vous devez savoir

Si vous avez déjà utilisé Linux un peu sérieusement, vous connaissez forcément cron. C’est simple, léger, fiable… mais limité. Chaque tâche planifiée est isolée, et dès qu’on veut gérer des dépendances, des redémarrages, ou des délais plus complexes, ça devient vite compliqué. Sans compter qu’il faut souvent jongler avec différents fichiers crontab pour différents utilisateurs, et qu’un petit oubli peut faire planter tout le planning.

C’est là que systemd timer entre en jeu. Présent par défaut sur toutes les distributions modernes, il fonctionne main dans la main avec systemd, le gestionnaire de services. Concrètement, un timer n’est pas juste une tâche qui s’exécute à intervalle régulier : c’est un service planifié, avec toutes les fonctionnalités qu’on attend d’un service moderne :

  • Activation conditionnelle : tu peux lancer une tâche seulement si un service est actif ou après un certain événement.
  • Logs intégrés : toutes les exécutions sont visibles via journalctl, plus besoin de bricoler des fichiers de log séparés.
  • Flexibilité dans les horaires : tu peux gérer des intervalles précis, des délais aléatoires, ou même exécuter une tâche quelques minutes après le démarrage de la machine.
  • Fiabilité : si le timer rate son exécution, systemd peut le relancer automatiquement. Plus besoin de s’inquiéter d’une tâche qui a sauté parce que le serveur était redémarré.

Autre avantage non négligeable : pas d’installation supplémentaire. Sur ma Debian 13 fraîchement déployée, cron n’était même pas installé par défaut. Avec systemd, pas de panique : tout est déjà là, intégré et maintenu avec le reste du système.

En résumé, si cron reste suffisant pour les tâches basiques, les systemd timers offrent une approche plus robuste, plus moderne et plus lisible, surtout dès qu’on commence à gérer un serveur ou des conteneurs qui tournent 24/7.

Comment planifier une tâche avec systemd timer

Pour planifier une tâche avec systemd timer, il faut comprendre une règle simple mais fondamentale : chaque tâche nécessite deux fichiers. Oui, deux !

Le premier est le fichier .service, qui définit ce que fait réellement la tâche : la commande à exécuter, l’utilisateur qui la lance, et toutes les options liées au service.

Le second est le fichier .timer, qui indique quand et comment le service doit s’exécuter : date, heure, intervalle, délai après le démarrage, etc.

Ces deux fichiers doivent porter le même nom de base pour être liés, mais avoir des extensions différentes (.service et .timer). Systemd va ensuite comprendre que le timer déclenche le service associé.

En résumé : le .service dit “quoi faire”, le .timer dit “quand le faire”. Et une fois ces fichiers en place, systemd se charge du reste, avec logs intégrés et fiabilité garantie.

Pour illustrer ce tutoriel, on va prendre un exemple un script qui va permet de redémarrer des stacks de conteneurs.

Voici le script qui sera à l’emplacement suivant : /root/scripts/stack-docker-maintenance.sh.

#!/bin/bash

echo "Pull image"
docker compose --file /containers/excalidraw/compose.yml pull
docker compose --file /containers/it-tools/compose.yml pull

echo "Stop stack"
docker compose --file /containers/excalidraw/compose.yml down
docker compose --file /containers/it-tools/compose.yml down

echo Start stack"
docker compose --file /containers/excalidraw/compose.yml up -d
docker compose --file /containers/it-tools/compose.yml up -d

Pour commencer nous allons créer le fichier de service :

nano /etc/systemd/system/stack-docker-maintenance.service

Voici le contenu du fichier :

[Unit]
Description=Stack Docker compose maintenance (pull/stop/up)
After=network.target

[Service]
Type=oneshot
# Chemin absolu vers votre script
ExecStart=/bin/bash /root/scripts/stack-docker-maintenance.sh
# Optionnel : definir le dossier de travail
WorkingDirectory=/root/scripts
User=root

[Install]
WantedBy=multi-user.target
SectionDirective / LigneRôle / Explication
[Unit]Description=Stack Docker compose maintenance (pull/stop/up)Décrit ce que fait le service, ici la maintenance de la stack Docker Compose (pull, stop, up).
After=network.targetLe service démarre après que le réseau soit prêt, nécessaire si le script a besoin d’accéder à Internet.
[Service]Type=oneshotLe service s’exécute une seule fois et se termine (pas de processus persistant).
ExecStart=/bin/bash /root/scripts/stack-docker-maintenance.shChemin vers le script à exécuter. Ici le script de maintenance Docker.
WorkingDirectory=/root/scriptsOptionnel : définit le dossier de travail pour le script. Pratique si le script utilise des chemins relatifs.
User=rootL’utilisateur qui exécutera le script. Ici root pour avoir accès à Docker.
[Install]WantedBy=multi-user.targetPermet à systemd de démarrer le service automatiquement quand le système atteint le niveau multi-user (équivalent runlevel 3).

On passe maintenant au fichier timer :

nano /etc/systemd/system/stack-docker-maintenance.timer
[Unit]
Description=Planification Stacks Docker maintenance

[Timer]
# Syntaxe : JourSemaine Année-Mois-Jour Heure:Minute:Seconde
# Pour tous les jours à 5h du matin :
OnCalendar=*-*-* 05:00:00

# Optionnel : Si le seurveur était éteint à 5h, lance le script des qu'il redemarre
#Persistent=true

[Install]
WantedBy=timers.target
SectionDirective / LigneRôle / Explication
[Unit]Description=Planification Stacks Docker maintenanceDécrit le timer, ici il planifie la maintenance de la stack Docker.
[Timer]OnCalendar=-* 05:00:00Définit quand la tâche doit s’exécuter. Ici tous les jours à 5h du matin. Syntaxe : JourSemaine Année-Mois-Jour Heure:Minute:Seconde.
Persistent=true (optionnel)Si le serveur était éteint au moment prévu, le timer lance le service dès le prochain démarrage. Très utile pour ne pas rater une tâche importante.
[Install]WantedBy=timers.targetPermet au timer d’être activé automatiquement et géré par systemd.

Ensuite on va recharger la configuration systemd :

systemctl daemon-reload

Cette commande est à exécuter après chaque modification de fichiers (.service ou .timer).

Activer le timer :

systemctl enable --now stack-docker-maintenance.timer
  • enable : configure le timer pour qu’il démarre automatiquement au boot.
  • –now : active le timer immédiatement, sans attendre le prochain redémarrage.

Pour vérifier la prise en compter entrer la commande suivante :

systemctl list-timers

Dans la liste, on voit bien notre service avec sa planification.

On vient de configurer une tâche à l’aide de systemd.

Focus sur les timers : planifications et répétitions

Pour les systemd timers, l’idée clé est simple : on définit quand le service associé doit s’exécuter, avec beaucoup de flexibilité. Le plus classique est de reproduire le comportement d’un cron. Par exemple, OnCalendar=*-*-* 05:00:00 va lancer la tâche tous les jours à 5h du matin. C’est l’équivalent d’un 0 5 * * * dans cron, mais avec la syntaxe systemd qui est plus explicite et plus lisible.

Si on veut que la tâche s’exécute juste au démarrage du serveur, on peut utiliser OnBootSec=5min pour déclencher le service cinq minutes après que le système ait démarré. Très pratique pour des scripts qui doivent s’assurer que tous les services sont opérationnels avant de tourner.

Pour des intervalles réguliers, comme toutes les 15 minutes, OnUnitActiveSec=15min est la solution. Contrairement à cron, il n’est pas nécessaire de calculer les heures ou minutes : systemd se charge de relancer le service exactement à l’intervalle défini, même si la tâche précédente a pris un peu plus de temps que prévu.

Et puis, on peut combiner des planifications différentes pour les jours de semaine et le week-end. Avec OnCalendar=Mon..Fri 03:00:00 tu exécutes le service uniquement en semaine, tandis que OnCalendar=Sat,Sun 06:00:00 planifie la tâche pour le week-end. On a donc une granularité que cron rendrait plus complexe, sans avoir besoin de multiplier les crontabs ou de bricoler des conditions dans ton script.

Enfin, n’oublie pas que la directive Persistent=true permet de rattraper les exécutions manquées. Si le serveur est éteint au moment prévu, systemd relancera automatiquement le service dès le prochain démarrage, ce qui rend ton planificateur fiable et résistant aux coupures.

FréquenceCronSystemd (OnCalendar)
Toutes les heures0 * * * *hourly ou *-*-* *:00:00
Tous les jours à minuit0 0 * * *daily ou *-*-* 00:00:00
Chaque lundi à 4h0 4 * * 1Mon *-*-* 04:00:00
Le 1er du mois à 2h0 2 1 * **-*-01 02:00:00
Toutes les 15 min*/15 * * * **:0/15

Exemple d’une tâche (service) qui va s’exécuter toutes les 15 minutes :

[Timer]
# S'exécute 15 min après le boot, puis toutes les 15 min
OnBootSec=15min
OnUnitActiveSec=15min
# Optionnel : pour être précis sur l'horloge (ex: 00, 15, 30, 45)
# OnCalendar=*:0/15

Tester et déboguer vos timers

Une fois votre .service et votre .timer en place, il est important de s’assurer que tout fonctionne comme prévu. Systemd offre quelques commandes très pratiques pour ça.

Pour vérifier le prochain passage, utilisez :

systemctl list-timers

Cette commande vous dira exactement quand votre timer va s’exécuter, et quand a eu lieu la dernière exécution. Très pratique pour confirmer que votre planification est correcte.

Si vous voulez tester votre script immédiatement, pas besoin d’attendre l’heure prévue par le timer :

systemctl start mon-script.service

Cela lance le service directement, ce qui vous permet de valider son fonctionnement.

Enfin, pour consulter les logs de votre script, notamment les echo que vous avez mis dans votre bash, c’est :

journalctl -u mon-script.service

Vous verrez toutes les sorties du script, ce qui facilite énormément le débogage et le suivi des tâches.

Conclusion

Avec systemd timer, on sort des limitations de cron tout en gardant une planification précise et fiable. Que ce soit pour exécuter des scripts de maintenance, des tâches répétitives toutes les X minutes, ou déclencher des actions au démarrage du serveur, systemd se charge de tout : répétitions, rattrapage des tâches manquées grâce à Persistent=true, et logs centralisés via journalctl.

Petite liberté sympa : le fichier .service et le fichier .timer n’ont pas obligatoirement besoin d’avoir le même nom, tant que le .timer fait référence au bon service via la directive Unit= (qui pointe vers ton service). Cela peut être pratique si tu veux réutiliser un même service pour plusieurs timers différents ou donner des noms plus explicites.

Enfin, pour ceux qui préfèrent ne pas passer par des scripts bash, vous pouvez directement exécuter vos stacks Docker Compose depuis le service, par exemple :

docker compose -f /path/stack/compose.yml up -d

FAQ

Peut-on utiliser un timer sans service séparé ?

Non, le timer doit pointer vers un service via Unit=. Le service contient la commande à exécuter, le timer gère la planification.

Le fichier service et timer doivent-ils avoir le même nom ?

Non, ce n’est pas obligatoire. Si les noms diffèrent, il faut simplement indiquer le nom correct du service dans la ligne Unit= du timer.

Peut-on planifier différentes heures selon les jours de la semaine ?

Oui, avec OnCalendar vous pouvez définir plusieurs expressions, par exemple :
OnCalendar=Mon..Fri 03:00:00 pour la semaine
- OnCalendar=Sat,Sun 06:00:00 pour le week-end

Peut-on exécuter directement des commandes Docker Compose depuis le service ?

Oui, votre service peut contenir une ligne comme : ExecStart=/usr/bin/docker compose -f /path/stack/compose.yml up -d

Que faire si le serveur est éteint au moment prévu du timer ?

Activez Persistent=true dans votre .timer : systemd exécutera le service dès que le serveur redémarrera.

Romain Drouche
Romain Drouche
Architecte Système | MCSE: Core Infrastructure
Expert en infrastructures IT avec plus de 15 ans d’expérience sur le terrain. Actuellement Chef de projet Systèmes et Réseaux et Référent SSI (Sécurité des Systèmes d’Information), je mets mon expertise au service de la fiabilité et de la sécurité des environnements technologiques.

Laisser un commentaire