Inspect running processes with ps and top, stop them with kill, and manage services with systemctl.
Why it matters
A server exists to run programs: a web server, a database, an API, a monitoring agent. An administrator needs to answer "is it running?", "why is the machine slow?" and "how do I restart it safely?" many times a day. Those questions are answered with process tools and with systemd, the service manager on almost every modern distro.
Processes
Every running program is a process with a numeric process ID (PID), an owner (a user) and a parent process that started it.
ps aux | head # every process: user, PID, CPU%, MEM%, command
ps aux | grep sshd # find one by name
pgrep -a ssh # PIDs and command lines matching a name
ps -ef --forest | less # show the parent/child tree
PID 1 is special: it is the first process the kernel starts, and on modern distros it is systemd. Everything else descends from it.
Watching live: top and htop
top
top updates every few seconds. The header shows load average (how many processes wanted CPU over the last 1, 5 and 15 minutes; compare it with the number of CPUs from nproc), memory and swap use. Inside top, press P to sort by CPU, M to sort by memory and q to quit. htop (install it with your package manager) is a friendlier version with colours and scrolling.
Stopping a process: signals
You stop a process by sending it a signal:
kill 4321 # sends SIGTERM (15): "please exit cleanly"
kill -9 4321 # sends SIGKILL (9): the kernel ends it immediately
pkill -f myscript # signal by name instead of PID
Always try plain kill first. SIGTERM lets the program save data and close files. kill -9 cannot be caught, so the program gets no chance to clean up; use it only when a process ignores SIGTERM. You can signal your own processes freely; other users' processes need sudo.
Foreground and background jobs
In an interactive shell, Ctrl+C interrupts the foreground program, Ctrl+Z pauses it, bg resumes it in the background and fg brings it back. Adding & starts a command in the background. These jobs end when you log out, which is why real services are run by systemd instead.
systemd and units
systemd starts the system at boot and supervises long-running services. Each thing it manages is a unit, described by a unit file. Service units end in .service, for example ssh.service or cron.service. Vendor unit files live in /usr/lib/systemd/system/; your local overrides go in /etc/systemd/system/.
The everyday commands:
systemctl status ssh # running? since when? main PID? last log lines
sudo systemctl start nginx # start now
sudo systemctl stop nginx # stop now
sudo systemctl restart nginx # stop then start (drops connections)
sudo systemctl reload nginx # re-read config without a full restart (if supported)
sudo systemctl enable nginx # start automatically at boot
sudo systemctl disable nginx # do not start at boot
systemctl is-active nginx # prints active / inactive
systemctl is-enabled nginx # prints enabled / disabled
systemctl list-units --type=service --state=running
systemctl --failed # units that crashed or failed to start
Two ideas people mix up: start/stop changes what is running right now; enable/disable changes what happens at the next boot. sudo systemctl enable --now nginx does both.
Reading systemctl status
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
Active: active (running) since Thu 2026-10-22 09:14:03 UTC; 2h ago
Main PID: 812 (nginx)
Tasks: 3 (limit: 4558)
Memory: 4.1M
Loaded tells you where the unit file is and whether it is enabled. Active tells you whether it is running and since when. If a service failed, the last few log lines appear underneath, which is often enough to see why.
A peek at a unit file
systemctl cat cron
[Unit]
Description=Regular background program processing daemon
[Service]
ExecStart=/usr/sbin/cron -f $EXTRA_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
ExecStart is the command systemd runs, Restart=on-failure brings it back if it crashes, and WantedBy is what enable hooks it into. After editing any unit file, run sudo systemctl daemon-reload so systemd notices.
Worked example: install and manage a web server
sudo apt install nginx # Ubuntu enables and starts it on install
systemctl status nginx
curl -I http://localhost # HTTP/1.1 200 OK
sudo systemctl stop nginx
curl -I http://localhost # connection refused
sudo systemctl start nginx
Common mistakes
- Reaching for
kill -9first. Trysystemctl stopfor services and plainkillfor processes. - Killing a service's process instead of stopping the service. With
Restart=on-failureoralways, systemd may just start it again. Usesystemctl stop. - Enabling but not starting (or starting but not enabling), then being surprised after a reboot.
- Editing a unit file and forgetting
daemon-reload. - Restarting when reload would do, which drops users' connections on a busy server.
Recap
- Every program is a process with a PID and an owner;
ps,pgrepandtopinspect them. killsends SIGTERM (clean exit);kill -9is a last resort.- systemd (PID 1) manages services as units;
systemctl start/stop/restart/reload/statuscontrols them now,enable/disablecontrols boot. systemctl --failedandsystemctl statusare the first stops when something is down.
Try it
The Do tab walks you through installing a small web server on your practice system and controlling it with systemctl.