Run a Script Before Shutdown or Reboot with systemd

Deepak Prasad
Tested on RHEL 10.2 (Coughlan) — vm1.lab.example
Package systemd 257-23.el10_2.2
Applies to Ubuntu, Debian, Kali Linux, Linux Mint, Pop!_OS, Raspberry Pi OS, elementary OS, Zorin OS, Parrot OS, MX Linux, RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora, Arch Linux
Privilege sudo or root
Scope Run a oneshot script during shutdown and reboot before shutdown.target completes and verify with a persistent log file. Does not cover shutdown-only units that skip reboot.
Related guides Run script at shutdown only not reboot
Run script at boot after network
Linux boot reboot shutdown
Create a systemd service
systemctl command

This pattern starts your script whenever the machine is shutting down, whether the final action is reboot or poweroff. Use it when you want one system-wide cleanup script during every shutdown transition — not tied to a single application service.

shutdown.target is the systemd target used while the system is transitioning toward shutdown. systemd includes your service in that transaction through WantedBy=shutdown.target.

Do not assume another service such as a database or network connection is still available. If your script depends on one particular service, it is usually better to run that cleanup as part of that service's shutdown with ExecStop= — see create a systemd service.

When you need a script only on halt and not on reboot, use shutdown-only systemd unit instead.


Create the cleanup script

Append one line to a log file on each shutdown transition:

bash
sudo tee /usr/local/sbin/before-shutdown-task.sh <<'EOF'
#!/bin/bash
LOG=/var/log/before-shutdown-task.log
echo "time=$(date -Is) shutdown_task_ran" >> "$LOG"
EOF

Make it executable:

bash
sudo chmod 755 /usr/local/sbin/before-shutdown-task.sh

Create the shutdown service

Create /etc/systemd/system/before-shutdown-task.service:

ini
[Unit]
Description=Run task before shutdown or reboot completes
DefaultDependencies=no
Before=shutdown.target

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/before-shutdown-task.sh

[Install]
WantedBy=shutdown.target

Enabling this unit makes systemd include it during the normal shutdown transaction on both reboot and poweroff.

WantedBy= decides which systemd transaction pulls the service in. Before= decides its ordering inside that transaction. Here, shutdown.target pulls it in for both reboot and poweroff, and Before=shutdown.target makes the script finish before that synchronization point.

This does not mean every other service is still running when your script starts.


Reload and enable

Reload unit definitions after editing the file:

bash
sudo systemctl daemon-reload

Enable the unit for shutdown and reboot transitions:

bash
sudo systemctl enable before-shutdown-task.service

Sample output:

output
Created symlink '/etc/systemd/system/shutdown.target.wants/before-shutdown-task.service' → '/etc/systemd/system/before-shutdown-task.service'.

Verify after reboot or poweroff

Reboot or run sudo poweroff on a test VM. After the system is back, read the log the script writes:

bash
sudo cat /var/log/before-shutdown-task.log

Sample output from lab testing:

output
time=2026-08-21T11:05:41+05:30 shutdown_task_ran
time=2026-08-21T11:13:41+05:30 shutdown_task_ran

Each line shows the unit ran during a shutdown transition. To run only on poweroff and skip reboot, use the shutdown-only guide.

If persistent journal storage is enabled on your system, you can also inspect the previous boot:

bash
journalctl -u before-shutdown-task.service -b -1 --no-pager

Troubleshooting

Symptom Likely cause Fix
Script killed mid-run Default timeout too low Set a larger TimeoutStartSec= for legitimately long cleanup
Shutdown hangs Script never exits Fix the script; avoid TimeoutStartSec=0 unless intentional
Unit never runs Not enabled to shutdown.target Re-run systemctl enable before-shutdown-task.service
Script needed on poweroff only This pattern runs on reboot too Use shutdown-only unit

References

Summary

A shutdown hook uses WantedBy=shutdown.target so systemd pulls your script into reboot and poweroff shutdown transactions, and Before=shutdown.target so the script finishes before that synchronization point. Verify with the log file under /var/log/; use journalctl -b -1 only when persistent journal storage is available.

To run only on poweroff and skip reboot, use the shutdown-only pattern in the linked guide.


Frequently Asked Questions

1. Does this run on reboot as well as poweroff?

Yes. Units hooked to shutdown.target run during both halt and reboot transitions unless you attach only to poweroff.target or halt.target instead.

2. Should I use ExecStop instead of a shutdown service?

ExecStop runs when a long-running service stops. A dedicated shutdown unit is useful when you want one system-wide script during every reboot or poweroff transition. If cleanup depends on one particular service, it is usually better to run that cleanup as part of that service shutdown with ExecStop=.

3. When should I change TimeoutStartSec=?

Use the default for short scripts. If cleanup legitimately needs more time than the configured default, set a larger TimeoutStartSec= value. Use 0 only when you intentionally want no timeout.
Omer Cakmak

Linux Administrator

Highly skilled at managing Debian, Ubuntu, CentOS, Oracle Linux, and Red Hat servers. Proficient in bash scripting, Ansible, and AWX central server management, he handles server operations on OpenStack, KVM, Proxmox, and VMware.

  • Debian
  • Ubuntu
  • Linux
  • Red Hat Enterprise Linux
  • Shell Script
  • System Administration