Every process on a Linux server runs under a user identity. When that identity has too much power, a single compromised application can escalate to root and take over the entire machine. When it has too little, legitimate operations break and your team wastes hours debugging permission errors.
Linux user and group management is the mechanism that controls who can do what on your server. This guide walks through creating users, organizing them into groups, setting file permissions, configuring sudo access, and locking down authentication with PAM — all with practical commands you can run on a production system right now.
Why User and Group Management Matters for Servers
On a desktop, poor user management is an inconvenience. On a server, it is a security liability. The GitLab GraphQL vulnerability disclosed in August 2026 (CVE-2026-19478, CVSS 9.4) allowed unauthenticated attackers to delete public projects — a stark reminder that access control failures at any layer cascade into real damage.
On Linux servers specifically, proper user management delivers three concrete benefits:
- Reduced blast radius. If a web application running as the
www-datauser gets exploited, the attacker can only access files that user owns. Without proper user isolation, every service shares the same permissions, and one breach becomes total compromise. - Audit trail. When five administrators all log in as
root, you cannot tell who changed the Nginx config at 3 AM. Individual user accounts create accountability through login logs and process ownership. - Compliance. Standards like CIS Benchmarks, SOC 2, and PCI DSS all require individual accountability and least-privilege access. Auditors will flag shared root access immediately.
The Linux Foundation’s Akrites initiative, launched in June 2026 and going live in September, specifically emphasizes proper access control as a foundational element of supply chain security (Infosecurity Magazine). Getting user management right is not optional — it is the baseline.
Understanding the Linux User Model
Linux identifies every user by a numeric UID (User ID) and every group by a GID (Group ID). The system stores these mappings in three critical files:
| File | Purpose | Key Fields |
|---|---|---|
/etc/passwd | User account database | username, UID, GID, home dir, shell |
/etc/shadow | Password hashes and aging | username, encrypted password, expiry dates |
/etc/group | Group membership | group name, GID, member list |
You can inspect any of these with cat, but modern tools provide better interfaces:
# View a specific user's entry
getent passwd deploy
# View a specific group
getent group docker
# List all groups a user belongs to
groups deploy
Linux reserves UIDs below 1000 for system accounts (like nobody, daemon, and www-data). Your human users should start at UID 1000 or higher. This convention matters because some scripts and tools filter based on UID ranges.
Creating and Managing User Accounts
Adding a New User
The useradd command creates a new user. On most modern distributions, the default settings are reasonable, but explicitly specifying a home directory and shell is good practice:
# Create a user with a home directory and bash shell
sudo useradd -m -s /bin/bash deploy
# Set an initial password
sudo passwd deploy
The -m flag creates the home directory /home/deploy with default files copied from /etc/skel. Without it, the user has no home directory and cannot store personal configuration.
For interactive users who will SSH into the server, also set a proper shell:
# Verify the shell exists
cat /etc/shells
# Create with explicit shell
sudo useradd -m -s /bin/bash -c "Deploy Account" deploy
The -c flag adds a comment field, which is helpful when multiple administrators manage the same server and you need to know who each account belongs to.
Modifying Existing Users
Use usermod to change attributes on an existing account. Common modifications include adding group memberships, changing the shell, or locking an account:
# Add user to the docker group (groupadd first if it doesn't exist)
sudo usermod -aG docker deploy
# Change the default shell
sudo usermod -s /usr/bin/zsh deploy
# Lock an account (disable password login)
sudo usermod -L deploy
# Unlock an account
sudo usermod -U deploy
The -aG flag is critical. Without -a, usermod -G docker deploy replaces all supplementary groups instead of adding to them. This is one of the most common mistakes in user management scripts.
Deleting Users
When an employee leaves or a service account is no longer needed, remove it cleanly:
# Remove user and home directory
sudo userdel -r deploy
# Remove user but keep home directory (for shared data)
sudo userdel deploy
The -r flag deletes the home directory and mail spool. On production servers, verify that no running processes belong to the user before deletion:
# Check for running processes
ps aux | grep -w deploy
# Check for files owned by the user
sudo find / -user deploy -type f 2>/dev/null
Group Management for Access Control
Groups are the primary mechanism for organizing access permissions. Rather than assigning permissions to individual users, assign them to groups and add users to those groups.
Creating and Managing Groups
# Create a new group
sudo groupadd deploy
# Create a group with a specific GID
sudo groupadd -g 5000 deploy
# Rename a group
sudo groupmod -n production deploy
# Delete a group
sudo groupdel deploy
Practical Group Strategies for Servers
A well-organized server uses groups to enforce separation of concerns. Here is a pattern that works well for teams managing multiple services:
# Service-specific groups
sudo groupadd webteam
sudo groupadd dbteam
sudo groupadd devops
# Add users to appropriate groups
sudo usermod -aG webteam alice
sudo usermod -aG dbteam bob
sudo usermod -aG devops charlie
# Set directory ownership
sudo chown -R root:webteam /var/www
sudo chmod -R 2775 /var/www
The 2775 permission set deserves explanation. The leading 2 sets the SGID bit, which means new files inherit the group ownership of the parent directory rather than the creating user’s primary group. This ensures that everyone in webteam can read and modify files in /var/www without needing to be in each other’s groups.
The www-data Pattern
Most web servers (Apache, Nginx) run as the www-data user. Your deployment user needs write access to the web root, but the web server process needs read access. Here is how to set this up:
# Add deploy user to www-data group
sudo usermod -aG www-data deploy
# Set directory permissions
sudo chown -R www-data:www-data /var/www/html
sudo chmod -R 775 /var/www/html
# Deploy user can now write files that the web server can read
File Permissions and Ownership
Linux file permissions control three operations for three categories of users: owner, group, and others. Understanding these is prerequisite to effective user management.
Reading Permissions
ls -la /var/www/html/index.html
# -rw-r--r-- 1 www-data www-data 4096 Aug 21 10:00 index.html
The permission string breaks down as:
-rw-— owner can read and writer--— group can read onlyr--— others can read only
Setting Permissions
# Symbolic mode: give group write access
chmod g+w /var/www/html/config.php
# Numeric mode: owner rwx, group r-x, others ---
chmod 750 /etc/nginx/nginx.conf
# Recursive: apply to all files and directories
chmod -R 755 /var/www/html
For directories, the execute bit has a special meaning: it allows traversing into the directory. A directory with 750 permissions means owner can enter and list, group can enter and list, and others cannot enter at all.
Special Permission Bits
Three special bits extend the basic permission model:
- SUID (4000): Runs the executable as the file owner.
/usr/bin/passwduses SUID so ordinary users can change their own password. - SGID (2000): On executables, runs as the group owner. On directories, forces new files to inherit the directory’s group.
- Sticky bit (1000): On directories like
/tmp, prevents users from deleting files they do not own.
# Find files with SUID bit set (security audit)
sudo find / -perm -4000 -type f 2>/dev/null
# Set SGID on a shared directory
sudo chmod g+s /shared/project-files
SUID files are a common escalation vector. Regularly auditing them is a security essential — see our Linux security hardening guide for a full checklist.
Configuring Sudo Access
Running everything as root is the fastest way to create a security disaster. Sudo lets specific users run specific commands with elevated privileges, without sharing the root password.
Basic Sudo Configuration
The sudoers file (/etc/sudoers) controls who can do what. Never edit it directly — always use visudo, which validates syntax before saving:
sudo visudo
A minimal sudoers configuration for a deployment user:
# Allow deploy user to run any command (use sparingly)
deploy ALL=(ALL:ALL) ALL
# Allow webteam to restart Nginx without password
%webteam ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx
# Allow dbteam to run PostgreSQL commands
%dbteam ALL=(postgres) /usr/bin/pg_*
Sudoers Best Practices
The principle of least privilege applies directly to sudo configuration. Give users only the commands they actually need:
# Too broad — gives full root access
deploy ALL=(ALL:ALL) ALL
# Better — limits to deployment-specific commands
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx, \
/usr/bin/systemctl restart php-fpm, \
/usr/bin/cp /tmp/app/* /var/www/html/
Use NOPASSWD only for automated scripts and CI/CD pipelines. For human administrators, requiring a password on each sudo invocation creates a natural audit trail and a moment of hesitation before making system changes.
Auditing Sudo Usage
Sudo logs every invocation to /var/log/auth.log (Debian/Ubuntu) or /var/log/secure (RHEL/CentOS):
# Recent sudo usage
grep "sudo" /var/log/auth.log | tail -20
# Failed sudo attempts
grep "sudo.*COMMAND" /var/log/auth.log | grep "NOT in sudoers"
For centralized logging, ship sudo logs to a remote syslog server or a tool like the ELK stack. Individual server logs are useful for immediate debugging but insufficient for long-term audit requirements.
PAM: Pluggable Authentication Modules
PAM is the framework that sits between login requests and the actual authentication mechanism. It controls password policies, account restrictions, and session behavior.
Key PAM Configuration Files
PAM configuration lives in /etc/pam.d/. Each service (SSH, sudo, login) has its own configuration file:
ls /etc/pam.d/
# common-auth common-password sshd sudo login ...
Enforcing Password Policies with PAM
The pam_pwquality module controls password complexity. Edit /etc/pam.d/common-password:
# Require minimum 12 characters, at least one uppercase, one lowercase, one digit
password requisite pam_pwquality.so retry=3 minlen=12 ucredit=-1 lcredit=-1 dcredit=-1
For account expiry and login restrictions, use pam_loginuid and pam_lastlog:
# Show last login time and warn about failed attempts
session required pam_lastlog.so showfailed
SSH Hardening with PAM
PAM integrates with SSH to enforce additional restrictions. In /etc/pam.d/sshd:
# Only allow users in the sshusers group
auth required pam_listfile.so item=user sense=allow file=/etc/ssh/users_allowed
This is a powerful pattern: instead of managing SSH access through firewall rules alone, you control it at the PAM layer. Combined with our SSH server hardening guide, this creates multiple layers of access control.
Managing System Accounts and Service Users
Every daemon on your server runs as a system user. Managing these accounts correctly prevents privilege escalation through service compromise.
Identifying System Accounts
# List all system accounts (UID < 1000)
awk -F: '$3 < 1000 {print $1}' /etc/passwd
# Check which system accounts have login shells
awk -F: '$3 < 1000 && $7 != "/usr/sbin/nologin" {print $1, $7}' /etc/passwd
System accounts with login shells are a red flag. They should generally have /usr/sbin/nologin or /bin/false as their shell:
# Lock a system account
sudo usermod -s /usr/sbin/nologin nobody
Creating Service-Specific Accounts
For critical services, create dedicated user accounts rather than running everything as www-data:
# Create dedicated user for the application
sudo useradd -r -s /usr/sbin/nologin -d /opt/myapp -m myapp
# Set ownership
sudo chown -R myapp:myapp /opt/myapp
# Create a systemd service running as this user
cat <<EOF | sudo tee /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/run
Restart=always
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
The -r flag in useradd creates a system account with a UID from the system range. The -s /usr/sbin/nologin ensures nobody can log in interactively as this user.
User Namespace Isolation for Containers
Modern container runtimes use Linux user namespaces to isolate container processes from the host. This is especially relevant in 2026 as Docker rootless mode and Podman become standard practice.
How User Namespaces Work
A user namespace maps a range of UIDs inside the container to a different range on the host. A process that appears to run as root (UID 0) inside the container might actually run as UID 100000 on the host, with no real root privileges.
# Check if user namespaces are enabled
cat /proc/sys/kernel/unprivileged_userns_clone
# Enable if disabled (Debian/Ubuntu)
echo "kernel.unprivileged_userns_clone=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Configuring Subordinate UIDs
For rootless containers, the system needs a range of UIDs mapped to the unprivileged user:
# Add UID/GID mapping for the deploy user
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 deploy
# Verify the mapping
cat /etc/subuid
cat /etc/subgid
This configuration allows the deploy user to run rootless Docker or Podman containers with proper UID mapping, reducing the attack surface significantly. See our Docker VMM guide for details on Docker’s latest virtualization changes.
Troubleshooting Common User Management Issues
”Permission denied” When Running Commands
The most common issue is forgetting to add a user to the right group:
# Check which groups a user belongs to
groups deploy
# Check what group owns a file
ls -la /var/www/html/
# Fix: add user to the correct group
sudo usermod -aG www-data deploy
# The user must log out and back in for group changes to take effect
Group membership changes do not apply to existing sessions. The user must log out and log back in, or use newgrp to activate the new group in the current shell:
newgrp www-data
Home Directory Permission Issues
A common misconfiguration is home directories with 777 permissions:
# Wrong — anyone can read/write
chmod 777 /home/deploy
# Correct — only the owner can access
chmod 750 /home/deploy
If you inherit a server with broken home directory permissions, audit them:
# Find home directories with open permissions
awk -F: '$3 >= 1000 {print $6}' /etc/passwd | xargs ls -ld | grep -E "drwxrwxrwx|drwxrwxr-x"
Sudo Not Working After Group Changes
After adding a user to a new group, sudo rules referencing that group may not take effect until the user logs out and back in. This catches even experienced administrators:
# Verify the current effective groups
id
# Force group refresh without logout
exec newgrp sudo
Security Audit Checklist
Run these commands regularly to verify your user management configuration:
# 1. Find users with UID 0 (should only be root)
awk -F: '$3 == 0 {print $1}' /etc/passwd
# 2. Find users without passwords
awk -F: '($2 == "" || $2 == "!" || $2 == "*") {print $1}' /etc/shadow
# 3. Find users with login shells that shouldn't have them
awk -F: '$3 >= 1000 && $7 != "/usr/sbin/nologin" && $7 != "/bin/bash" && $7 != "/bin/sh" {print $1, $7}' /etc/passwd
# 4. Find world-writable files outside /tmp
find / -path /proc -prune -o -path /sys -prune -o -type f -perm -0002 -print 2>/dev/null
# 5. Check for SUID/SGID binaries
find / -perm /6000 -type f 2>/dev/null | head -20
# 6. List sudoers entries
grep -r "ALL" /etc/sudoers /etc/sudoers.d/ 2>/dev/null
Integrate these checks into a monitoring script or a cron job that runs weekly. The CIS Benchmark for Linux provides a comprehensive set of user management checks that auditors expect to see.
Wrapping Up
User and group management is the first line of defense on any Linux server. Start with dedicated service accounts, enforce the principle of least privilege through groups, configure sudo with minimal permissions, and audit regularly. These commands and configurations work across Ubuntu, Debian, CentOS, and RHEL — the core principles are distribution-agnostic, with only minor syntax differences between families.
The investment in proper user management pays off when something goes wrong. A compromised web application running as www-data with no write access to system files is an incident. The same application running as root is a catastrophe.
Further Reading
- Linux Security Hardening: Essential Practices for Production Servers — Complete hardening checklist including user management
- SSH Server Hardening: Securing Remote Server Access — SSH-specific access control and authentication
- Docker Rootless Mode Setup — Running containers without root privileges