Linux Operating Systems Fundamentals · Lesson 7
Administering the System
User and group accounts, MTA basics and local mail, rsyslog and systemd-journald logging, and maintaining system time with hwclock, timedatectl, ntpd, and chrony.
Lesson purpose
Keeping servers healthy is routine, careful work: create and retire accounts correctly, keep system mail flowing, record what happens in logs and read them, and keep every clock accurate. This lesson covers user and group administration and the files behind it, basic mail transfer agent (MTA) administration, logging with rsyslog and systemd-journald, and keeping time with hardware and software clocks and NTP (ntpd and chrony).
Learning objectives
- Explain how
/etc/login.defs,/etc/default/useradd, and/etc/skelshape account creation, and read the records in/etc/passwd,/etc/shadow,/etc/group, and/etc/gshadow. - Create, modify, lock, and delete accounts and groups with
useradd,passwd,chage,usermod,userdel,groupadd,groupmod, andgroupdel. - Describe the MTA, MDA, and MUA roles; send and read local mail; inspect the mail queue; and configure aliases and forwarding.
- Write rsyslog rules using facilities, priorities, and actions; forward logs to a central server; rotate logs; and create log entries.
- Configure, view, filter, persist, and maintain the systemd journal.
- Manage the hardware and software clocks and synchronize time with NTP using ntpd or chrony.
LPIC-1 exam focus
- 107.1 Manage user and group accounts and related system files
- 108.1 Maintain system time
- 108.2 System logging
- 108.3 Mail Transfer Agent (MTA) basics
1. Users, groups, and discretionary access control
- Authentication confirms that a person or program is who it claims to be.
- Discretionary access control (DAC) is the traditional Linux model: access to a file or other object depends on the user’s identity and group memberships, and the owner can change those permissions (Lesson 4).
- UID and GID. People use names, but Linux uses numbers. The kernel checks the user ID (UID) and group ID (GID).
- Primary (default) group. Each account has one, recorded in
/etc/passwd. New files get this group. - Supplementary groups. An account can belong to many other groups, which are listed in
/etc/group. - Changing the current group. A process has one current group at a time.
newgrp groupnamestarts a shell with a different current group (the account must be a member). - Account types:
- User (normal) accounts are for people. Their UIDs usually start at 1000.
- System accounts run services (daemons) or special tasks. They have low UIDs, usually no login shell, and root is UID 0.
2. The files that control account creation
useradd reads two configuration files and copies from one directory. Then it writes to four account files.
/etc/login.defs ─┐
/etc/default/useradd ─┼─► useradd ─► /etc/passwd, /etc/shadow, /etc/group, /etc/gshadow
/etc/skel/ ──────┘ └─► /home/username (if a home directory is created)
/etc/login.defs
/etc/login.defs holds settings for the shadow password suite, which includes useradd, userdel, passwd, and related commands. To see only the active lines:
$ grep -Ev '^(#|$)' /etc/login.defs
| Directive | Meaning |
|---|---|
UID_MIN / UID_MAX |
Range for new user accounts (typically 1000–60000) |
SYS_UID_MIN / SYS_UID_MAX |
Range for new system accounts (typically 201–999) |
GID_MIN / GID_MAX, SYS_GID_* |
The same ranges for groups |
PASS_MAX_DAYS |
Days until a password must be changed |
PASS_MIN_DAYS |
Days before a password can be changed again |
PASS_WARN_AGE |
Days of warning before a password expires |
PASS_MIN_LEN |
Minimum password length (on most modern systems, PAM enforces password quality instead) |
CREATE_HOME |
yes creates a home directory by default. If it’s missing, the default is no. |
USERGROUPS_ENAB |
yes creates a private group named after each new user |
UMASK |
Permissions mask for new home directories |
ENCRYPT_METHOD |
Password hashing algorithm, such as SHA512 or YESCRYPT |
These values apply only to accounts created after you change them.
/etc/default/useradd
$ useradd -D
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes
$ sudo useradd -D -s /bin/bash # change a default without editing the file
HOMEis the base directory for new home directories.SHELLis the default login shell. Some Ubuntu releases set/bin/sh, which links to Dash, so check it before creating accounts.SKELis the skeleton directory.INACTIVEis the number of days after a password expires before the account is disabled.-1means never.EXPIREis the default account expiration date.
/etc/skel
The files in /etc/skel, such as .bashrc, .bash_profile, and .bash_logout, are copied into each new home directory. List them with ls -a /etc/skel. Changing /etc/skel later doesn’t update existing users. You have to copy the changes to them yourself or with a script.
3. Reading /etc/passwd and /etc/shadow
/etc/passwd
This file has one line per account and seven colon-separated fields. Everyone can read it.
Christine:x:1001:1001:Christine B:/home/Christine:/bin/bash
| Field | Meaning |
|---|---|
| 1 | Username |
| 2 | Password placeholder. x means the hash is in /etc/shadow. |
| 3 | UID |
| 4 | Primary GID |
| 5 | Comment (GECOS), usually the full name |
| 6 | Home directory |
| 7 | Login shell. /sbin/nologin or /bin/false blocks interactive logins. |
/sbin/nologinshows a polite message (which you can customize in/etc/nologin.txt) and disconnects. It’s typical for service accounts./bin/falsedisconnects silently.- If you ever find password hashes in
/etc/passwd, move them to/etc/shadowwithpwconv.
/etc/shadow
Only root can read this file. It has one line per account and nine fields.
DAdams:$6$B/zCaNx...:17806:5:30:15:3::
| Field | Meaning |
|---|---|
| 1 | Username (the only field shared with /etc/passwd) |
| 2 | Salted password hash. !! or ! means no password has been set; * or ! means no password login is possible; a ! in front of a hash means the account is locked. |
| 3 | Date of the last password change, in days since January 1, 1970 |
| 4 | Minimum days between password changes |
| 5 | Maximum days before a password change is required |
| 6 | Days of warning before the password expires |
| 7 | Inactive days after the password expires before the account is disabled |
| 8 | Account expiration date, in days since January 1, 1970 |
| 9 | Reserved |
The hash prefix identifies the algorithm: $6$ is SHA-512, $y$ is yescrypt (the default on current Debian, Ubuntu, and Fedora), and $1$ is old MD5.
Two different expirations:
- Password expiration (field 5) has a grace period (field 7). The user can still log in with the old password, but must change it immediately. After the grace period, the account is effectively locked.
- Account expiration (field 8) has no grace period. After that date, the account can’t be used at all. Set it for interns, contractors, and other temporary accounts so a forgotten account can’t be used later.
You don’t need to convert the dates in fields 3 and 8 by hand. chage -l displays them as calendar dates.
4. Creating accounts with useradd
Distributions differ, so check the defaults before you create accounts:
$ grep CREATE_HOME /etc/login.defs
$ useradd -D | grep SHELL
| Option | Meaning |
|---|---|
-c |
Comment (full name) |
-d |
Home directory path |
-m / -M |
Create / don’t create the home directory |
-s |
Login shell |
-g |
Primary group (the group must exist) |
-G |
Supplementary groups, comma-separated |
-u |
Specific UID |
-e |
Account expiration date, YYYY-MM-DD |
-f |
Inactive days after password expiration (-1 means never) |
-r |
Create a system account |
-k |
Use a different skeleton directory |
-D |
Show or change the defaults |
$ sudo useradd -m -s /bin/bash -c "Jim Kirk" JKirk # explicit and portable
$ getent passwd JKirk
JKirk:x:1002:1002:Jim Kirk:/home/JKirk:/bin/bash
$ sudo getent shadow JKirk
JKirk:!:17806:0:99999:7:::
$ sudo ls -a /home/JKirk
. .. .bash_logout .bashrc .profile
getentreads account databases (passwd,shadow,group,gshadow) through the system’s name service. It also returns accounts from LDAP or other directories, not just local files. Readingshadowrequiressudo.adduser(Debian and Ubuntu) is an interactive, higher-level wrapper configured in/etc/adduser.conf. Those distributions calluseradda “low-level utility.”- Don’t set passwords with
useradd -p. It expects an already-hashed value and can leave the hash in your shell history. Usepasswdinstead.
Classroom convention: Always pass -m -s /bin/bash (and -c) when you create interactive accounts with useradd, so the result is the same on every distribution.
5. Passwords and aging: passwd and chage
$ sudo passwd DAdams # set or reset another user's password
$ passwd # change your own password
passwd option |
Meaning |
|---|---|
-l / -u |
Lock / unlock (adds or removes the leading ! in /etc/shadow) |
-d |
Delete the password |
-e |
Expire the password now (the user must change it at the next login) |
-n / -x / -w / -i |
Minimum days / maximum days / warning days / inactive days |
-S |
Status: P/PS usable, NP no password, L/LK locked, then the aging values |
$ sudo passwd -S DAdams
DAdams PS 2018-10-01 0 99999 7 -1 (Password set, SHA512 crypt.)
$ sudo chage -l DAdams
Last password change : Oct 02, 2018
Password expires : never
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 99999
Number of days of warning before password expires : 7
chage shows aging information as readable dates. It can change the values interactively (sudo chage DAdams) or with options:
$ sudo chage -m 5 -M 90 -W 14 -I 3 DAdams # min, max, warn, inactive
$ sudo chage -E 2026-12-18 intern1 # account expires at the end of the term
$ sudo chage -d 0 newhire # force a password change at the next login
A 14–15 day warning period covers a two-week vacation.
6. Modifying and deleting accounts
usermod option |
Meaning |
|---|---|
-c |
Change the comment |
-d (with -m) |
New home directory (-m moves the existing files) |
-e |
Account expiration date |
-f |
Inactive days |
-g |
Change the primary group |
-aG |
Append supplementary groups |
-G alone |
Replace all supplementary groups |
-l |
Rename the login (doesn’t rename the home directory) |
-L / -U |
Lock / unlock |
-s |
Change the shell |
-u |
Change the UID |
$ sudo usermod -s /bin/bash DBowman # fix a wrong default shell
$ sudo usermod -L DAdams # lock the account
$ sudo passwd -S DAdams # shows LK
$ sudo usermod -U DAdams # unlock it
The most important usermod warning: usermod -G wheel alice removes alice from every other supplementary group. Always use -aG to add a group.
Locking isn’t complete protection. usermod -L and passwd -l block password logins only. SSH key logins still work. To disable an account completely, also expire it (usermod -e 1 or chage -E 0) or set its shell to /sbin/nologin.
$ sudo userdel -r DBowman # delete the account, its home directory, and its mail spool
- Without
-r, the home directory is left behind. - A “mail spool not found” message is harmless.
- Before deleting anything, follow the organization’s retention policy. HR or legal may require you to back up the user’s files first. Afterward, find files the user owned elsewhere with
find / -nouser.
7. Groups
/etc/group has four fields:
Project42:x:1042:DAdams,JKirk
- Group name
- Password placeholder (
xmeans see/etc/gshadow) - GID
- Supplementary members, comma-separated. Users whose primary group this is don’t appear in this list.
$ groups DAdams # the account's groups
$ id DAdams # UID, primary GID, and all groups
$ sudo groupadd -g 1042 Project42 # create a group with a chosen GID
$ sudo usermod -aG Project42 DAdams # add a member
$ sudo gpasswd -d DAdams Project42 # remove a member
$ sudo groupmod -g 1138 Project42 # change the GID
$ sudo groupmod -n Proj42 Project42 # rename the group
$ sudo groupdel Project42 # delete the group
$ sudo find / -gid 1138 2>/dev/null # find files still assigned to the old GID
- When
USERGROUPS_ENAB yesis set and no-gis given,useraddcreates a user private group with the same name as the user. addgroupis the Debian and Ubuntu wrapper forgroupadd.- Group passwords are stored in
/etc/gshadow(a!there means none is set). They let non-members join a group withnewgrp. Because that means sharing a password, don’t use group passwords. Manage access through membership. - A user added to a group has to log out and back in, or use
newgrp, before the new membership takes effect. - After deleting a group, audit the filesystem for files that still carry its GID.
8. Email: MTA, MDA, and MUA
Linux email follows the Unix approach of small cooperating programs:
| Role | Job | Examples |
|---|---|---|
| MTA (mail transfer agent) | Receives mail and relays it between servers over SMTP. Hands local mail to an MDA. | Postfix, Exim, Sendmail |
| MDA (mail delivery agent) | Puts messages into a local user’s mailbox | procmail, the MTA’s local delivery agent, Dovecot LDA |
| MUA (mail user agent) | Lets the user read and send mail. It doesn’t receive mail itself. | mail, mutt, Thunderbird |
The boundaries blur, since some packages combine the MTA and MDA, or the MDA and MUA.
MTA choices
- Sendmail. Historically dominant and extremely flexible, but its configuration is complex. It had security problems in the past. Its features (forwarding, aliases, mailing lists) became standard everywhere.
- Postfix. Written by Wietse Venema with security and simplicity in mind. It’s modular (several small programs) and is the default on many distributions.
- Exim. Created at the University of Cambridge in 1995. It’s a flexible drop-in replacement for Sendmail with a very different configuration, and it’s the Debian default.
Even when a server doesn’t handle user email, an MTA delivers local system messages, such as cron output and security alerts, to root or an administrator.
Sending and reading local mail with mail
The traditional mail program is sometimes called binmail, after /bin/mail. It’s in the mailx package (Red Hat) or bsd-mailx/mailutils (Debian and Ubuntu).
$ mail -s "Lab status" rich
Hi Rich, lab 7 is ready.
<Ctrl+D>
EOT
$ mail # read your mailbox (/var/spool/mail/$USER)
& 1 # read message 1
& d 1 # delete message 1
& q # quit
-ssets the subject; quote it if it has spaces.-csends copies (Cc) and-bsends blind copies (Bcc). The book prints these as-ccand-bc.-vshows delivery details.-f filereads a different mailbox file.- End the message body with Ctrl+D.
- Postfix may not deliver to usernames containing uppercase letters. Check
/var/log/maillogor/var/log/mail.logif messages disappear.
The mail queue
$ mailq # list messages waiting to be sent
$ sendmail -bp # the same thing, in Sendmail-compatible form
$ sudo postqueue -p # Postfix's own command
$ sudo postsuper -d QUEUEID # Postfix: delete a stuck message
An empty queue reports “Mail queue is empty.” Queue files are under /var/spool/. Use the MTA’s own tools to remove stuck messages rather than deleting files by hand.
Aliases and forwarding
System-wide aliases (root only):
# /etc/aliases
hostmaster: christine,rich
postmaster: root
root: nick
$ sudo newaliases # rebuild /etc/aliases.db (sendmail -bi does the same)
$ mail -s "Alias test" hostmaster < /dev/null
- The format is
ALIAS: recipient1,recipient2. - The MTA reads the binary
/etc/aliases.db, so always runnewaliasesafter editing/etc/aliases, then send a test message. - Aliases hide real usernames (for example, publishing
hostmasterinstead of an employee’s login), catch common misspellings, and send root’s mail to a person.
Per-user forwarding:
$ echo rich > ~/.forward
$ chmod 644 ~/.forward
$ rm ~/.forward # stop forwarding
Sendmail compatibility
Postfix and Exim provide a Sendmail emulation layer, so the commands sendmail, mailq, sendmail -bp, newaliases, and sendmail -bi work no matter which MTA is installed.
9. The syslog protocol
In the mid-1980s, Eric Allman defined syslog for Sendmail. It became the standard message format for the operating system, applications, and network devices: a timestamp, a facility, a severity, and the message.
Facilities identify what produced the message:
| Code | Keyword | Source |
|---|---|---|
| 0 | kern |
Kernel |
| 1 | user |
User programs |
| 2 | mail |
Mail system |
| 3 | daemon |
Background services |
| 4 / 10 | auth / authpriv |
Security and authentication (authpriv is for private details) |
| 5 | syslog |
The logger itself |
| 6 | lpr |
Printing |
| 7 / 8 | news / uucp |
Legacy news and UUCP |
| 9 | cron |
Job scheduler |
| 11 / 12 | ftp / ntp |
FTP and NTP |
| 13 / 14 | security / console |
Log audit / log alert |
| 16–23 | local0–local7 |
Available for local use (appliances, custom apps) |
Severities, from most to least severe:
| Code | Keyword | Meaning |
|---|---|---|
| 0 | emerg |
System unusable |
| 1 | alert |
Immediate action needed |
| 2 | crit |
Critical condition |
| 3 | err |
Error |
| 4 | warning |
Warning |
| 5 | notice |
Normal but significant |
| 6 | info |
Informational |
| 7 | debug |
Debugging |
Memory aid: a lower number means more severe.
Logging software history
- sysklogd: the original, with
syslogdfor system events andklogdfor kernel events. - syslog-ng: added filtering and remote logging. The book spells it “syslogd-ng.”
- rsyslog: the fast, standard syslog daemon (
rsyslogd) on most distributions. - systemd-journald: systemd’s binary journal. It isn’t syslog format, but it collects syslog, kernel, boot, and service messages.
10. rsyslog
Rules
The configuration file is /etc/rsyslog.conf plus /etc/rsyslog.d/*.conf. (The book writes /etc/rsyslogd.conf; the daemon is rsyslogd, but the file is rsyslog.conf.) Each rule has the form:
facility.priority action
| Selector | Meaning |
|---|---|
kern.crit |
Kernel messages at crit or more severe (crit, alert, emerg) |
kern.=crit |
Only crit |
*.emerg |
Emergencies from any facility |
auth,authpriv.* |
Several facilities, all priorities |
*.info;mail.none;authpriv.none |
Everything at info or above, except mail and authpriv |
Actions:
- Write to a file (a leading
-means don’t sync after every write, which is faster but can lose the last messages in a crash). - Pipe to a program.
- Write to a terminal or the console.
- Send to a remote host.
- Send to specific users, or to all logged-in users (
:omusrmsg:*).
# Ubuntu (Debian family)
auth,authpriv.* /var/log/auth.log
*.*;auth,authpriv.none -/var/log/syslog
kern.* -/var/log/kern.log
mail.* -/var/log/mail.log
*.emerg :omusrmsg:*
# Red Hat family
*.info;mail.none;authpriv.none;cron.none /var/log/messages
authpriv.* /var/log/secure
mail.* -/var/log/maillog
cron.* /var/log/cron
local7.* /var/log/boot.log
Where to look first: On Debian and Ubuntu, start with /var/log/syslog and /var/log/auth.log. On Red Hat, start with /var/log/messages and /var/log/secure. Applications often have their own directories, such as /var/log/apache2/ or /var/log/httpd/.
Sending logs to a central log server
A central log host collects logs from many clients, which helps both troubleshooting and security (an attacker who breaks into one server can’t erase the copies elsewhere). On each client, add a rule at the end of /etc/rsyslog.conf:
*.* @@(z9)loghost.example.edu:6514
@means UDP.@@means TCP. Use TCP when losing messages matters.(z1)–(z9)is optional zlib compression, from lowest to highest.- Host: a fully qualified name or IP address. Put IPv6 addresses in brackets.
:portis optional. Syslog traditionally uses port 514.
Then restart the service: sudo systemctl restart rsyslog. Port 6514 is normally used for syslog over TLS, which needs more configuration than this.
Rotating logs with logrotate
logrotate runs daily (from cron or a systemd timer). It renames, compresses, removes, and optionally mails old logs so they don’t fill the disk.
# /etc/logrotate.conf (global settings)
weekly
rotate 4
create
dateext
#compress
include /etc/logrotate.d
/var/log/wtmp {
monthly
create 0664 root utmp
minsize 1M
rotate 1
}
- Global settings come first. Per-file blocks override them.
include /etc/logrotate.dpulls in per-package files, usually named after the service they manage.- Rotated file names: with
dateextyou getbtmp-20260901. Without it you getmail.log.1,mail.log.2, and so on, where the highest number is the oldest.
| Directive | Meaning |
|---|---|
hourly / daily / weekly [n] / monthly |
Rotation schedule (hourly also needs logrotate to run hourly) |
size n |
Rotate by size instead of time (add k, M, or G for units) |
rotate n |
Keep n old copies (0 deletes instead of keeping) |
compress |
gzip rotated files |
missingok |
Don’t complain if the log is missing |
notifempty |
Skip empty logs |
create mode owner group |
Create a new empty log with these attributes |
copytruncate |
Copy and then truncate, for programs that keep the file open |
dateext / dateformat |
Date-based suffix and its format |
The status file is /var/lib/logrotate/logrotate.status (Red Hat) or /var/lib/logrotate/status (Debian). Test a configuration with sudo logrotate -d /etc/logrotate.conf (a dry run).
/var/log/btmp records failed logins, which you read with lastb. /var/log/wtmp records logins, which you read with last.
Writing and reading log entries
$ logger "Backup script finished"
$ logger -p local0.warning -t backup "Disk 90% full"
$ tail -f /var/log/syslog # follow new entries (Ctrl+C to stop)
$ grep -i "failed password" /var/log/auth.log
logger option |
Meaning |
|---|---|
-p |
Facility and priority |
-t |
Tag, which makes entries easy to search for |
-i |
Include the process ID |
-f |
Log the contents of a file |
-s |
Also write to standard error |
rsyslog adds the timestamp, host name, and user to every entry.
11. systemd-journald
The journal stores entries in an indexed binary format. You read it only with journalctl. It captures syslog messages, kernel messages, boot messages, and service output, along with metadata such as unit, PID, and UID.
Configuration: /etc/systemd/journald.conf
| Directive | Meaning |
|---|---|
Storage= |
auto (default), persistent, volatile, or none |
Compress= |
Compress journal objects (default yes) |
ForwardToSyslog= |
Also pass messages to a syslog daemon |
ForwardToWall= |
Send emergency messages to all terminals |
SystemMaxUse= / SystemKeepFree= / SystemMaxFileSize= |
Size limits for persistent storage (/var/log/journal) |
RuntimeMaxUse= / RuntimeKeepFree= / RuntimeMaxFileSize= |
The same limits for volatile storage (/run/log/journal) |
MaxFileSec= |
Maximum time before a journal file is rotated |
Storage modes:
autowrites to/var/log/journalif that directory exists; otherwise it uses/run/log/journal, which is lost at reboot.persistentcreates/var/log/journalif needed and writes there.volatilekeeps the journal in memory only (/run/log/journal).nonediscards messages.
Making the journal persistent
$ sudo sed -i 's/^#\?Storage=.*/Storage=persistent/' /etc/systemd/journald.conf
$ sudo systemctl restart systemd-journald # reload doesn't work for journald
$ ls /var/log/journal/
Setting Storage=persistent and restarting lets journald create the directory with the correct permissions. That’s safer than creating it by hand.
Journal files
- The active files are
system.journaland, if configured,user-UID.journalfor each user. They live in a directory named after the machine ID. - Rotated (archived) files have
@and a long ID in their names. sudo journalctl --rotateforces a rotation.
Viewing and filtering
The syntax is journalctl [OPTIONS] [MATCHES]. Reading the full system journal requires root or membership in the systemd-journal group (on some distributions, adm or wheel).
| Option | Meaning |
|---|---|
-n N |
Last N entries |
-e |
Jump to the end |
-r |
Newest first |
-f |
Follow new entries, like tail -f |
-k |
Kernel messages (like dmesg) |
-b / -b -1 |
This boot / the previous boot |
-u unit |
Only entries from one unit |
-p err |
This priority and more severe |
-S / -U |
Since / until ("2026-09-24 08:00", today, yesterday, -1h) |
--no-pager |
Don’t use less |
-o verbose / -o json |
Show every field / JSON output |
$ sudo journalctl -u ssh --since today
$ sudo journalctl -p err -b
$ sudo journalctl _UID=1001 --since "2026-09-24 08:00"
$ sudo journalctl _SYSTEMD_UNIT=sshd.service + _SYSTEMD_UNIT=cron.service
$ sudo journalctl -f
Field matches use the form FIELD=value. Examples include _SYSTEMD_UNIT=, _PID=, _UID=, _HOSTNAME=, PRIORITY=, _TRANSPORT=, and _UDEV_SYSNAME=. Matches on different fields are combined with AND. Separate them with + to get OR. The full list is in man systemd.journal-fields.
Maintaining the journal
$ journalctl --disk-usage
$ sudo journalctl --vacuum-size=300M # remove archived files down to 300 MB
$ sudo journalctl --vacuum-time=2weeks # remove archived entries older than 2 weeks
$ sudo journalctl --sync # flush to disk before copying journal files
The vacuum options affect archived files only, so the reported usage can stay above the target you set.
Journals from other systems
journalctl -D /path/to/dirreads journal files in another directory, such as a rescued disk.--file=patternreads specific files.-m(--merge) combines entries from all available journals in one view, for example on a central host that receives journals throughsystemd-journal-remote.
Writing journal entries and combining with rsyslog
$ echo "Nightly job done" | systemd-cat -t nightly -p info
$ logger "Test of logger" # also reaches the journal on systemd systems
$ journalctl -t nightly
Most distributions run journald and rsyslog together:
- Journal client (preferred): rsyslog reads the journal with the
imjournalmodule (or theimuxsocksocket), so no boot messages are lost. - Forward to syslog: set
ForwardToSyslog=yesso journald passes messages through/run/systemd/journal/syslog.
12. Keeping time: clocks and standards
Accurate time matters for scheduled jobs, logs you need to compare across servers, and authentication systems such as Kerberos and TLS certificate checks.
- Local time (“wall clock” time) depends on the time zone.
- UTC (Coordinated Universal Time) is the same everywhere. Use it for servers, logs, and meetings across time zones.
- Hardware clock (RTC, real-time clock). Runs on the motherboard battery (CMOS battery) while the system is off. Keep it in UTC to avoid daylight saving time problems.
- Software (system) clock. Set from the RTC at boot and used by the operating system. It drifts, especially on busy systems, which is why NTP exists.
hwclock
$ sudo hwclock -r # --show: read the RTC (requires root)
$ sudo hwclock -w # --systohc: system time → RTC
$ sudo hwclock -s # --hctosys: RTC → system time
$ sudo hwclock -u -w # --utc: keep the RTC in UTC
date and timedatectl
$ date
$ sudo date 05301430 # MMDDhhmm (local time)
$ sudo date -u 05301930 # the same, given in UTC
$ timedatectl # summary: local, UTC, RTC, zone, NTP
$ sudo timedatectl set-ntp false # required before setting the time by hand
$ sudo timedatectl set-time "2026-09-24 16:15:00"
$ sudo timedatectl set-ntp true
$ sudo timedatectl set-local-rtc 0 # RTC in UTC (1 = local time; avoid)
set-timefails with “Automatic time synchronization is enabled” until you turn off NTP. The book usesset-ntp 0andset-ntp 1;falseandtrueare clearer.- Classroom convention: use
timedatectlon systemd systems, and usehwclockanddatewhen you need to know the individual pieces. - If you mess up the clock during a lab, turn NTP back on (or reboot).
13. Network Time Protocol (NTP)
NTP synchronizes clocks over the network using UDP port 123. The same software can act as a client, a server, or a peer.
The stratum hierarchy
- Stratum 0: reference clocks, such as atomic clocks and GPS receivers.
- Stratum 1: servers connected directly to a stratum 0 device.
- Stratum 2 and below: each level gets its time over the network from the level above, so accuracy drops slightly at each step.
- Stratum 16: unsynchronized.
NTP software measures network delay and compensates for it.
SNTP (Simple NTP) is a lightweight version for devices that don’t need high accuracy. systemd-timesyncd is an SNTP client.
Choosing time sources
- Your ISP or organization’s time servers are the most accurate and cause the least network traffic.
- pool.ntp.org is a volunteer pool. Each request gets a different member. It has regional and vendor subsets such as
us.pool.ntp.org,north-america.pool.ntp.org, and2.ubuntu.pool.ntp.org. Number the entries0.,1.,2., and so on to get different servers. - Google’s leap-smearing servers (
time1–time4.google.com) spread a leap second across a whole day instead of inserting it at once. Don’t mix smeared and non-smeared sources. - Published server lists are also available. Follow each server’s usage rules.
- For high-precision needs, use local hardware reference clocks rather than servers on the internet.
ntpd (the traditional daemon)
- Package
ntp, daemonntpd, configuration/etc/ntp.conf.
server 0.us.pool.ntp.org iburst
server 1.us.pool.ntp.org iburst
server 2.us.pool.ntp.org iburst
iburst sends a quick burst of requests at startup to speed up the first synchronization.
$ sudo ntpdate 0.pool.ntp.org # one-time manual correction (before starting ntpd)
$ sudo systemctl enable --now ntpd
$ ntpstat # synchronized? to what, at which stratum, how accurate
$ ntpq -p # peer table
- Insane time: older ntpd wouldn’t correct a clock that was off by more than about 17 minutes, which is why administrators ran
ntpdatefirst. - Reading
ntpq -p:*marks the source currently in use,+marks good candidates,stis the stratum, andreachis an octal record of recent responses (377 means the last 8 all succeeded). Delay, offset, and jitter are in milliseconds. - After NTP has corrected the system clock, copy it to the hardware clock with
hwclock --systohc.
chrony (the modern default)
chronyd synchronizes faster and handles busy networks, virtual machines, and machines that are often turned off or disconnected. It’s the default on Red Hat, Fedora, and SUSE, and it’s commonly used on Ubuntu too.
- Package
chrony, daemonchronyd(the service ischronyon Debian and Ubuntu). - Configuration is
/etc/chrony.confor/etc/chrony/chrony.conf.
pool 2.ubuntu.pool.ntp.org iburst maxsources 2
server time.example.edu iburst
rtcsync
serveris one host.poolis a pool name that resolves to several servers.maxsourceslimits how many servers chrony uses from a pool, and it replaces any that fail.rtcsyncmakes chrony copy the system time to the RTC regularly, so you don’t need to runhwclock --systohc.- Open UDP port 123 in the firewall if the machine serves time to others. Restart chronyd after editing the configuration.
$ sudo systemctl enable --now chronyd
$ chronyc sources -v # like ntpq -p, with a legend (^* = current source)
$ chronyc sourcestats # offset and drift statistics for each source
$ chronyc tracking # how far off the system clock is, stratum, leap status
Only one time daemon should run at a time. Check which one is active with systemctl status chronyd ntpd systemd-timesyncd.
Classroom application
- Account life cycle. Check
CREATE_HOMEanduseradd -Don two distributions. Create an intern account with a home directory, the Bash shell, a comment, and an expiration date at the end of the semester. Set its password, force a change at first login, then lock, unlock, and finally delete it withuserdel -r. Explain each change you see in/etc/passwd,/etc/shadow, andchage -l. - Group trap. Add a user to two groups with
-aG, then runusermod -Gwithout-aand compare the output ofidbefore and after. - Local mail. Send mail between two accounts, add a
/etc/aliasesentry and runnewaliases, then test a.forwardfile. - rsyslog rule. Add
local0.* /var/log/lab.log, restart rsyslog, send a message withlogger -p local0.notice, and find it in the file and injournalctl -t. - Journal detective. Make the journal persistent, reboot, and then use
-b -1,-u,-p err, and--sinceto answer specific questions (for example, “When did sshd last restart?”). - Time audit. Report the
timedatectloutput, the active time daemon, andchronyc tracking. Add a pool withmaxsourcesand confirm the change inchronyc sources -v.
Common misconceptions
- “
/etc/passwdholds passwords.” It holds anxplaceholder. The hashes are in/etc/shadow, which only root can read. - “
usermod -Gadds a group.” Without-a, it replaces all of the user’s supplementary groups. - “A locked account can’t log in at all.”
-Land-lblock passwords only. SSH keys still work unless the account is expired or its shell isnologin. - “Password expiration and account expiration are the same.” Password expiration has a grace period. Account expiration doesn’t.
- “Editing /etc/aliases is enough.” You must also run
newaliases. - “
kern.critlogs only critical messages.” It logs crit and more severe. Usekern.=critfor exactly crit. - “
@sends logs over TCP.”@is UDP and@@is TCP. - “Vacuuming shrinks the whole journal.” It removes archived files only. Active files are untouched.
- “The hardware clock should be set to local time.” Keep it in UTC and let the time zone handle local time.
- “Run ntpd and chrony together for redundancy.” Run only one time daemon, with several sources.
Lesson summary
- Accounts:
/etc/login.defs,/etc/default/useradd, and/etc/skelshape whatuseradddoes./etc/passwd,/etc/shadow,/etc/group, and/etc/gshadowstore the results. Usepasswdandchagefor passwords and aging,usermod -aGfor group changes, anduserdel -r(following the retention policy) to remove accounts. - Email: MTAs (Postfix, Exim, Sendmail) move mail, MDAs deliver it, and MUAs read it. Use
mail,mailq/sendmail -bp,/etc/aliasesplusnewaliases, and~/.forward. - Logging: syslog uses facility, severity, and message. rsyslog rules use
facility.priority action, send to remote hosts with@/@@, rotate with logrotate, and accept entries fromlogger. - Journal: journald stores binary, indexed entries. Configure it in
journald.conf, make it persistent, search it withjournalctloptions and field matches, clean it up with vacuum options, and write to it withsystemd-cat. - Time: keep the RTC in UTC. Use
hwclock,date, andtimedatectlfor manual work, and NTP (preferably chrony, with pools,iburst, andrtcsync) to keep clocks accurate.
The next lesson is Configuring Basic Networking.
Course Notes