Process Management

beginner linux processes systemd signals

Every running program on Linux is a process. Understanding how to view, control, and kill processes is essential for any server work.

Processes vs Threads

A process is an independent program with its own memory space. A thread is a lightweight unit of execution inside a process that shares memory with other threads in the same process.

When we run node server.js, that’s one process. If Node spawns worker threads internally, those are threads within that process.

Process States

Linux Process Lifecycle
Created
fork/exec
Ready
waiting for CPU
Running
executing on CPU
Terminated
exit / killed
Sleeping / Waiting
waiting for I/O or event
↕ swaps with Running when I/O completes

A zombie process is one that finished but its parent hasn’t read its exit status yet. They’re harmless in small numbers but can pile up if the parent is buggy.

Viewing Processes

ps aux                      # list ALL processes with details
ps aux | grep nginx         # find a specific process
top                         # real-time process monitor (press q to quit)
htop                        # better version of top (install: apt install htop)
pgrep -f "node server"     # get PID of a process by name

In ps aux output, the columns we care about most: USER, PID, %CPU, %MEM, and COMMAND.

Killing Processes

Every process has a PID (process ID). We use kill to send signals to a process.

kill 1234              # send SIGTERM (graceful shutdown — "please stop")
kill -9 1234           # send SIGKILL (force kill — "stop NOW, no cleanup")
kill -HUP 1234         # send SIGHUP (reload config without restart)
killall nginx          # kill all processes named "nginx"
pkill -f "node app"    # kill processes matching a pattern

The key difference: SIGTERM (15) lets the process clean up (close connections, save state). SIGKILL (9) is instant death — the process can’t catch or ignore it. Always try SIGTERM first.

Foreground and Background

./long_task.sh         # runs in foreground (blocks terminal)
./long_task.sh &       # runs in background (terminal stays usable)
jobs                   # list background jobs in current shell
fg %1                  # bring job 1 back to foreground
bg %1                  # resume a stopped job in background
# Ctrl+Z              # pause (stop) a foreground process

nohup keeps a process running even after we close the terminal.

nohup ./deploy.sh &              # runs in background, survives logout
nohup ./deploy.sh > deploy.log 2>&1 &  # with custom log file

systemd — The Service Manager

Modern Linux uses systemd to manage services (daemons). Think of it as the boss that starts, stops, and babysits our services.

systemctl start nginx      # start a service
systemctl stop nginx       # stop a service
systemctl restart nginx    # stop + start
systemctl reload nginx     # reload config without downtime
systemctl status nginx     # check if it's running + recent logs
systemctl enable nginx     # start automatically on boot
systemctl disable nginx    # don't start on boot
systemctl list-units --type=service  # list all services

Checking Logs with journalctl

systemd captures logs from all services. journalctl is how we read them.

journalctl -u nginx              # logs for a specific service
journalctl -u nginx --since "1 hour ago"  # recent logs only
journalctl -u nginx -f           # follow logs in real-time (like tail -f)
journalctl -u nginx --no-pager   # dump all without paging

In simple language, processes are just programs doing their thing. We can watch them (ps, top), talk to them (kill signals), and let systemd babysit them so they stay running.