10 · Infrastructure & Identity

Linux Administration

Eight commands every Linux administrator runs every week. User lifecycle, group management, SSH hardening, filesystems — and what the ACL lab quietly teaches you about all of them.

This page is a working reference, not a tutorial. Each section is a self-contained answer to a real question that comes up the first time you administer a Linux system: how do I make an account, lock one, share a directory with a team, get my coworker SSH access, mount the new disk? Every command shown is exactly what you'd type at a real prompt.

The accompanying hands-on lab threads all eight topics into a single onboarding scenario — create a team, give them shared storage, get them on SSH, then off-board one of them. If you do the lab, you'll use everything here at least once.

01Creating users

A user account in Linux is a row in /etc/passwd, a row in /etc/shadow (with the hashed password), a primary group, optional secondary groups, a home directory, and a login shell. Two tools create users: useradd and adduser. They are not the same tool, and which one is available depends on your distribution.

useradd — the portable workhorse

useradd is part of the shadow-utils package and exists on essentially every modern Linux distribution. It is low-level: it makes the account, but it doesn't set a password, doesn't always create a home directory, and doesn't ask you any questions. You give it flags; it does exactly what you said.

Minimal usage

root# useradd alice

That creates the account but, on most distros, does not create /home/alice, leaves the account locked (no password), and uses the system default shell (often /bin/sh). The result is usually not what you wanted.

Practical usage — the flags that actually matter

root# useradd -m -s /bin/bash -c "Alice Chen, Engineering" -G developers,sudo alice

That command creates alice with a home directory at /home/alice, bash as her login shell, a human-readable comment ("GECOS" field) listing her name and department, and membership in two supplementary groups.

Common flags

FlagWhat it does
-mCreate the user's home directory (skeleton files from /etc/skel are copied in). Without -m, no home directory exists and the user can't log in cleanly.
-MExplicitly do not create a home directory (for service accounts that don't need one).
-s SHELLSet the login shell. /bin/bash for human users, /usr/sbin/nologin for service accounts that should never log in interactively.
-c "COMMENT"The GECOS field — traditionally the user's full name, phone, room number. Modern usage: just the full name and maybe a department.
-G g1,g2Supplementary groups (comma-separated, no spaces). Membership is set exactly to this list — existing memberships are wiped. Use usermod -aG later to append instead of replace.
-g GROUPPrimary group. By default, useradd creates a new group with the same name as the user (USERGROUPS_ENAB in /etc/login.defs).
-u UIDSpecify the user's UID. Useful when you need the UID to match across machines (e.g., for shared NFS mounts).
-d /pathCustom home directory path (default /home/<name>).
-rCreate a system account (UID below 1000, no aging, no home by default). Use for daemons and services.
-e YYYY-MM-DDAccount expiration date. After this date, the account is disabled.
-f DAYSDays after password expiry before the account is locked. 0 = lock immediately on expiry.

adduser — the same thing, except when it isn't

There are two different adduser commands in the wild, and they behave completely differently. Knowing which one you have matters.

Debian / Ubuntu adduser

What it is: a Perl script (a friendly wrapper around useradd) that walks you through the whole account-creation process interactively.

What it does for you: creates the home directory, copies the skeleton files, picks a sane UID/GID, sets the shell, prompts you for the GECOS fields and the password, and asks for confirmation.

When you want it: interactive use on a Debian/Ubuntu box. It's the friendlier choice when you're sitting at a terminal making one account by hand.

RHEL / Rocky / Fedora / SUSE adduser

What it is: a symbolic link directly to useradd. Same binary, same flags, no interactive prompts at all.

What it does for you: exactly what useradd does. Nothing more.

When you want it: never specifically. If you're on RHEL/Rocky/Fedora, use useradd directly — adduser is just a different name for the same thing.

Debian-style adduser in action

root# adduser alice Adding user `alice' ... Adding new group `alice' (1003) ... Adding new user `alice' (1003) with group `alice (1003)' ... Creating home directory `/home/alice' ... Copying files from `/etc/skel' ... New password: Retype new password: passwd: password updated successfully Changing the user information for alice Enter the new value, or press ENTER for the default Full Name []: Alice Chen Room Number []: Work Phone []: Home Phone []: Other []: Is the information correct? [Y/n] y

Other ways to create users

When to use which

Reach for useradd

Writing a script. Provisioning many accounts. Running on RHEL/Rocky/Fedora/SUSE. Need predictable, scriptable behavior. Want exact control over UID, GID, shell, and home.

Reach for adduser

You're on Debian or Ubuntu, you're at a terminal, and you're making one account interactively. The wrapper will handle the home directory, password, and GECOS in one pass without you needing to remember the flags.

Common mistake Forgetting -m with useradd on RHEL. The account is created, but /home/<user> doesn't exist. The user logs in, lands in /, can't write anywhere, and everyone is confused. Always pass -m for human users.

02Setting passwords & aging

Creating the account is half the work; the password (and its lifecycle) is the other half. Two commands cover almost everything: passwd sets and manages the password itself, and chage manages the aging policy — how long before it expires, how soon before then to warn the user, how to force a change on the next login.

passwd — setting the password

Set a user's password (root)

root# passwd alice New password: Retype new password: passwd: password updated successfully

Change your own password (any user)

alice$ passwd Changing password for alice. Current password: New password: Retype new password: passwd: password updated successfully

Force a password change at next login

Standard practice when a help desk resets a password for someone: set a temporary password, then force the user to change it the moment they log in. Two ways to do this:

root# passwd -e alice # or equivalently: root# chage -d 0 alice

Both work by setting the "last changed" date to a value that makes the system consider the password expired. The next time alice logs in — on console, SSH, anywhere — she'll be prompted to set a new password before she can do anything else.

passwd flag reference

FlagWhat it does
-eExpire the password immediately. Forces a change at next login.
-lLock the account by prefixing the password hash with ! in /etc/shadow. The user can't log in with a password, but SSH keys still work. This is not a full disable.
-uUnlock a previously locked account.
-dDelete the password entirely. The user can log in with no password (dangerous). Almost always wrong.
-SStatus: show the password state for the user. Output tells you whether the password is set, locked, or expired.
-n DAYSMinimum days between password changes. 1 stops users from changing the password back immediately after it's reset.
-x DAYSMaximum days the password is valid. 90 = enforce a quarterly change.
-w DAYSDays before expiry to start warning the user at login.
-i DAYSDays after expiry before the account itself is locked.

chage — the aging tool you'll actually use

When you need to control when a password expires, when the user is warned, and when the account itself goes inactive — that's chage. (Pronounced "change-age" or "shaj"; depends on who you ask.)

Inspect the current policy

root# chage -l alice Last password change : Jun 04, 2026 Password expires : Sep 02, 2026 Password inactive : never Account expires : never Minimum number of days between password change : 1 Maximum number of days between password change : 90 Number of days of warning before password expires : 14

Set a 90-day password policy with 14-day warning

root# chage -M 90 -m 1 -W 14 alice

Reads as: maximum age 90 days, minimum 1 day between changes (prevents instant-revert), warn for 14 days before the password expires.

Force a password change at next login (again, the chage way)

root# chage -d 0 alice

Set the account itself to expire on a specific date

root# chage -E 2026-12-31 alice # Use -E -1 to remove an expiration date

chage flag reference

FlagWhat it does
-lList the current aging info for the user (the inspect command).
-d DAYS"Last changed" date in days since epoch. -d 0 forces a change at next login.
-m DAYSMinimum days between changes. Stops "change, then change back" workflows.
-M DAYSMaximum days between changes. The classic "passwords expire every 90 days" knob.
-W DAYSDays before password expiry to start warning the user.
-I DAYSDays after password expiry before the account becomes inactive.
-E YYYY-MM-DDAccount expiration date. After this, login is denied entirely.

System-wide defaults

The defaults that useradd and chage apply when you don't specify flags live in /etc/login.defs. The interesting lines:

# /etc/login.defs — aging defaults applied to new accounts PASS_MAX_DAYS 90 PASS_MIN_DAYS 1 PASS_WARN_AGE 14 UID_MIN 1000 UID_MAX 60000 CREATE_HOME yes USERGROUPS_ENAB yes

If your policy requires 90-day rotation, set PASS_MAX_DAYS here and every new account inherits it. Changing this file does not retroactively update existing users — for those, run chage against each.

Modern guidance NIST SP 800-63B has moved away from forced periodic password changes for general use, recommending instead that you only require a change when there's evidence of compromise. Many organizations still enforce rotation for compliance reasons (PCI DSS, HIPAA, internal policy). Know which world you're operating in before you set PASS_MAX_DAYS.

03Disabling accounts

"Disable this account" sounds simple. It is not. The default approach — locking the password — only blocks password-based login. If the user has an SSH key in their ~/.ssh/authorized_keys, they can still log in. If they have a running session, they can still use it. A proper disable closes every door at once.

Why "lock" is not "disable"

root# passwd -l bob # locks the password root# passwd -S bob bob L 06/04/2026 1 90 14 -1 (Password locked.)

That L means the hash in /etc/shadow now has a ! prefix; no password will ever match it. But:

A real disable closes every path.

The proper disable recipe

# 1. Lock the password hash root# usermod -L bob # 2. Expire the account itself (NOT the password) root# usermod -e 1 bob # —or any past date: -e 2020-01-01 # 3. Change the login shell so even key-based SSH lands on nothing root# usermod -s /usr/sbin/nologin bob # 4. Kill any running sessions root# pkill -KILL -u bob # 5. Wipe authorized_keys (keys are auth surface, not a password) root# mv /home/bob/.ssh/authorized_keys /home/bob/.ssh/authorized_keys.disabled-$(date +%F) # 6. Disable cron and at jobs owned by bob root# crontab -u bob -r # remove user's crontab

After those six steps, bob cannot log in with a password, cannot log in with an SSH key, cannot land in a working shell even if those two somehow succeed, has no running sessions, and has no scheduled jobs that will fire later. That is disabled.

Audit step Before you delete an account permanently, leave it in this "fully disabled" state for 30–90 days. You will discover that bob was the owner of three cron jobs, two systemd services, a shared mailbox, and the database account that runs the nightly ETL. Locking him out first — rather than deleting him — lets you find those dependencies without losing the audit trail.

Disable vs delete

Deletion is the next step after disable — and it's a separate decision.

root# userdel bob # remove the account, keep /home/bob root# userdel -r bob # remove the account AND /home/bob and mail spool root# userdel -f -r bob # force, even if bob is currently logged in
Watch out userdel -r deletes the home directory with no prompt. If bob had work product there, it's gone. For real offboarding, archive /home/bob first (tar czf bob-archive.tgz /home/bob), then delete.

04Groups, in depth

A group is a named collection of users that can be granted permissions as a unit. Instead of giving alice, bob, and carol each their own permission to read /srv/projects/teamA/, you create a group called teamA, add the three of them to it, and grant the group read access. Now adding a fourth person (or removing one) is a single command and doesn't touch the directory at all.

This sounds trivial, and at the level of three users it is. At the level of three hundred users across a dozen projects, it is the only sustainable way to manage access. Groups are why Linux administration scales.

Primary vs supplementary groups

Every Linux user has exactly one primary group, which determines the default group ownership of files they create. They can also have zero or more supplementary groups (also called secondary groups), which grant additional access.

alice$ id uid=1003(alice) gid=1003(alice) groups=1003(alice),1004(developers),1005(teamA),27(sudo)

Here alice's primary group is alice (gid 1003), and her supplementary groups are developers, teamA, and sudo. When she runs touch newfile, the file's group ownership is alice — her primary. To make team files default-group teamA instead, you use the setgid bit on the directory (covered in Topic 5).

UPG — the "user private group" convention Most modern distributions create a new group with the same name as the user when the account is made, and make that the user's primary group. This is called user private groups. The reason: it lets you set a permissive umask (002 instead of 022) without exposing files to other users, because each user's primary group only contains themselves. It looks redundant at first; it isn't.

Creating a group

root# groupadd teamA # basic root# groupadd -g 2001 teamA # specific GID (useful across machines) root# groupadd -r backup-svc # system group (GID below 1000)

Listing groups and their members

Three commands cover everything you'll need to ask.

What groups exist on this system?

$ getent group root:x:0: sudo:x:27:alice,bob,carol developers:x:1004:alice,bob,carol,dave teamA:x:2001:alice,carol ...

Same as cat /etc/group on a system with only local accounts; getent additionally pulls in LDAP/AD groups if the system is joined to a directory.

Who is in this specific group?

$ getent group teamA teamA:x:2001:alice,carol

What groups is this specific user in?

$ groups alice alice : alice developers teamA sudo $ id alice uid=1003(alice) gid=1003(alice) groups=1003(alice),1004(developers),2001(teamA),27(sudo)

Adding and removing members

The single most important fact about adding a user to a group: always use the -a flag with usermod -G. Without -a, you replace the user's entire set of supplementary groups with the one you just specified. People have wiped out a user's sudo access this way, often without realizing it.

Add alice to teamA (APPEND — the right way)

root# usermod -aG teamA alice

Add alice to teamA (WRONG — this replaces all her supplementary groups)

root# usermod -G teamA alice # Now alice is in teamA and ONLY teamA. She has lost sudo and developers.

Remove alice from teamA

root# gpasswd -d alice teamA

There's no usermod -d for groups — gpasswd -d is the standard way to remove one user from one group without touching the rest of their memberships.

Change alice's primary group

root# usermod -g developers alice

Temporarily switch primary group in your session

alice$ newgrp teamA # Now files alice creates in this shell will be group-owned by teamA, not alice. # Open a new shell to revert.

Removing or renaming a group

root# groupdel teamA # fails if any user has it as PRIMARY group root# groupmod -n project-x teamA # rename teamA to project-x root# groupmod -g 3000 project-x # change the GID
Side effect of changing a GID Files already on disk are tagged by GID, not name. If you change teamA's GID from 2001 to 3000 and there are existing files owned by gid 2001, those files now appear to belong to "an unknown group" (the number 2001 with no name). Either avoid changing GIDs, or run find / -gid 2001 -exec chgrp 3000 {} + right after.

The shape of /etc/group

Every group is one line, four colon-separated fields:

groupname:x:GID:user1,user2,user3 teamA:x:2001:alice,carol developers:x:1004:alice,bob,carol,dave

Special groups worth knowing

Why groups are the answer

When permissions are granted to individuals, every onboard and offboard touches every resource the user can access. When permissions are granted to groups, onboarding is "add user to group" and offboarding is "remove user from group" — the resources don't move.

The rule: grant permissions to groups, put users into groups, and try very hard to never grant a permission to a single named user.

05Creating directories

mkdir is the simplest command in this reference, but a handful of flags turn it from "make one directory" into "build out a whole project tree in one line with the right permissions."

Basic usage

$ mkdir myproject

Create parents as needed

$ mkdir -p /srv/projects/teamA/data/raw # Without -p, this fails because /srv/projects/teamA/data doesn't exist yet.

The -p flag is the single most-used mkdir option. It creates every directory in the path that doesn't already exist, and silently does nothing for the ones that do. Safe to run twice.

Set the mode (permissions) at creation

$ mkdir -m 0750 /srv/projects/teamA # Owner: rwx, group: r-x, others: nothing

Without -m, the new directory's permissions are governed by your umask. With -m, you pick exactly the mode you want, ignoring umask.

Bash brace expansion — multiple directories in one call

$ mkdir -p /srv/projects/{teamA,teamB,teamC}/{data,docs,scripts} # Creates 9 directories: teamA/data, teamA/docs, teamA/scripts, # teamB/data, teamB/docs, teamB/scripts, etc.

Common flag reference

FlagWhat it does
-pCreate parent directories as needed; succeed silently if the target already exists.
-m MODESet the mode at creation. Use octal: 0755, 0750, 0700.
-vVerbose — print one line per directory created. Useful for sanity-checking brace-expansion explosions.
-ZSet the SELinux security context on the new directory (on SELinux-enabled systems).

After creating — ownership and the setgid trick

Creating the directory is step one. Step two, for a shared team directory, is usually to (a) set the group, (b) grant the group write access, and (c) make sure every file created inside the directory also belongs to that group automatically.

# Create the shared dir root# mkdir -p /srv/projects/teamA # Set the group root# chgrp teamA /srv/projects/teamA # Grant rwx to owner, rwx to group, nothing to others — AND set the setgid bit (the leading 2) root# chmod 2770 /srv/projects/teamA # Test: any file alice creates here will be group-owned by teamA, not by alice alice$ touch /srv/projects/teamA/notes.txt alice$ ls -l /srv/projects/teamA/notes.txt -rw-rw---- 1 alice teamA 0 Jun 4 10:33 /srv/projects/teamA/notes.txt

The setgid bit on a directory (the leading 2 in 2770) means: any file or subdirectory created inside this directory inherits the directory's group, not the creator's primary group. This is exactly the behavior you want for shared team storage.

Permission shorthand Common modes for new directories:
· 0755 — public-readable (web roots, system binaries)
· 0750 — private to a group (team home, shared scripts)
· 2770 — shared team writable, setgid for group inheritance
· 0700 — private to owner (~/.ssh, secrets)

06SSH — and the root login question

SSH is how you'll log into every Linux server you administer for the rest of your career. Setting it up correctly — key-based authentication, the right users allowed in, and a deliberate decision about root login — is the single highest-leverage security action you take on a new system.

Install and start the SSH server

# Debian / Ubuntu root# apt install openssh-server root# systemctl enable --now ssh # RHEL / Rocky / Fedora root# dnf install openssh-server root# systemctl enable --now sshd

The service is named ssh on Debian-family and sshd on RHEL-family. The configuration file is the same on both: /etc/ssh/sshd_config.

Set up key-based authentication

Passwords are guessable; SSH keys are not (when generated with a modern algorithm). The standard setup is: generate a key on your local machine, copy the public half to the server, then disable password authentication on the server entirely.

On your local machine (the client)

you$ ssh-keygen -t ed25519 -C "alice@workstation" Generating public/private ed25519 key pair. Enter file in which to save the key (/home/alice/.ssh/id_ed25519): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/alice/.ssh/id_ed25519 Your public key has been saved in /home/alice/.ssh/id_ed25519.pub

Use ed25519, not rsa. It's shorter, faster, and at least as strong. Always set a passphrase — it's what protects the key if your laptop is stolen.

Copy the public key to the server

you$ ssh-copy-id [email protected] # That's it. ssh-copy-id handles the directory permissions, the file mode, everything.

If ssh-copy-id isn't available, do it by hand

you$ cat ~/.ssh/id_ed25519.pub | ssh [email protected] "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

Note the permissions: ~/.ssh must be 700 and authorized_keys must be 600. SSH will refuse to use them otherwise — this is a frequent source of "why won't my key work?" frustration.

The root login question

Should the root account be allowed to log in via SSH? This is one of the few security questions where the right answer is almost always "no" — but understanding why matters, because there are scenarios where you'll need to override it.

Disable root SSH (the default for hardened systems)

root# grep PermitRootLogin /etc/ssh/sshd_config #PermitRootLogin prohibit-password root# vi /etc/ssh/sshd_config # Set the line to: PermitRootLogin no root# sshd -t # test config syntax FIRST root# systemctl restart sshd # apply

Why disable root SSH

Enable root SSH (the rare valid cases)

# In sshd_config: PermitRootLogin prohibit-password # or, less commonly: PermitRootLogin yes

There are three options that allow root login at all:

Other sshd_config settings worth knowing

SettingWhat it does
PasswordAuthentication noDisable password login entirely. Keys only. The single biggest hardening step you can take after disabling root.
PubkeyAuthentication yesAllow public-key authentication. On by default; verify it.
AllowUsers alice bobOnly these users can SSH. Everyone else is denied even if their credentials are correct.
AllowGroups developersOnly members of these groups can SSH. Pairs perfectly with the group strategy from Topic 4.
Port 2222Listen on a non-default port. Marginal security benefit (reduces drive-by scans, doesn't stop a real attacker), but quiets the logs.
MaxAuthTries 3Disconnect after N failed auth attempts in a single session.
ClientAliveInterval 300Send a keepalive every 300 seconds. With ClientAliveCountMax 2, drops idle sessions after ~10 minutes.
The workflow Always test before restarting: sshd -t parses the config and reports errors without restarting the service. A typo in sshd_config can lock you out of the server. Open a second SSH session before you restart, so if the new config breaks login, you still have a way in.

07chroot jails — and what replaced them

A chroot jail is a Unix isolation technique: you take a process and tell the kernel, "as far as you're concerned, this directory is the root of the filesystem." The process can see /usr/lib, /etc/passwd, and so on, but those paths all resolve under the jail directory, not the real system. To the jailed process, the rest of the filesystem doesn't exist.

It is a beautiful idea, it was the original "I'd like this process to be contained" mechanism on Unix, and on modern systems it has been almost entirely superseded by containers — for a reason worth understanding.

A short history

The chroot() system call was added to Version 7 Unix in 1979. Bill Joy used it in 1982 to test installations of BSD. By the 1990s, it was the standard way to run a network-facing daemon (BIND, FTP servers, anonymous HTTP) in a sandbox: build a minimal copy of /usr/lib, /bin, and /etc inside /var/named/chroot/, then start the daemon with chroot /var/named/chroot /usr/sbin/named. If the daemon was exploited, the attacker landed inside the jail, not the real filesystem.

FreeBSD took the idea further in 2000 with the jail() syscall — an extended chroot that also isolated the process from the host's process table, network stack, and user namespace. FreeBSD jails are still in active use today.

What chroot actually does (and doesn't)

What chroot isolates

Filesystem view. The process sees only the subtree under the new root.

That's it.

What chroot does NOT isolate

Process table. The jailed process can see (and signal) every other process on the host.

Network. Same interfaces, same routes, same firewall.

Users. UID 0 inside is UID 0 outside. Root in the jail is root on the host.

Mounts. The jailed process can mount and unmount filesystems if it has the privilege.

Combine those gaps with the fact that a process running as root inside a chroot can call chroot() again to break out, and you have the core security problem: chroot was never designed as a hard security boundary. It was a way to constrain a benign process to a tidy view of the filesystem.

The famous escape Inside a chroot, if you're root: mkdir foo; chroot foo; cd ../../../../..; chroot . — you're back at the real /. The chroot syscall doesn't change what "parent directory" means at the kernel level; it only changes where / resolves to for path lookups.

What replaced chroot

Linux gradually grew a set of kernel features that, taken together, provide what chroot was reaching for and more:

Put namespaces and cgroups together, wrap them in tooling that builds and runs filesystem images, and you have a container. That's all a container is, at the kernel level: a regular Linux process running inside several namespaces with cgroup limits applied. There's no virtual machine, no separate kernel; it's just very thorough scoping.

What you'll actually use

Where chroot still matters

chroot is not dead. It's just no longer the answer to "how do I sandbox a thing." It's still the right tool for:

The throughline

chroot was the first attempt at "let me give this process a smaller world." It worked well enough for benign cases and badly for adversarial ones. Modern containers are the answer to the same question, except they isolate everything the kernel can be asked to scope — filesystem, processes, network, users, resource limits — not just the filesystem path lookup.

You'll meet chroot in the wild via SFTP jails and recovery boots. You'll live in containers.

08Mounting drives — and what mapping means

On Linux, every piece of storage — a local disk, a USB drive, a network share, an ISO image — must be mounted at a directory before you can read from or write to it. The directory becomes the entry point; everything you do at that path under the hood reaches the storage device.

Windows administrators often ask whether "mounting" is the same as "mapping." The answer is yes, in spirit, and no, in implementation. We'll get to that.

What "mount" actually means

A new disk shows up to the kernel as a block device — something like /dev/sdb for a SATA disk or /dev/nvme0n1 for an NVMe drive. The disk usually has one or more partitions: /dev/sdb1, /dev/sdb2. Each partition holds a filesystem (ext4, xfs, ntfs, vfat).

Until you mount that filesystem, it's invisible to your shell. You can't cd into it. You can't read its files. The kernel knows it exists; it just hasn't been wired into the directory tree yet.

Discover what's there

root# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8:0 0 100G 0 disk ├─sda1 8:1 0 512M 0 part /boot/efi └─sda2 8:2 0 99.5G 0 part / sdb 8:16 0 500G 0 disk └─sdb1 8:17 0 500G 0 part

In that output, sda2 is the root filesystem (already mounted at /), and sdb1 is a 500 GB partition that's been formatted but not yet mounted — no mountpoint listed.

Mount it

root# mkdir -p /mnt/data root# mount /dev/sdb1 /mnt/data root# df -h /mnt/data Filesystem Size Used Avail Use% Mounted on /dev/sdb1 492G 73M 467G 1% /mnt/data

Now anything you do under /mnt/data — reading, writing, creating files — happens on /dev/sdb1. Unmount when finished:

root# umount /mnt/data

Discovery and inspection commands

CommandWhat it tells you
lsblkTree view of all block devices: disks, partitions, what they're mounted on.
df -hMounted filesystems with sizes used / free in human-readable units.
findmntPretty tree of every active mount, showing source, type, and options.
blkidUUIDs and labels for every block device; used to write reliable /etc/fstab entries.
mountWith no arguments, lists every currently mounted filesystem.

Persistent mounts — /etc/fstab

A mount made with the mount command lasts until the next reboot. To make a mount persistent — come up automatically every time the system starts — add an entry to /etc/fstab. Each line is one mount.

# /etc/fstab # <device> <mountpoint> <type> <options> <dump> <fsck> UUID=a8b2c3d4-5678-90ab-cdef-1234567890ab / ext4 defaults 0 1 UUID=c0d1e2f3-4567-89ab-cdef-0123456789ab /mnt/data ext4 defaults,nosuid,nodev 0 2 //fileserver/share /mnt/share cifs credentials=/root/.smbcred 0 0

Use UUID= rather than /dev/sdb1. Device names can change between reboots (the disk that was sdb last week could be sdc after you add another); UUIDs don't. Get the UUID from blkid.

After editing /etc/fstab, test before rebooting:

root# mount -a # Tries to mount every fstab entry that isn't already mounted. If there's # a syntax error or the device isn't there, you find out NOW instead of # after a reboot that fails to come up.

Useful mount options

OptionWhat it does
roMount read-only. Useful for evidence preservation in forensics, or for protecting a reference filesystem.
nosuidIgnore setuid/setgid bits on this filesystem. Stops a user from sneaking a setuid-root binary onto a removable disk.
nodevIgnore device files on this filesystem. Stops a malicious device node from granting unintended access.
noexecRefuse to execute binaries from this filesystem. Common on /tmp and user data drives.
noatimeDon't update access times on read. Significant performance improvement for high-read workloads.
defaultsShorthand for rw, suid, dev, exec, auto, nouser, async. The "normal" mount.

Network mounts — NFS and CIFS/SMB

You can mount storage that lives on another machine over the network. Two common protocols:

# NFS — the Unix native answer root# mount -t nfs fileserver:/exports/projects /mnt/projects # CIFS / SMB — talking to a Windows or Samba server root# mount -t cifs //fileserver/share /mnt/share -o credentials=/root/.smbcred,uid=alice,gid=teamA

Both are then accessible exactly the same way as a local mount — programs reading from /mnt/projects have no idea the bytes are crossing the network.

"Mount" vs "map" — the Windows question

In day-to-day conversation, the two terms are used interchangeably. The distinction comes from how the two operating systems organize their filesystem namespace.

Linux: mount

One unified filesystem tree starting at /. Any device, any network share, any image, gets attached at some directory within that tree.

A new disk doesn't get a letter — it gets a path: /mnt/data, /srv/projects, /home on its own disk, whatever you choose.

The kernel concept is "mount" — attaching a filesystem at a directory.

Windows: map

Drive letters: C:, D:, E:. Each device or share gets its own top-level letter.

net use Z: \\fileserver\share "maps" the network share to drive Z:. Now Z: is a top-level namespace just like C:.

The OS concept is "map" — assigning a network resource to a drive letter.

The reason this question keeps coming up: Windows can also mount a volume into an empty folder on NTFS (Disk Management → Change Drive Letter and Paths → Mount in the following empty NTFS folder), which behaves much like Linux mounting. And Linux can use automounters to make drives appear under /mnt/auto/ as if they had been "mapped." So the line between the two terms is blurrier than vocabulary alone suggests. The cleanest answer:

Why mount something in the first place

Four typical reasons to mount a drive:

The mental model

Linux's filesystem is one tree. Mounting is how anything new joins that tree. The directory you mount onto is just an attachment point — the storage itself can be a local disk, a partition, a remote share, an encrypted image, or a tmpfs filesystem in RAM. The semantics are the same once it's mounted.

"Mapping," in the Windows sense, is the equivalent operation in an OS that uses drive letters instead of a unified tree.

References

Formatted in APA 7. Pattern to memorize: Author(s). (Year). Title of work (Identifier). Publisher. URL. Names are alphabetized by the first author's last name; italics on the work title, not on the author or publisher.

  1. FreeBSD Project. (n.d.). jail(8): FreeBSD system manager's manual. https://www.freebsd.org/cgi/man.cgi?jail
  2. Grassi, P. A., Fenton, J. L., Newton, E. M., Perlner, R. A., Regenscheid, A. R., Burr, W. E., Richer, J. P., Lefkovitz, N. B., Danker, J. M., Choong, Y.-Y., Greene, K. K., & Theofanos, M. F. (2017). Digital identity guidelines: Authentication and lifecycle management (NIST Special Publication No. 800-63B, Rev. 3). National Institute of Standards and Technology. https://doi.org/10.6028/NIST.SP.800-63b
  3. Kerrisk, M. (n.d.-a). fstab(5): Linux manual page. Linux man-pages project. https://man7.org/linux/man-pages/man5/fstab.5.html
  4. Kerrisk, M. (n.d.-b). mount(8): Linux manual page. Linux man-pages project. https://man7.org/linux/man-pages/man8/mount.8.html
  5. Kerrisk, M. (n.d.-c). namespaces(7): Linux manual page. Linux man-pages project. https://man7.org/linux/man-pages/man7/namespaces.7.html
  6. OpenBSD Project. (n.d.). sshd_config(5): OpenSSH daemon configuration file. https://man.openbsd.org/sshd_config
  7. shadow-maint. (n.d.). shadow-utils [Source code repository]. GitHub. https://github.com/shadow-maint/shadow
  8. Wirzenius, L., Oja, J., Stafford, S., & Weeks, A. (2004). The Linux system administrator's guide (Version 0.9). The Linux Documentation Project. https://tldp.org/LDP/sag/html/index.html