Servers rarely have a human sitting in front of them waiting to type commands after every reboot. A production web server, database, or mail server needs to come back online automatically after a power outage, kernel update, or scheduled reboot — without any manual intervention. This is what automatic service management is for.
In this article, we explain from first principles how Linux automatically starts and stops services, focusing on the modern systemd init system (used by most major distributions today), while also covering legacy init.d/SysVinit concepts so you understand older systems too.
What Is a “Service” in Linux?
A service (sometimes called a daemon) is a background program that runs without direct user interaction — for example, sshd (the SSH server), nginx (a web server), mysqld (a database server), or cron (the task scheduler). Services typically:
- Start automatically at boot (if enabled)
- Run continuously in the background
- Log their activity to system logs
- Can be stopped, started, restarted, or reloaded on demand
flowchart TD
A[System Powers On] --> B[Kernel Loads]
B --> C[systemd - PID 1 - Starts]
C --> D{Unit Enabled?}
D -->|Yes| E[Service Starts Automatically]
D -->|No| F[Service Stays Inactive]
E --> G[Service Running in Background]systemd: The Modern Init System
Most modern Linux distributions (Ubuntu, Debian, RHEL/CentOS 7+, Fedora, openSUSE) use systemd as PID 1 — the very first process the kernel starts, responsible for starting every other process, including services.
systemd manages services through unit files, which describe how to start, stop, and supervise a piece of software.
Enabling a Service to Start Automatically at Boot
sudo systemctl enable nginxThis creates a symbolic link from the service’s unit file into the appropriate target’s .wants directory, telling systemd to start it during the relevant boot stage.
Disabling Automatic Start
sudo systemctl disable nginxThis removes the symlink, so the service will no longer start automatically — but it doesn’t stop it if it’s currently running.
Enabling AND Starting Immediately
sudo systemctl enable --now nginxThe --now flag both enables the service for future boots and starts it right away.
Checking Whether a Service Is Enabled
systemctl is-enabled nginxUnderstanding systemd Targets (Run Level Equivalents)
systemd uses targets instead of the old SysVinit “run levels” to represent system states. Common targets include:
| systemd Target | Roughly Equivalent SysVinit Run Level | Meaning |
|---|---|---|
poweroff.target | 0 | System shutdown |
rescue.target | 1 | Single-user/maintenance mode |
multi-user.target | 3 | Full multi-user mode, no GUI |
graphical.target | 5 | Multi-user mode with GUI |
reboot.target | 6 | System reboot |
A service enabled for multi-user.target will automatically start whenever the system reaches that target during boot.
Writing a Simple systemd Unit File
Suppose you have a custom Python application you want to run as a service. Create a unit file at /etc/systemd/system/myapp.service:
[Unit]
Description=My Custom Python Application
After=network.target
[Service]
ExecStart=/usr/bin/python3 /opt/myapp/app.py
Restart=on-failure
User=myappuser
WorkingDirectory=/opt/myapp
[Install]
WantedBy=multi-user.target
Explanation:
[Unit]— metadata and dependency info (After=network.targetensures networking is up first)[Service]— how to run and supervise the program, including automatic restart behavior[Install]— defines which target enables this service
After creating or editing a unit file, always reload systemd’s configuration cache:
sudo systemctl daemon-reload
sudo systemctl enable --now myappAutomatically Stopping Services
Sometimes you want a service to stop automatically under certain conditions — for example, stopping cleanly on shutdown (which systemd handles automatically for enabled services), or stopping a service after a scheduled task completes.
Using systemd Timers to Stop a Service on a Schedule
Create a timer unit /etc/systemd/system/myapp-stop.timer:
[Unit]
Description=Stop myapp every night at 2 AM
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
And a matching service that just stops the target service:
[Unit]
Description=Stops myapp
[Service]
Type=oneshot
ExecStart=/usr/bin/systemctl stop myappEnable the timer:
sudo systemctl enable --now myapp-stop.timerLegacy Systems: SysVinit and init.d
Older systems (and some embedded distributions) still use SysVinit, where services are controlled through scripts in /etc/init.d/:
sudo /etc/init.d/apache2 start
sudo /etc/init.d/apache2 stopAutomatic startup was managed with update-rc.d (Debian) or chkconfig (RHEL):
sudo update-rc.d apache2 defaults # Debian/Ubuntu
sudo chkconfig apache2 on # RHEL/CentOSEven on modern systemd-based distributions, systemd provides a compatibility layer so old init.d scripts often still work, though native unit files are strongly preferred.
Comparison: systemd vs. SysVinit
| Feature | systemd | SysVinit (init.d) |
|---|---|---|
| Startup speed | Fast (parallel startup) | Slower (sequential startup) |
| Configuration format | Declarative unit files (.service) | Shell scripts |
| Dependency management | Built-in, explicit (After=, Requires=) | Manual, via script ordering/numbering |
| Logging | Centralized via journald | Varies per service |
| Modern distro support | Default on nearly all major distros | Legacy/embedded systems |
| Enable/disable command | systemctl enable/disable | update-rc.d / chkconfig |
A Practical Example: Auto-Starting a Database Server
Step 1: Install MySQL/MariaDB
sudo apt install mariadb-serverStep 2: Enable it to start on boot
sudo systemctl enable mariadbStep 3: Start it now
sudo systemctl start mariadbStep 4: Verify
systemctl status mariadb
systemctl is-enabled mariadbStep 5: Test that it survives a reboot
sudo reboot
# after reboot:
systemctl status mariadbReal-World Use Case: Auto-Restart on Crash
Production services should recover automatically from crashes without waiting for a human. In the unit file:
[Service]
Restart=always
RestartSec=5This tells systemd to restart the service 5 seconds after any failure, indefinitely — critical for services like web application backends that must stay available.
Best Practices
- Always use
daemon-reloadafter creating or editing unit files, orsystemdwon’t see your changes. - Use
enable --nowto avoid forgetting to start a service you just enabled (or vice versa). - Set
Restart=on-failureorRestart=alwaysfor critical services so they self-heal from crashes. - Use
After=andRequires=to correctly order dependencies (e.g., a web app should start after networking and its database). - Avoid editing vendor unit files directly — use
systemctl edit servicenameto create an override drop-in file instead, which survives package upgrades. - Regularly audit enabled services with
systemctl list-unit-files --state=enabledto ensure only necessary services start automatically (reduces attack surface).
Troubleshooting
Problem: Service doesn’t start automatically after reboot
Check whether it’s actually enabled:
systemctl is-enabled myappIf it says disabled, run:
sudo systemctl enable myappProblem: Failed to start myapp.service: Unit not found
The unit file may be missing, misnamed, or not reloaded:
sudo systemctl daemon-reload
systemctl status myappProblem: Service starts but immediately stops (crash loop)
Check logs for the actual error:
journalctl -u myapp -n 100 --no-pagerProblem: Service starts too early, before its dependency (e.g., network) is ready
Add explicit ordering in the unit file:
[Unit]
After=network-online.target
Wants=network-online.targetProblem: Changes to a unit file don’t seem to take effect
Always run daemon-reload after any edit, and restart the service itself:
sudo systemctl daemon-reload
sudo systemctl restart myappConclusion
Automatic service management is what keeps Linux servers reliable, self-healing, and hands-off. With systemd, enabling a service to survive reboots is as simple as systemctl enable --now servicename, while unit files give you fine-grained control over dependencies, restart behavior, and scheduling through timers. Understanding both the modern systemd approach and the legacy SysVinit model ensures you can manage services confidently on any Linux system you encounter, from a fresh cloud VM to a decade-old production server.
