🔧 Lesson 6.3: Services and systemctl
Your system runs dozens of background services. Learn to control them like a pro.
🎯 Learning Objectives
- Understand what services (daemons) are and why they matter
- Start, stop, restart, and check the status of services with
systemctl - Enable and disable services at boot
- View service logs with
journalctl - Create a simple custom service
Estimated Time: 40 minutes
📑 In This Lesson
What Are Services?
A service (also called a daemon) is a program that runs in the background — no terminal window, no user interaction. Services start when your computer boots and keep running silently, handling essential tasks.
Common examples:
- ssh (sshd) — listens for incoming SSH connections
- apache2 / nginx — web servers
- NetworkManager — manages your network connections
- cron — runs scheduled tasks
- cups — manages printers
- ufw — the firewall
🐧 Why "Daemon"?
The term comes from Greek mythology — a daemon is a supernatural being that works in the background. In Unix tradition, daemon processes are named with a trailing "d": sshd, httpd, crond.
systemd — The Service Manager
systemd is the init system and service manager used by Ubuntu (and most modern Linux distros). It's the very first process that runs (PID 1) and manages all other services.
You interact with systemd through the systemctl command (system control). The basic pattern is always:
sudo systemctl [action] [service-name]
💡 Unit Files
systemd uses unit files to define services — configuration files that describe how to start, stop, and manage a service. They live in /etc/systemd/system/ (custom) and /lib/systemd/system/ (package-provided). You'll see an example later in this lesson.
Checking Service Status
# Full status report for a service
sudo systemctl status ssh
# Quick check — is it running?
systemctl is-active ssh
# Quick check — is it enabled at boot?
systemctl is-enabled ssh
Example systemctl status Output
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled; preset: enabled)
Active: active (running) since Mon 2026-04-14 09:00:15 PDT; 5h ago
Docs: man:sshd(8)
Main PID: 892 (sshd)
Tasks: 1 (limit: 18845)
Memory: 5.3M
CPU: 85ms
CGroup: /system.slice/ssh.service
└─892 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
Apr 14 09:00:15 ray-desktop systemd[1]: Started OpenBSD Secure Shell server.
Key things to look at:
- Active —
active (running)means it's working;inactive (dead)means it's stopped;failedmeans something went wrong - Loaded — shows the unit file path and whether it's enabled (starts at boot) or disabled
- Main PID — the process ID of the service
- Log lines — the most recent log entries at the bottom
Starting, Stopping, and Restarting
# Start a stopped service
sudo systemctl start ssh
# Stop a running service
sudo systemctl stop ssh
# Restart a service (stop + start)
sudo systemctl restart ssh
# Reload configuration without fully restarting
# (only works if the service supports it)
sudo systemctl reload ssh
# Reload if supported, otherwise restart
sudo systemctl reload-or-restart ssh
(inactive)"] -->|"start"| B["Running
(active)"] B -->|"stop"| A B -->|"restart"| B B -->|"reload"| C["Running
(new config)"] style A fill:#ef4444,stroke:#b91c1c,color:#fff style B fill:#22c55e,stroke:#166534,color:#fff style C fill:#3b82f6,stroke:#2563eb,color:#fff
💡 restart vs reload
restart fully stops and starts the service — there's a brief moment of downtime. reload tells the service to re-read its configuration without stopping, so there's no interruption. Not all services support reload — use reload-or-restart to safely handle both cases.
Enable and Disable at Boot
Starting a service makes it run now. Enabling a service makes it start automatically on every boot. These are separate actions.
# Enable a service to start at boot
sudo systemctl enable ssh
# Disable a service from starting at boot
sudo systemctl disable ssh
# Enable AND start immediately (convenient combo)
sudo systemctl enable --now ssh
# Disable AND stop immediately
sudo systemctl disable --now ssh
# Prevent a service from being started at all (even manually)
sudo systemctl mask ssh
# Undo a mask
sudo systemctl unmask ssh
| Action | Runs Now? | Starts at Boot? |
|---|---|---|
start | ✅ Yes | Unchanged |
stop | ❌ Stops | Unchanged |
enable | Unchanged | ✅ Yes |
disable | Unchanged | ❌ No |
enable --now | ✅ Yes | ✅ Yes |
disable --now | ❌ Stops | ❌ No |
mask | Prevents | Prevents |
⚠️ mask Is Serious
Masking a service links its unit file to /dev/null, making it impossible to start — even manually. Use this for services you never want running (maybe a service that conflicts with another). Remember to unmask if you change your mind.
Listing All Services
# List all loaded services and their states
systemctl list-units --type=service
# List ALL services (including inactive/disabled)
systemctl list-units --type=service --all
# List only running services
systemctl list-units --type=service --state=running
# List only failed services (great for troubleshooting!)
systemctl list-units --type=service --state=failed
# List enabled services (those that start at boot)
systemctl list-unit-files --type=service --state=enabled
💡 How Many Services Are Running?
# Count running services
systemctl list-units --type=service --state=running --no-pager | grep -c ".service"
A typical Ubuntu desktop runs 50-80+ services. Most are small and use minimal resources.
Viewing Service Logs
systemd captures log output from every service through journalctl. No more hunting through random log files in /var/log/.
# View logs for a specific service
journalctl -u ssh.service
# Show only the most recent entries
journalctl -u ssh.service -n 50
# Follow logs in real time (like tail -f)
journalctl -u ssh.service -f
# Show logs since a specific time
journalctl -u ssh.service --since "2026-04-14 09:00"
journalctl -u ssh.service --since "1 hour ago"
# Show only error messages
journalctl -u ssh.service -p err
# Show logs from the current boot
journalctl -u ssh.service -b
# How much disk space are logs using?
journalctl --disk-usage
# Clean old logs (keep only last 7 days)
sudo journalctl --vacuum-time=7d
🐧 Log Priority Levels
| Level | Flag | Meaning |
|---|---|---|
| 0 | emerg | System is unusable |
| 1 | alert | Immediate action required |
| 2 | crit | Critical conditions |
| 3 | err | Error conditions |
| 4 | warning | Warning conditions |
| 5 | notice | Normal but significant |
| 6 | info | Informational |
| 7 | debug | Debug-level messages |
Use -p err to show only errors and above (err, crit, alert, emerg).
Creating a Custom Service
You can turn any script or program into a managed service. Here's a simple example:
Step 1: Create a Script
# Create a simple script
sudo nano /usr/local/bin/hello-service.sh
#!/bin/bash
# A simple service that logs a message every 30 seconds
while true; do
echo "Hello from my custom service! $(date)"
sleep 30
done
# Make it executable
sudo chmod +x /usr/local/bin/hello-service.sh
Step 2: Create a Unit File
sudo nano /etc/systemd/system/hello.service
[Unit]
Description=Hello World Demo Service
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/hello-service.sh
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
Step 3: Load, Start, and Enable
# Tell systemd about the new unit file
sudo systemctl daemon-reload
# Start the service
sudo systemctl start hello.service
# Check it's running
sudo systemctl status hello.service
# View its logs
journalctl -u hello.service -f
# Enable it to start at boot (optional)
sudo systemctl enable hello.service
# When done experimenting, stop and clean up:
sudo systemctl stop hello.service
sudo systemctl disable hello.service
sudo rm /etc/systemd/system/hello.service
sudo rm /usr/local/bin/hello-service.sh
sudo systemctl daemon-reload
💡 Unit File Sections Explained
- [Unit] — metadata and dependencies.
After=network.targetmeans "start after the network is up" - [Service] — how to run the service.
Restart=on-failureauto-restarts if it crashes - [Install] — when to start.
WantedBy=multi-user.targetmeans "start in normal (non-graphical) mode and above"
⚠️ Always daemon-reload After Changes
Whenever you create, modify, or delete a unit file, run sudo systemctl daemon-reload so systemd picks up the changes. Forgetting this is the #1 source of "my changes aren't taking effect" confusion.
Exercises
🏋️ Exercise 1: Explore Your Services
- List running services:
systemctl list-units --type=service --state=running - Count them:
systemctl list-units --type=service --state=running --no-pager | grep -c ".service" - Check for failed services:
systemctl list-units --type=service --state=failed - List services that start at boot:
systemctl list-unit-files --type=service --state=enabled
🏋️ Exercise 2: Inspect a Service
- Check cron's status:
sudo systemctl status cron - Is it enabled?
systemctl is-enabled cron - View its recent logs:
journalctl -u cron -n 20 - View its unit file:
systemctl cat cron
🏋️ Exercise 3: Start/Stop Practice
Practice with the cron service (safe to restart — it just runs scheduled tasks):
# Check status
sudo systemctl status cron
# Stop it
sudo systemctl stop cron
# Verify it stopped
systemctl is-active cron
# Start it back up
sudo systemctl start cron
# Restart it (stop + start in one command)
sudo systemctl restart cron
# Verify it's running
sudo systemctl status cron
🏋️ Exercise 4: Create Your Own Service
Follow the "Creating a Custom Service" section above to:
- Create the script at
/usr/local/bin/hello-service.sh - Create the unit file at
/etc/systemd/system/hello.service - Reload, start, and check status
- Watch the logs:
journalctl -u hello.service -f - Clean up when done (stop, disable, remove files, daemon-reload)
Knowledge Check
❓ Question 1
What's the difference between start and enable?
❓ Question 2
When must you run sudo systemctl daemon-reload?
❓ Question 3
How do you view real-time logs for the SSH service?
❓ Question 4
What does systemctl mask do that disable doesn't?
Summary
🎉 Key Takeaways
- Services (daemons) are background processes managed by
systemd systemctl status,start,stop,restartcontrol services right nowsystemctl enable/disablecontrol whether services start at bootenable --nowis the convenient combo (enable + start in one command)journalctl -u service-nameshows service logs; add-fto follow live- Always run
daemon-reloadafter changing unit files - You can create custom services with a simple script + unit file
🍎 On macOS
macOS does not use systemd or systemctl. Instead, it uses launchctl with .plist files (XML) to manage services (called "launch daemons" and "launch agents"). The concepts are similar — start, stop, enable at boot — but the commands are different:
sudo launchctl list— list running servicessudo launchctl load /path/to/plist— start/enable a servicesudo launchctl unload /path/to/plist— stop/disable a service- Service definitions live in
/Library/LaunchDaemons/(system-wide) and~/Library/LaunchAgents/(per-user)
If you installed services via Homebrew, use brew services list, brew services start, and brew services stop for a friendlier interface.
🎉 Module 6 Complete!
You can now manage processes, check your system's health, and control services — the essential skills of a Linux administrator. You're well on your way to being comfortable with any Linux system.
🚀 What's Next?
Module 7 takes you into Networking and SSH — connecting to other machines, transferring files, and securing remote access.