$linuxjunkies
>

How to Configure sudo Safely

Learn to configure sudo securely using visudo, sudoers syntax, per-command restrictions, NOPASSWD, and drop-in files to enforce least-privilege access on Linux.

IntermediateUbuntuDebianFedoraArch9 min readUpdated June 7, 2026

Before you start

  • ▸A non-root user account that currently has sudo or root access
  • ▸Basic familiarity with a terminal text editor (nano, vim, etc.)
  • ▸Root or existing sudo access to apply changes

sudo is the gatekeeper between a normal user account and root-level access. A misconfigured sudoers file can hand an attacker a trivial privilege escalation path, or lock out legitimate administrators from a production system. Neither outcome is acceptable. This guide walks through editing sudoers safely with visudo, understanding the syntax in depth, writing per-command rules, and using NOPASSWD only where it is genuinely justified.

Why You Must Use visudo

The sudoers file is parsed every time sudo is invoked. A syntax error does not crash a daemon — it silently breaks all sudo access. visudo validates the file before saving, preventing you from locking yourself out. Never edit /etc/sudoers directly with a plain text editor.

sudo visudo

By default visudo uses the editor defined in EDITOR or VISUAL. To override once:

sudo EDITOR=nano visudo

To change the default permanently, add this to /etc/sudoers (via visudo):

Defaults editor=/usr/bin/nano

Understanding sudoers Syntax

Every non-comment line in sudoers follows one of two forms: a Defaults entry or a rule entry.

The Rule Format

A privilege rule looks like this:

WHO  WHERE=(AS_WHOM)  COMMANDS
  • WHO — a username, a %groupname, or an alias.
  • WHERE — the hostname or ALL. Use ALL for most setups.
  • AS_WHOM — the target user (and optionally group) to run as. (ALL:ALL) means any user and any group; (root) means root only.
  • COMMANDS — a comma-separated list of absolute paths, or ALL.

The classic wheel/sudo group line that ships with most distros:

%sudo   ALL=(ALL:ALL) ALL    # Debian/Ubuntu group
%wheel  ALL=(ALL:ALL) ALL    # Fedora/RHEL/Arch group

Defaults Entries

Defaults tune sudo's behaviour globally or per-user. Several are worth setting explicitly:

# Require re-authentication after 5 minutes of inactivity (default is 15)
Defaults timestamp_timeout=5

# Log each sudo invocation to syslog with the full command
Defaults log_output

# Prevent environment variable injection attacks
Defaults env_reset
Defaults env_keep += "LANG LC_ALL LC_MESSAGES TERM"

# Insult users who type the wrong password (optional, morale-based security)
Defaults insults

env_reset is enabled by default on most distros; verify it is present and not overridden.

Drop-in Files: /etc/sudoers.d/

Rather than editing /etc/sudoers directly for every change, place per-role or per-application rules in the /etc/sudoers.d/ directory. Each file is included automatically. This makes auditing and configuration management (Ansible, Puppet, etc.) far cleaner.

sudo visudo -f /etc/sudoers.d/webops

visudo -f applies the same syntax check to drop-in files. File names in sudoers.d must not contain a dot or end with a tilde — both cause sudo to silently ignore the file.

# Correct
/etc/sudoers.d/webops

# Will be ignored by sudo
/etc/sudoers.d/webops.conf
/etc/sudoers.d/webops~

Per-Command Rules

Granting full ALL access is appropriate for trusted admins. For service accounts, automation users, and junior operators, restrict to specific commands only.

Single Command

# Allow alice to restart nginx only
alice  ALL=(root) /usr/bin/systemctl restart nginx

Multiple Commands

# Allow the 'dbops' group to manage the postgresql service
%dbops  ALL=(root) /usr/bin/systemctl start postgresql, \
                   /usr/bin/systemctl stop postgresql, \
                   /usr/bin/systemctl restart postgresql, \
                   /usr/bin/systemctl status postgresql

Command Aliases for Readability

When the same command set appears in multiple rules, define a Cmnd_Alias:

Cmnd_Alias NGINX_CTL = /usr/bin/systemctl start nginx, \
                       /usr/bin/systemctl stop nginx, \
                       /usr/bin/systemctl restart nginx, \
                       /usr/bin/systemctl reload nginx

%webops  ALL=(root) NGINX_CTL

Blocking Dangerous Escape Paths

Allowing a user to run an editor, shell, or interpreter via sudo effectively gives them unrestricted root access — they can drop to a shell or write arbitrary files. Be explicit about exclusions with !:

# Dangerous: do not do this
bob  ALL=(root) /usr/bin/vim

# If you genuinely need file editing, use sudoedit instead
bob  ALL=(root) sudoedit /etc/nginx/nginx.conf

sudoedit (or sudo -e) copies the file to a temporary location, opens it as the invoking user, then copies it back — no root-owned editor process that can be escaped.

Using NOPASSWD Carefully

NOPASSWD tells sudo not to prompt for a password before running the specified commands. It is appropriate for:

  • Automated scripts and CI/CD pipelines where there is no interactive session.
  • Specific, narrow, low-risk commands (e.g., reading a status file).

It is not appropriate as a blanket convenience for human admin accounts. An unattended terminal with a passwordless-sudo account is a trivial escalation vector.

Syntax

# CI runner: restart the app service without a password
ci-runner  ALL=(root) NOPASSWD: /usr/bin/systemctl restart myapp

# Deployment user: limited deployment commands, no password
deploy     ALL=(root) NOPASSWD: /usr/bin/systemctl reload nginx, \
                                /usr/bin/systemctl restart myapp

Mixing PASSWD and NOPASSWD

You can require a password for most commands but not for specific ones on the same line:

alice  ALL=(root) PASSWD: ALL, NOPASSWD: /usr/bin/systemctl status nginx

User and Host Aliases

For larger environments, aliases reduce repetition and make the policy readable:

User_Alias  WEBTEAM  = alice, bob, carol
User_Alias  DBAGROUP = dave, eve
Host_Alias  WEBSERVERS = web1, web2, web3

WEBTEAM   WEBSERVERS=(root) NGINX_CTL
DBAGROUP  ALL=(root)        /usr/bin/systemctl restart postgresql

Verifying Your Configuration

Check what sudo privileges a specific user has without impersonating them:

sudo -l -U alice

Typical output (will vary):

User alice may run the following commands on hostname:
    (root) /usr/bin/systemctl restart nginx

Validate the entire sudoers configuration (including all drop-in files) for syntax errors:

sudo visudo -c

A clean config returns: parsed OK.

Auditing sudo Usage

Every sudo invocation is logged. On systemd-based systems:

journalctl -t sudo --since today

On systems writing to syslog:

grep sudo /var/log/auth.log       # Debian/Ubuntu
grep sudo /var/log/secure         # Fedora/RHEL

Troubleshooting

Locked out of sudo

If you save a broken sudoers file outside of visudo, boot to a root shell via the GRUB recovery menu, or use another session where you are already root, then run visudo to fix the file.

"sudo: command not found" for a valid binary

sudo resets PATH by default (env_reset). Use the full absolute path in your rule and in the command invocation, or add the needed path to secure_path:

Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

Drop-in file silently ignored

Confirm the filename contains no dots and does not end in a tilde. Check that the main sudoers file still contains the #includedir /etc/sudoers.d directive (note: despite the #, this is not a comment — it is a sudo directive).

grep includedir /etc/sudoers
tested on:Ubuntu 24.04Debian 12Fedora 40Arch 2024.05

Frequently asked questions

Is it safe to give a user NOPASSWD: ALL?
No. NOPASSWD: ALL means any process running as that user — including malware — can gain root silently. Restrict NOPASSWD to specific, low-risk commands on dedicated automation accounts only.
What is the difference between sudo -i, sudo -s, and sudo su?
All three effectively give an interactive root shell, but they set different environments and are logged differently. From a sudoers perspective, all three require the user to have ALL or shell access — which is why granting them to untrusted users is dangerous regardless of method.
Why do my changes to /etc/sudoers.d/ seem to have no effect?
The filename almost certainly contains a dot or a tilde. Rename the file to contain only letters, digits, hyphens, or underscores, then verify the main /etc/sudoers still has the #includedir /etc/sudoers.d line.
Can I restrict sudo to specific source terminals or SSH sessions?
Yes. The NOTTY and requiretty Defaults options control whether sudo requires a real TTY. You can also scope rules by hostname in multi-server environments using Host_Alias, though this is no substitute for host-level access control.
How do I recover if I accidentally break the sudoers file?
Boot into single-user mode or a GRUB recovery shell (which gives a root prompt without requiring sudo), then run visudo to correct the syntax error. On cloud instances, use the provider's emergency console or a recovery disk.

Related guides