Introduction / Why This Is Needed
Systemd is an init system and service manager used by default in most modern Linux distributions (Ubuntu, Fedora, Debian, CentOS). Instead of scripts in /etc/init.d/, you work with declarative unit files. This approach provides powerful capabilities: dependency management, parallel startup, automatic restart of crashed processes, and centralized logging via journald.
In this guide, you will learn how to create custom systemd services to run your applications, scripts, or daemons in the background with control over their lifecycle.
Requirements / Preparation
Before you begin, ensure that:
- You have access to a Linux terminal with sudo (administrator) privileges.
- You are familiar with basic file editing commands (
nano,vim). - The path to the executable file or script you want to run as a service is known and accessible.
- Your distribution uses systemd (you can check with the
pidof systemdcommand).
Step 1: Create the Service Unit File
All custom service unit files are located in /etc/systemd/system/. The filename must end with .service and usually matches the logical service name.
# Navigate to the system directory for units
cd /etc/systemd/system/
# Create the service file (replace 'myapp' with your name)
sudo nano myapp.service
⚠️ Important: Do not create files directly in
/lib/systemd/system/— this directory is reserved for distribution packages. Your manual edits in/etc/systemd/system/will take precedence.
Step 2: Write the Unit File Configuration
A unit file consists of several sections. Here is a minimal but working template:
[Unit]
Description=My custom service
Documentation=man:myapp(1)
After=network.target
[Service]
Type=simple
User=your_user
Group=your_group
ExecStart=/full/path/to/your/script_or_binary
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Section breakdown:
[Unit]— metadata and dependencies.Description— a brief description of the service.After=— indicates that this service should start after the specified ones.network.targetis a common choice for network applications.Requires=— a hard dependency (if the specified service fails, this one will too).
[Service]— the core configuration.Type=— the service type.simple(default) — the process starts and runs in the foreground.forking— for daemons that perform afork().User=/Group=— the user and group to run the process as. It is highly recommended not to run everything as root.ExecStart=— mandatory directive. The full path to the executable file or script. The script must be executable (chmod +x script.sh).Restart=— the restart policy.on-failure— restart on non-zero exit codes.always— always restart.RestartSec=— the delay before restarting in seconds.
[Install]— instructions forsystemctl enable.WantedBy=— defines in which target state (target) the service should be enabled.multi-user.target— the standard multi-user mode (equivalent to runlevel 3/5).
💡 Tip: For simple scripts, the template above is often sufficient. For Java applications or complex environments, you may need
EnvironmentFile=(load environment variables from a file) orExecStartPre=(a command to run before starting).
Step 3: Reload the systemd Configuration
After saving the file, systemd must "see" the new unit. Run:
sudo systemctl daemon-reload
This command forces systemd to re-read all unit files from disk. Without it, systemctl will operate on the old configuration copy.
Step 4: Enable and Start the Service
Now you can activate the service.
- Enable for autostart (will create a symlink in
/etc/systemd/system/multi-user.target.wants/):sudo systemctl enable myapp.service
Output likeCreated symlink /etc/systemd/system/multi-user.target.wants/myapp.service → /etc/systemd/system/myapp.service.indicates success. - Start immediately without rebooting:
sudo systemctl start myapp.service
Step 5: Check Status and Logs
Verify that the service is running correctly.
# Primary check command
systemctl status myapp.service
What to look for in the output:
Active: active (running)— the service is alive.Loaded: loaded (/etc/systemd/system/myapp.service; enabled; vendor preset: enabled)— the file is loaded and enabled.- No red lines saying
Failedorinactive (dead).
For detailed log viewing, use journalctl:
# Show all service logs (from the beginning)
sudo journalctl -u myapp.service
# Follow logs in real time (like tail -f)
sudo journalctl -u myapp.service -f
# Show logs from the last 10 minutes
sudo journalctl -u myapp.service --since "10 minutes ago"
Common Issues
1. Failed to start... Error or Service Crashes Immediately
- Cause: An error in the application/script itself that
ExecStartruns. - Solution: Run the
ExecStartcommand manually in the terminal to see its output. Check file permissions and paths to dependent libraries/files. - Diagnosis:
journalctl -u myapp.service -n 50 --no-pagerwill show the last 50 lines of the service logs.
2. Service Does Not Enable (enable creates a symlink, but after reload status is disabled)
- Cause: The
[Install]section is missingWantedBy=orRequiredBy=, or an incorrect target is specified. - Solution: Add
WantedBy=multi-user.target(for background services) orWantedBy=graphical.target(for GUI applications). Re-rundaemon-reloadandenable.
3. Service Starts but Does Not Work as Expected (No Network/File Access)
- Cause: A security context issue. The service runs in an isolated environment.
- Solution:
- Ensure
User=andGroup=are set correctly. - Access to network ports below 1024 may require additional capabilities (
AmbientCapabilities=CAP_NET_BIND_SERVICE) or running as root (not recommended). - Check that the specified user has read/write permissions for the necessary directories.
- Ensure
4. Dependency failed for... Error
- Cause: The service has a dependency (
After=,Requires=) on another service that failed to start or does not exist. - Solution: Check the status of dependent services (
systemctl status network.targetor your_dependency.service). Ensure dependency names are spelled correctly.