Skip to main content

Module 15 – BONUS: System Users vs Normal Users on Linux

+==============================================================================+
| MODULE 15 (BONUS) : SYSTEM ACCOUNTS vs HUMAN ACCOUNTS |
| Estimated duration: 1-2 hours | Level: Intermediate |
+==============================================================================+

Table of Contents​

  1. Introduction
  2. The UID convention on Linux
  3. System users (service accounts)
  4. Normal users (human accounts)
  5. Create a system user with useradd -r
  6. Difference between -r and -s in useradd
  7. Real-world examples of system accounts
  8. Link with Module 14 – The wikijs_* accounts
  9. Commands to list and identify users
  10. Best practices in production
  11. Summary diagram
  12. Practical exercises

Introduction​

On Linux, not all user accounts are equal. There are two main categories:

CategoryTypical UIDRoleExample
System user (service account)< 1000Run services/daemonswww-data, mysql, nobody
Normal user (human account)≥ 1000Physical person who logs inalice, bob, student
Attention

This is not an absolute rule: it is a convention that depends on the distribution and the configuration of /etc/login.defs.

Back to the table of contents


The UID convention on Linux​

What is a UID?​

The UID (User IDentifier) is a unique number assigned to each user account. It is this number (not the name) that the Linux kernel uses to manage permissions.

UID ranges​

┌──────────────────────────────────────────────────────────────────┐
│ UID RANGES ON LINUX │
├──────────┬───────────────────────────────────────────────────────┤
│ UID 0 │ root (super-user) │
├──────────┼───────────────────────────────────────────────────────┤
│ 1-999 │ SYSTEM accounts / services / daemons │
│ │ (www-data, mysql, sshd, daemon, nobody, etc.) │
├──────────┼───────────────────────────────────────────────────────┤
│ 1000+ │ NORMAL / human accounts │
│ │ (alice, bob, student, etc.) │
├──────────┼───────────────────────────────────────────────────────┤
│ 65534 │ nobody (unprivileged user) │
└──────────┴───────────────────────────────────────────────────────┘

Where are these ranges defined?​

The /etc/login.defs file defines the official ranges on your system:

grep -E '^(UID_MIN|UID_MAX|SYS_UID_MIN|SYS_UID_MAX)' /etc/login.defs

Typical result on Ubuntu/Debian:

SYS_UID_MIN               201
SYS_UID_MAX 999
UID_MIN 1000
UID_MAX 60000

Interpretation:

  • SYS_UID_MIN (201) → SYS_UID_MAX (999): range reserved for system accounts
  • UID_MIN (1000) → UID_MAX (60000): range for human accounts
  • UID 0: always root
  • UID 1-200: often reserved for critical system accounts (depending on the distribution)

Back to the table of contents


System users (service accounts)​

Definition​

A system user (or service account) is an account created to run a service, daemon, or system component. It is not intended for a human.

Typical characteristics​

CharacteristicTypical value
UID< 1000 (often between 1 and 999)
Shell/usr/sbin/nologin or /bin/false
HomeNo home, or a technical directory (e.g., /var/www)
PasswordDisabled (locked)
Interactive loginImpossible (or not desired)

Why system users?​

  1. Principle of least privilege: each service runs with its limited permissions, not as root
  2. Isolation: if a service is compromised, the attacker only has the rights of that account
  3. Traceability: it is known which service performed which action in the logs
  4. Security: interactive login is avoided (shell nologin)

Common examples​

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
sshd:x:105:65534::/run/sshd:/usr/sbin/nologin
mysql:x:114:120:MySQL Server,,,:/nonexistent:/bin/false
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
Note

root (UID 0) is a special case: it is a system account with an interactive shell and total privileges.

Back to the table of contents


Normal users (human accounts)​

Definition​

A normal user is an account created for a physical person who logs into the system.

Typical characteristics​

CharacteristicTypical value
UID≥ 1000
Shell/bin/bash or /bin/sh
Home/home/<username>
PasswordDefined (active)
Interactive loginYes

How to create them?​

sudo useradd -m -s /bin/bash alice
id alice
Tip

The -m creates the home directory (/home/alice) and the -s /bin/bash provides an interactive shell.

Back to the table of contents


Create a system user with useradd -r​

The -r flag (system account)​

The -r flag of useradd creates a system account:

sudo useradd -r myservice

What -r does:

  • Assigns a UID in the system range (according to /etc/login.defs)
  • By default, does not create a home directory (unless -m is added)

Examples​

sudo useradd -r myservice
sudo useradd -r -m myservice
sudo useradd -r -m -s /usr/sbin/nologin myservice
sudo useradd -r -m -s /bin/bash myservice

Verification​

id myservice
getent passwd myservice

Back to the table of contents


Difference between -r and -s in useradd​

This is a fundamental distinction:

OptionRoleEffect
-rDeclares the account as systemUID in the system range
-sSets the login shellProgram launched at login

-r does not affect the shell​

sudo useradd -r svc_web

-s does not affect the account type​

sudo useradd -s /usr/sbin/nologin alice
sudo useradd -r -m -s /usr/sbin/nologin svc_web
Summary

-r = account type (system); -s = shell (login / non-login). The two are independent.

Back to the table of contents


Real-world examples of system accounts​

Apache / Nginx​

id www-data
getent passwd www-data

MySQL / MariaDB​

id mysql
getent passwd mysql

SSHD​

id sshd

Back to the table of contents


Link with Module 14 – The wikijs_* accounts​

In the Module 14 lab, we created:

sudo useradd -r -m -s /bin/bash wikijs_dev
sudo useradd -r -m -s /bin/bash wikijs_test
sudo useradd -r -m -s /bin/bash wikijs_prod

These accounts are system because we used -r.

Verification:

id wikijs_dev
id wikijs_test
id wikijs_prod

Link with systemd:

[Service]
User=wikijs_dev

Back to the table of contents


Commands to list and identify users​

1) View UID ranges​

grep -E '^(UID_MIN|UID_MAX|SYS_UID_MIN|SYS_UID_MAX)' /etc/login.defs

2) List human users (UID ≥ UID_MIN)​

UID_MIN=$(awk '/^UID_MIN/{print $2}' /etc/login.defs)
awk -F: -v m="$UID_MIN" '$3>=m {print $1" (uid="$3")"}' /etc/passwd | sort -t'=' -k2 -n

3) List system users (UID < UID_MIN)​

UID_MIN=$(awk '/^UID_MIN/{print $2}' /etc/login.defs)
awk -F: -v m="$UID_MIN" '$3<m {print $1" (uid="$3")"}' /etc/passwd | sort -t'=' -k2 -n

4) List non-login accounts (typical services)​

awk -F: '($7 ~ /(nologin|false)$/) {print $1" -> "$7}' /etc/passwd

5) List probable human accounts (home + interactive shell)​

awk -F: '($6 ~ /^\/home\//) && ($7 ~ /(bash|sh)$/) {print $1" home="$6" shell="$7}' /etc/passwd

Back to the table of contents


Best practices in production​

1) Always use -r for service accounts​

sudo useradd -r -m -s /usr/sbin/nologin my_service

2) Avoid interactive shells for services​

sudo usermod -s /usr/sbin/nologin wikijs_dev

3) Never run a service as root​

[Service]
User=www-data

Back to the table of contents


Summary diagram​

Decision flow: how to identify an account?​

Back to the table of contents


Practical exercises​

Exercise 1: identify account types (beginner)​

  1. Display UID ranges:
grep -E '^(UID_MIN|UID_MAX|SYS_UID_MIN|SYS_UID_MAX)' /etc/login.defs
  1. List system accounts:
UID_MIN=$(awk '/^UID_MIN/{print $2}' /etc/login.defs)
awk -F: -v m="$UID_MIN" '$3<m {print $1" (uid="$3")"}' /etc/passwd | sort -t'=' -k2 -n
  1. List human accounts:
UID_MIN=$(awk '/^UID_MIN/{print $2}' /etc/login.defs)
awk -F: -v m="$UID_MIN" '$3>=m {print $1" (uid="$3")"}' /etc/passwd | sort -t'=' -k2 -n

Exercise 2: create and compare accounts (intermediate)​

sudo useradd -m -s /bin/bash test_human
sudo useradd -r -m -s /usr/sbin/nologin test_service
id test_human
id test_service

Bonus lab created on: February 2026