Last modified: June 06, 2026
This article is written in: πΊπΈ
A service is a background program that provides a function to the system, users, or other programs.
Services usually run without direct user interaction. They may start automatically when the system boots, listen for network connections, process scheduled work, write logs, or respond to requests from other programs.
Common examples include:
| Service | Description |
sshd |
SSH server for remote login |
nginx |
Web server |
httpd |
Apache web server |
cron |
Scheduled task service |
mariadb |
Database server |
postgresql |
Database server |
vsftpd |
FTP server |
NetworkManager |
Network management service |
The main idea is:
Modern Linux systems commonly use systemd to manage services.
The command-line tool used to control systemd is:
systemctl
A simplified model looks like this:
+--------------------------------------------------+
| Linux Operating System |
| |
| +------------------------+ +-------------+ |
| | Service Manager | | User | |
| | systemd |<--| Commands | |
| +------------------------+ | systemctl | |
| | ^ +-------------+ |
| | | |
| start | | stop/restart/status |
| enable | | disable |
| v | |
| +------------------------+ |
| | Linux Service | |
| | | |
| | - runs in background | |
| | - performs tasks | |
| | - listens on ports | |
| | - writes logs | |
| | - responds to events | |
| +------------------------+ |
| |
+--------------------------------------------------+
The administrator uses systemctl to ask systemd to start, stop, enable, disable, restart, reload, or inspect services.
A process is a running instance of a program.
A service is a managed system function, usually represented by one or more processes.
For example:
Service:
sshd.service
Process:
PID 1234 running /usr/sbin/sshd
A service may have one process, several worker processes, or no long-running process if it is a one-shot task.
systemd unit: nginx.service
|
v
main process: nginx master
|
v
worker processes: nginx workers
So a service is not exactly the same thing as a process.
A service is the managed unit. A process is the actual running program.
A daemon is a background process that usually runs independently of direct user control.
Many daemon names end with the letter d.
Examples:
A daemon often starts during boot and keeps running until shutdown.
The word daemon describes how the program runs:
A daemon describes a background process.
A service describes a function provided to the system or users.
Example:
Daemons are often services, but not every service is a traditional daemon.
For example, a one-shot service may run once, complete a task, and exit.
systemd is a service manager and initialization system used by many modern Linux distributions.
It is responsible for:
At boot time, systemd starts the services and units needed to bring the system into a usable state.
In systemd, a unit is something systemd can manage.
Common unit types include:
A service unit usually ends in:
.service
Example:
To list active units:
systemctl list-units
To list all service units, including inactive ones:
systemctl list-units --type=service --all
A service can have several important states.
Important distinction:
For example:
That means it is running now, but will not automatically start at boot.
A service can be inactive but enabled.
Use:
systemctl status sshd.service
or sometimes, depending on distribution:
systemctl status ssh.service
Example output:
β sshd.service - OpenSSH server daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; preset: enabled)
Active: active (running) since Mon 2026-06-01 10:30:00 CEST; 5min ago
Main PID: 1234 (sshd)
Tasks: 1
Memory: 6.2M
CPU: 120ms
CGroup: /system.slice/sshd.service
ββ1234 /usr/sbin/sshd -D
Interpretation:
If a service is broken, status output often includes recent log lines.
To start a service immediately:
sudo systemctl start sshd.service
To stop it immediately:
sudo systemctl stop sshd.service
To restart it:
sudo systemctl restart sshd.service
To reload configuration without fully stopping the service, if supported:
sudo systemctl reload sshd.service
If you are not sure whether reload is supported, use:
sudo systemctl reload-or-restart sshd.service
To enable a service at boot:
sudo systemctl enable sshd.service
Example output:
Created symlink /etc/systemd/system/multi-user.target.wants/sshd.service β /usr/lib/systemd/system/sshd.service.
Interpretation:
To disable a service at boot:
sudo systemctl disable sshd.service
This prevents automatic startup, but it does not necessarily stop the service right now.
To enable and start at the same time:
sudo systemctl enable --now sshd.service
To disable and stop at the same time:
sudo systemctl disable --now sshd.service
Masking is stronger than disabling.
A disabled service can still be started manually.
A masked service cannot be started unless it is unmasked first.
Mask a service:
sudo systemctl mask service-name.service
Unmask it:
sudo systemctl unmask service-name.service
Use masking carefully. It is useful when you want to prevent a service from being started by mistake or by another dependency.
List active services:
systemctl list-units --type=service
List all services:
systemctl list-units --type=service --all
List enabled services:
systemctl list-unit-files --type=service | grep enabled
List failed services:
systemctl --failed
Example failed output:
UNIT LOAD ACTIVE SUB DESCRIPTION
myapp.service loaded failed failed My Test Service
Interpretation:
journalctlsystemd services usually log to the system journal.
To view logs for a service:
journalctl -u sshd.service
To view logs from the current boot:
journalctl -u sshd.service -b
To follow logs live:
journalctl -u sshd.service -f
To show recent lines:
journalctl -u sshd.service -n 50
Example output:
Jun 01 10:30:00 host systemd[1]: Started OpenSSH server daemon.
Jun 01 10:32:10 host sshd[1500]: Accepted publickey for adam from 192.168.1.20 port 53022
Interpretation:
Services may depend on other units.
For example, a web service may need the network to be online before it starts.
To list dependencies:
systemctl list-dependencies nginx.service
To see what depends on a service:
systemctl list-dependencies --reverse nginx.service
To check dependencies of a target:
systemctl list-dependencies multi-user.target
Example:
systemctl list-dependencies multi-user.target | grep sshd
If output appears, sshd.service is part of that dependency tree.
A target is a group of units.
Targets are similar to boot milestones.
Common targets:
To see the default target:
systemctl get-default
Example output:
graphical.target
Set default target:
sudo systemctl set-default multi-user.target
Older Linux systems may use SysV init scripts.
Common tools include:
List old init scripts:
ls /etc/init.d
Start a service using the older interface:
sudo service httpd start
Enable a service on older Red Hat-style systems:
sudo chkconfig httpd on
Modern systems often keep the service command as a compatibility layer, but systemctl is preferred on systemd systems.
The uploaded notes use vsftpd as an example service.
FTP is useful for learning service management, ports, logs, and testing, but it is usually not preferred for secure production file transfer unless configured carefully with encryption. For secure remote administration, SSH/SFTP is usually safer.
vsftpdOn Red Hat/CentOS-style systems:
sudo yum install vsftpd
or newer systems:
sudo dnf install vsftpd
On Debian/Ubuntu systems:
sudo apt install vsftpd
Check if it is installed on RPM-based systems:
rpm -qa | grep vsftpd
Example output:
vsftpd-3.0.2-29.el7.x86_64
Interpretation:
The vsftpd package is installed.
vsftpdThe configuration file is commonly:
/etc/vsftpd/vsftpd.conf
Open it:
sudo vi /etc/vsftpd/vsftpd.conf
Common options:
Meaning:
After changing configuration, restart the service:
sudo systemctl restart vsftpd.service
vsftpdStart now:
sudo systemctl start vsftpd.service
Enable at boot:
sudo systemctl enable vsftpd.service
Enable and start together:
sudo systemctl enable --now vsftpd.service
Check status:
systemctl status vsftpd.service
Example output:
β vsftpd.service - Vsftpd ftp daemon
Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; enabled; vendor preset: disabled)
Active: active (running) since Mon 2026-06-01 12:30:50 CEST; 5min ago
Interpretation:
FTP normally listens on TCP port 21.
Use ss:
sudo ss -tulnp | grep ':21'
Example output:
tcp LISTEN 0 32 0.0.0.0:21 0.0.0.0:* users:(("vsftpd",pid=1234,fd=3))
Interpretation:
Older command:
sudo netstat -tulnp | grep ftp
On modern Linux, ss is usually preferred.
Test locally:
ftp localhost
Example output:
Connected to localhost (127.0.0.1).
220 (vsFTPd 3.0.2)
Name (localhost:user):
Interpretation:
Test from another machine:
ftp SERVER_IP
If local testing works but remote testing fails, check:
Common log file:
sudo tail -f /var/log/vsftpd.log
Example output:
Mon Jun 1 12:35:15 2026 [pid 1235] CONNECT: Client "::1"
Mon Jun 1 12:35:16 2026 [pid 1235] [anonymous] OK LOGIN: Client "::1"
Mon Jun 1 12:36:20 2026 [pid 1236] [user] UPLOAD: Client "::1", "/home/user/testfile.txt"
Interpretation:
You can also use systemd logs:
journalctl -u vsftpd.service -f
A custom service is defined using a unit file.
System-level service unit files are usually stored in:
/etc/systemd/system/
A simple service file has three main sections:
[Unit] describes the service and its ordering or dependencies.
Common directives:
[Service] describes how the service runs.
Common directives:
[Install] describes how the service is enabled at boot.
Common directive:
WantedBy=multi-user.target
Create an executable script:
sudo tee /usr/local/bin/sample-service.sh > /dev/null <<'EOF'
#!/bin/bash
while true; do
echo "$(date): sample service is running"
sleep 10
done
EOF
sudo chmod +x /usr/local/bin/sample-service.sh
Create a service unit:
sudo tee /etc/systemd/system/sample.service > /dev/null <<'EOF'
[Unit]
Description=Sample Script Service
[Service]
Type=simple
ExecStart=/usr/local/bin/sample-service.sh
Restart=always
[Install]
WantedBy=multi-user.target
EOF
Reload systemd:
sudo systemctl daemon-reload
Start the service:
sudo systemctl start sample.service
Check status:
systemctl status sample.service
Example output:
β sample.service - Sample Script Service
Loaded: loaded (/etc/systemd/system/sample.service; disabled)
Active: active (running) since Mon 2026-06-01 13:00:00 CEST
Main PID: 2401 (sample-service)
Interpretation:
Enable it:
sudo systemctl enable sample.service
The Type= field controls how systemd decides whether a service has started successfully.
Common types:
For most simple scripts, use:
Type=simple
For one-time tasks, use:
Type=oneshot
Practice identifying when a service is installed but not running.
Use the sample service or another safe test service:
sudo systemctl stop sample.service
systemctl status sample.service
Example output:
β sample.service - Sample Script Service
Loaded: loaded (/etc/systemd/system/sample.service; enabled)
Active: inactive (dead)
Interpretation:
sudo systemctl start sample.service
Verify:
systemctl status sample.service
Expected:
Active: active (running)
Understand the difference between stopped and disabled.
sudo systemctl disable sample.service
Check:
systemctl is-enabled sample.service
Example output:
disabled
The service may still be running.
Check:
systemctl is-active sample.service
Example output:
active
Interpretation:
sudo systemctl enable sample.service
Or enable and start:
sudo systemctl enable --now sample.service
Practice diagnosing a failed custom service.
Create a broken unit:
sudo tee /etc/systemd/system/broken.service > /dev/null <<'EOF'
[Unit]
Description=Broken Service Example
[Service]
Type=simple
ExecStart=/not/a/real/path
[Install]
WantedBy=multi-user.target
EOF
Reload and start:
sudo systemctl daemon-reload
sudo systemctl start broken.service
systemctl status broken.service
Example output:
β broken.service - Broken Service Example
Loaded: loaded (/etc/systemd/system/broken.service; disabled)
Active: failed (Result: exit-code)
Process: 2500 ExecStart=/not/a/real/path (code=exited, status=203/EXEC)
Interpretation:
journalctl -u broken.service -b
Example output:
systemd[1]: broken.service: Failed to locate executable /not/a/real/path
systemd[1]: broken.service: Failed at step EXEC spawning /not/a/real/path: No such file or directory
Edit the unit:
sudo systemctl edit --full broken.service
Set a valid executable path.
Then reload and restart:
sudo systemctl daemon-reload
sudo systemctl restart broken.service
Show how Restart= affects service behavior.
sudo tee /usr/local/bin/crash-service.sh > /dev/null <<'EOF'
#!/bin/bash
echo "crash service started"
sleep 2
echo "crash service exiting with error"
exit 1
EOF
sudo chmod +x /usr/local/bin/crash-service.sh
Create the unit:
sudo tee /etc/systemd/system/crash.service > /dev/null <<'EOF'
[Unit]
Description=Crash Test Service
[Service]
Type=simple
ExecStart=/usr/local/bin/crash-service.sh
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
EOF
Start it:
sudo systemctl daemon-reload
sudo systemctl start crash.service
systemctl status crash.service
Example output:
β crash.service - Crash Test Service
Loaded: loaded (/etc/systemd/system/crash.service; disabled)
Active: activating (auto-restart) (Result: exit-code)
Process: 2701 ExecStart=/usr/local/bin/crash-service.sh (code=exited, status=1/FAILURE)
Interpretation:
journalctl -u crash.service -f
Example output:
crash-service.sh[2701]: crash service started
crash-service.sh[2701]: crash service exiting with error
systemd[1]: crash.service: Main process exited, code=exited, status=1/FAILURE
systemd[1]: crash.service: Scheduled restart job, restart counter is at 3.
Fix the script or change restart policy.
Stop the test:
sudo systemctl stop crash.service
Understand why a network service may fail to start when its port is already in use.
Start a temporary listener on port 8080:
python3 -m http.server 8080
In another terminal, check the port:
ss -tulnp | grep ':8080'
Example output:
tcp LISTEN 0 5 0.0.0.0:8080 0.0.0.0:* users:(("python3",pid=3001,fd=3))
Now start another service configured to use the same port.
Example failure log may look like:
Address already in use
Failed to bind to 0.0.0.0:8080
Interpretation:
Find and stop the conflicting process:
sudo ss -tulnp | grep ':8080'
sudo kill 3001
Or configure one service to use a different port.
Practice checking service logs after a bad configuration change.
For a real service like nginx, a bad config might cause restart failure.
For a safer custom example, create a script that exits when a config file contains bad.
sudo tee /usr/local/bin/config-check-service.sh > /dev/null <<'EOF'
#!/bin/bash
if grep -q bad /etc/config-check-service.conf; then
echo "Bad configuration found"
exit 1
fi
echo "Configuration OK"
sleep infinity
EOF
sudo chmod +x /usr/local/bin/config-check-service.sh
echo "bad=true" | sudo tee /etc/config-check-service.conf
Create service:
sudo tee /etc/systemd/system/config-check.service > /dev/null <<'EOF'
[Unit]
Description=Config Check Service
[Service]
Type=simple
ExecStart=/usr/local/bin/config-check-service.sh
[Install]
WantedBy=multi-user.target
EOF
Start it:
sudo systemctl daemon-reload
sudo systemctl start config-check.service
systemctl status config-check.service
Example output:
Active: failed (Result: exit-code)
Process: 3100 ExecStart=/usr/local/bin/config-check-service.sh (code=exited, status=1/FAILURE)
journalctl -u config-check.service -b
Example output:
config-check-service.sh[3100]: Bad configuration found
Interpretation:
echo "good=true" | sudo tee /etc/config-check-service.conf
sudo systemctl restart config-check.service
Understand service ordering with After= and Wants=.
Suppose a service needs the network before starting.
A unit may include:
[Unit]
Description=Network Dependent App
Wants=network-online.target
After=network-online.target
Meaning:
systemctl list-dependencies network-online.target
Check reverse dependencies:
systemctl list-dependencies --reverse network-online.target
Interpretation:
Important note:
Understand failed state and how to clear it.
Use the broken service:
sudo systemctl start broken.service
Check failed services:
systemctl --failed
Example output:
UNIT LOAD ACTIVE SUB DESCRIPTION
broken.service loaded failed failed Broken Service Example
Interpretation:
sudo systemctl reset-failed broken.service
Check again:
systemctl --failed
Expected output:
0 loaded units listed.
Understand why a service may refuse to start even though it exists.
sudo systemctl mask sample.service
Try to start it:
sudo systemctl start sample.service
Example output:
Failed to start sample.service: Unit sample.service is masked.
Interpretation:
sudo systemctl unmask sample.service
sudo systemctl start sample.service
Use service monitoring tools to identify a resource-heavy service.
sudo tee /usr/local/bin/cpu-service.sh > /dev/null <<'EOF'
#!/bin/bash
while true; do
:
done
EOF
sudo chmod +x /usr/local/bin/cpu-service.sh
Create unit:
sudo tee /etc/systemd/system/cpu-test.service > /dev/null <<'EOF'
[Unit]
Description=CPU Test Service
[Service]
Type=simple
ExecStart=/usr/local/bin/cpu-service.sh
[Install]
WantedBy=multi-user.target
EOF
Start:
sudo systemctl daemon-reload
sudo systemctl start cpu-test.service
systemctl statussystemctl status cpu-test.service
Example output:
β cpu-test.service - CPU Test Service
Active: active (running)
Main PID: 3500 (cpu-service.sh)
Tasks: 1
CPU: 1min 20s
toptop -p 3500
Example output:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3500 root 20 0 4000 900 800 R 99.9 0.0 1:20 cpu-service.sh
Interpretation:
Stop the test service:
sudo systemctl stop cpu-test.service
For real services, investigate configuration, loops, workload spikes, or bugs.
Understand services that run once and exit successfully.
Create script:
sudo tee /usr/local/bin/oneshot-task.sh > /dev/null <<'EOF'
#!/bin/bash
echo "$(date): oneshot task ran" >> /var/log/oneshot-task.log
EOF
sudo chmod +x /usr/local/bin/oneshot-task.sh
Create unit:
sudo tee /etc/systemd/system/oneshot-task.service > /dev/null <<'EOF'
[Unit]
Description=One Shot Task Example
[Service]
Type=oneshot
ExecStart=/usr/local/bin/oneshot-task.sh
[Install]
WantedBy=multi-user.target
EOF
Run:
sudo systemctl daemon-reload
sudo systemctl start oneshot-task.service
Check status:
systemctl status oneshot-task.service
Example output:
Active: inactive (dead)
Process: 3600 ExecStart=/usr/local/bin/oneshot-task.sh (code=exited, status=0/SUCCESS)
Interpretation:
Understand systemd timers as an alternative to cron.
A timer activates a service on a schedule.
Create a timer for the one-shot task:
sudo tee /etc/systemd/system/oneshot-task.timer > /dev/null <<'EOF'
[Unit]
Description=Run oneshot task every minute
[Timer]
OnCalendar=*:0/1
Persistent=true
[Install]
WantedBy=timers.target
EOF
Reload and start timer:
sudo systemctl daemon-reload
sudo systemctl enable --now oneshot-task.timer
List timers:
systemctl list-timers --all
Example output:
NEXT LEFT LAST PASSED UNIT ACTIVATES
Mon 2026-06-01 14:01:00 30s Mon 2026-06-01 14:00:00 30s oneshot-task.timer oneshot-task.service
Interpretation:
When a service is not working, troubleshoot in layers.
systemctl status service-name.service
If output says:
Unit service-name.service could not be found.
then the package may not be installed, or the unit name may be wrong.
Search unit files:
systemctl list-unit-files | grep service-name
systemctl is-active service-name.service
Possible output:
systemctl is-enabled service-name.service
Possible output:
systemctl status service-name.service
Look for:
journalctl -u service-name.service -b
Follow logs:
journalctl -u service-name.service -f
For network services:
sudo ss -tulnp
Example:
sudo ss -tulnp | grep ':80'
This helps answer:
ps -ef | grep service-name
or use systemdβs process tree:
systemctl status service-name.service
Many services have a built-in config test.
Examples:
sudo nginx -t
sudo apachectl configtest
sudo sshd -t
If available, always test configuration before restarting production services.
Example:
Unit nginx.service could not be found.
Possible causes:
Fix:
sudo systemctl daemon-reload
systemctl list-unit-files | grep nginx
Check:
systemctl status service-name.service
journalctl -u service-name.service -b
Common causes:
Check:
systemctl status service-name.service
sudo ss -tulnp
journalctl -u service-name.service -b
Possible causes:
Check:
systemctl is-enabled service-name.service
systemctl status service-name.service
If disabled:
sudo systemctl enable service-name.service
If enabled but still fails at boot, check:
journalctl -u service-name.service -b
systemctl list-dependencies service-name.service
Possible causes:
Check:
systemctl status service-name.service
journalctl -u service-name.service -b
Look for:
Possible causes:
Service state:
systemctl status service.service
systemctl is-active service.service
systemctl is-enabled service.service
systemctl --failed
Start and stop:
sudo systemctl start service.service
sudo systemctl stop service.service
sudo systemctl restart service.service
sudo systemctl reload service.service
sudo systemctl reload-or-restart service.service
Boot behavior:
sudo systemctl enable service.service
sudo systemctl disable service.service
sudo systemctl enable --now service.service
sudo systemctl disable --now service.service
Masking:
sudo systemctl mask service.service
sudo systemctl unmask service.service
Listing:
systemctl list-units --type=service
systemctl list-units --type=service --all
systemctl list-unit-files --type=service
systemctl list-timers --all
Logs:
journalctl -u service.service
journalctl -u service.service -b
journalctl -u service.service -f
journalctl -u service.service -n 50
Dependencies:
systemctl list-dependencies service.service
systemctl list-dependencies --reverse service.service
Ports and processes:
sudo ss -tulnp
ps -ef | grep service-name
Custom units:
sudo systemctl daemon-reload
sudo systemctl edit --full service.service
sudo systemctl reset-failed service.service
If you created the sample services, clean them up:
sudo systemctl stop sample.service broken.service crash.service config-check.service cpu-test.service oneshot-task.timer oneshot-task.service 2>/dev/null
sudo systemctl disable sample.service broken.service crash.service config-check.service cpu-test.service oneshot-task.timer oneshot-task.service 2>/dev/null
sudo rm -f /etc/systemd/system/sample.service
sudo rm -f /etc/systemd/system/broken.service
sudo rm -f /etc/systemd/system/crash.service
sudo rm -f /etc/systemd/system/config-check.service
sudo rm -f /etc/systemd/system/cpu-test.service
sudo rm -f /etc/systemd/system/oneshot-task.service
sudo rm -f /etc/systemd/system/oneshot-task.timer
sudo rm -f /usr/local/bin/sample-service.sh
sudo rm -f /usr/local/bin/crash-service.sh
sudo rm -f /usr/local/bin/config-check-service.sh
sudo rm -f /usr/local/bin/cpu-service.sh
sudo rm -f /usr/local/bin/oneshot-task.sh
sudo rm -f /etc/config-check-service.conf
sudo systemctl daemon-reload
sudo systemctl reset-failed
systemctl list-units --type=service --all to list active and inactive services. Pick five services and explain what each one does.systemctl status, systemctl is-active, and systemctl is-enabled. Explain the difference between active and enabled.journalctl -u service-name -b to inspect logs for a service. Identify when it started and whether it produced errors.vsftpd, nginx, or openssh-server on a lab machine. Verify that it is running and listening on the expected port.ss -tulnp to identify which services are listening on network ports.ExecStart. Start it, inspect the failure, fix it, and restart it.systemctl list-timers --all to verify the schedule.sshd, nginx, and a one-shot backup task.