A program that must survive reboot belongs under the system service manager instead of a login shell. On systemd-based Linux hosts, a custom service unit lets boot start the program before anyone logs in and gives operators normal start, stop, status, and log commands for the same workload.
A service unit under /etc/systemd/system describes the program with sections such as [Unit], [Service], and [Install]. ExecStart= names the command, Type=exec makes systemd wait until the executable is invoked, Restart=on-failure restarts the process after unexpected exits, and WantedBy=multi-user.target makes enablement attach the service to the normal multi-user boot target.
This procedure creates a system-level startup service, not a graphical desktop login item. Desktop session autostart belongs in the matching desktop environment, while a command that should run once and exit at boot normally needs Type=oneshot instead of the long-running service pattern shown here. Custom system services run as root unless the unit sets User=account-name, so use a dedicated unprivileged account when the program does not need full administrator rights.
$ sudoedit /usr/local/bin/startup-demo.sh
#!/bin/sh echo "startup-demo started" exec sleep infinity
Replace the example with the real command. Use a wrapper script only when the service needs setup before the main process starts.
$ sudo chmod 755 /usr/local/bin/startup-demo.sh
$ sudoedit /etc/systemd/system/startup-demo.service
[Unit] Description=Startup demo service [Service] Type=exec ExecStart=/usr/local/bin/startup-demo.sh Restart=on-failure [Install] WantedBy=multi-user.target
Add User=account-name under [Service] when the program should run as a dedicated non-root account.
Tool: systemd Unit Generator
$ sudo systemd-analyze verify /etc/systemd/system/startup-demo.service
No output means systemd accepted the unit syntax and referenced directives.
$ sudo systemctl daemon-reload
$ sudo systemctl enable --now startup-demo.service Created symlink /etc/systemd/system/multi-user.target.wants/startup-demo.service -> /etc/systemd/system/startup-demo.service.
--now starts the service immediately after enablement instead of waiting for the next reboot.
$ systemctl is-enabled startup-demo.service enabled
$ systemctl status --no-pager startup-demo.service
* startup-demo.service - Startup demo service
Loaded: loaded (/etc/systemd/system/startup-demo.service; enabled; preset: enabled)
Active: active (running) since Sat 2026-06-13 10:15:42 UTC; 6s ago
Main PID: 1842 (startup-demo.sh)
Tasks: 2 (limit: 4567)
Memory: 512.0K
CPU: 8ms
CGroup: /system.slice/startup-demo.service
|-1842 /bin/sh /usr/local/bin/startup-demo.sh
`-1843 sleep infinity
$ sudo journalctl -u startup-demo.service -b --no-pager Jun 13 10:15:42 host.example.net systemd[1]: Started startup-demo.service - Startup demo service. Jun 13 10:15:42 host.example.net startup-demo.sh[1842]: startup-demo started
-b limits the output to messages from the current boot.