A graphic of the sudo linux command.

sudo runs one command as another user, normally root, after checking that you are allowed to. The point is not convenience — it is that nobody needs to know the root password, every privileged action is attributable to a person, and permissions can be granted narrowly rather than all at once.

sudo and su are different

sudosu
Password asked forYoursThe target user’s
ScopeOne commandA whole shell
LoggedEvery invocationOnly the switch
GranularityPer user, per commandAll or nothing

That is why most distributions now ship with the root password locked and administration done through sudo. If three people administer a server, sudo means three revocable grants and an audit trail, instead of one shared secret that has to be changed whenever anyone leaves.

Everyday use

sudo systemctl restart nginx     # one command as root
sudo -u www-data ls /var/www     # as a specific user
sudo -i                          # a root login shell
sudo -s                          # a root shell, keeping your environment
sudo -l                          # what am I allowed to run
sudo -k                          # forget the cached authentication
sudo !!                          # re-run the previous command with sudo

sudo !! is the one you will use ten times a day, and sudo -l is the one worth knowing when you land on an unfamiliar machine — it prints exactly what your account may do.

After a successful authentication, sudo remembers you for a while — fifteen minutes by default, per terminal. That is why the password prompt seems to appear unpredictably.

The redirection trap

sudo echo "127.0.0.1 test" >> /etc/hosts
bash: /etc/hosts: Permission denied

This surprises everyone once. The shell sets up the redirection before sudo runs anything, so the file is opened by your shell, as you, without privileges. sudo elevated echo — which was never the part that needed elevating.

# Append
echo "127.0.0.1 test" | sudo tee -a /etc/hosts

# Overwrite
echo "contents" | sudo tee /etc/motd

# Discard the echoed output
echo "contents" | sudo tee /etc/motd > /dev/null

# Or elevate the whole shell command
sudo sh -c 'echo "127.0.0.1 test" >> /etc/hosts'

The same logic explains why sudo cmd1 | cmd2 only elevates cmd1, and why a shell glob like sudo cp /root/* fails — the shell expands it as you, before sudo is involved.

Editing sudoers

Never open /etc/sudoers in an editor directly. A syntax error in that file can lock every administrator out of privilege escalation on the machine, and if the root account is disabled you may have no way back in short of a rescue boot.

sudo visudo                              # edits with a syntax check before saving
sudo visudo -f /etc/sudoers.d/deploy      # a drop-in file, same protection
sudo visudo -c                            # check the current configuration

visudo validates the file and refuses to install a broken one. Prefer drop-in files under /etc/sudoers.d/ to editing the main file: they survive package upgrades, and one bad file is easier to remove than a mangled sudoers.

Keep a second root session open while changing sudo configuration, exactly as with sshd. Test in the new terminal; if it went wrong, fix it in the old one.

The syntax

kevin    ALL=(ALL:ALL) ALL
                     └─ which commands
            └────────── which users:groups they may become
        └─────────────── on which hosts
└─────────────────────── who
# Everyone in a group gets full rights
%sudo    ALL=(ALL:ALL) ALL          # Debian, Ubuntu
%wheel   ALL=(ALL)     ALL          # Fedora, RHEL, Arch

# One user, two specific commands, no password
deploy   ALL=(ALL) NOPASSWD: /bin/systemctl restart myapp, /bin/systemctl status myapp

# Run as a particular user rather than root
kevin    ALL=(www-data) /usr/bin/php

The group is the normal way in. On Debian and Ubuntu that is sudo; on Fedora, RHEL and Arch it is wheel. Adding someone is usually all you need:

sudo usermod -aG sudo kevin       # Debian, Ubuntu<br>sudo usermod -aG wheel kevin      # Fedora, RHEL, Arch

The -a matters enormously. Without it, usermod -G replaces every secondary group the user has rather than adding one, which is a memorable way to remove your own access.

Group membership applies at login, so the user must log out and back in before it takes effect.

Restricting commands is harder than it looks

A rule like deploy ALL=(ALL) NOPASSWD: /usr/bin/vim looks like it grants a little. It grants everything: many programs can launch a shell from inside themselves, and a shell launched by a root process is a root shell. Editors, pagers, and anything with a scripting feature all fall into this category — vim, less, find, awk, tar, package managers, and language interpreters among them.

The rule of thumb: grant a specific command with specific arguments, and prefer commands that do exactly one thing. Allowing systemctl restart myapp is defensible. Allowing systemctl with any arguments is much less so, and allowing an editor is equivalent to granting full root.

Where someone genuinely needs to edit a file as root, sudoedit exists for exactly that: it copies the file, runs your normal unprivileged editor on the copy, and writes it back with privileges.

kevin  ALL=(ALL) sudoedit /etc/nginx/nginx.conf

NOPASSWD

NOPASSWD is necessary for automation — a deploy script cannot type a password. It is also the line most often written too broadly:

# Reasonable: one job, one command
deploy  ALL=(ALL) NOPASSWD: /usr/bin/systemctl reload nginx

# Not reasonable: anyone who compromises this account owns the machine
deploy  ALL=(ALL) NOPASSWD: ALL

The second form turns any weakness in that account — a leaked key, a vulnerable web application running as it — into immediate root. If you find it in a configuration you inherited, narrowing it is usually the highest-value security change available for the effort involved.

The environment

sudo deliberately builds a clean environment rather than passing yours through. Two consequences:

  • secure_path overrides PATH. A command in ~/bin or a version manager’s shims will not be found under sudo, even though it works normally. Use the full path.
  • Shell aliases and functions do not apply. sudo ll fails because ll is an alias your shell expands, and sudo never sees it.
sudo -E command                  # preserve your environment (use sparingly)
sudo env "PATH=$PATH" command    # preserve just PATH
sudo printenv                    # see what the command actually gets

-E is convenient and worth thinking about before using: passing your whole environment into a root process is precisely what env_reset exists to prevent.

Who did what

sudo journalctl -t sudo                   # systemd systems
sudo grep sudo /var/log/auth.log          # Debian, Ubuntu
sudo grep sudo /var/log/secure            # Fedora, RHEL
sudo journalctl _COMM=sudo --since today

Every invocation is logged with the user, the working directory, the target user and the exact command line. This is the main practical benefit of sudo over a shared root password, and it is worth actually reading occasionally rather than only after something has gone wrong. See systemctl for more on journalctl.

Gotchas

“user is not in the sudoers file”

This incident will be reported — and it means exactly what it says. Either the account is not in the right group, or it was added and has not logged out since. Check with groups or id.

sudo su – is redundant

It works, but sudo -i does the same thing more directly and is what the tool intends. Nothing breaks either way; it is just a habit worth updating.

Files created as root belong to root

Run a build or a package install with sudo in your home directory and you will find files you can no longer write. sudo chown -R $USER:$USER . puts it right — see file permissions. Better still, do not use sudo for things that do not need it.

The lecture, and the timeout

Both are configurable in sudoers — Defaults lecture=never, and Defaults timestamp_timeout=30 for a longer or shorter cache. Setting the timeout to -1 means it never expires, which quietly removes a useful safety property on a shared machine.

Quick reference

sudo command                     # as root
sudo -u user command             # as someone else
sudo -i                          # root login shell
sudo -l                          # what am I allowed to do
sudo !!                          # repeat the last command with sudo
sudo -k                          # forget the cached password

echo x | sudo tee -a /etc/file   # redirect into a root-owned file
sudo sh -c 'cmd > /etc/file'     # the alternative

sudo visudo                      # the only safe way to edit sudoers
sudo visudo -f /etc/sudoers.d/x  # a drop-in
sudo visudo -c                   # validate
sudoedit /etc/file               # edit as root with your own editor

sudo usermod -aG sudo alice      # grant (Debian) — note the -a
sudo usermod -aG wheel alice     # grant (RHEL, Arch)
sudo journalctl -t sudo          # who ran what

Related

  • File permissions — what root can do, and why files created under sudo cause trouble.
  • ssh — disabling root login and relying on sudo instead.
  • systemctl — the most common thing people are granted narrow sudo rights for.
  • cron — scheduled jobs run as a user, which is often the better answer than NOPASSWD.
  • polkit — the desktop equivalent, behind graphical authentication prompts.