Skip to main content

Multi-Developer Access with Least Privilege

Prerequisites

RequirementDetails
Access Level:Root or sudo privileges.
Software:SSH + OpenSSH server.
Knowledge:User/group management, /etc/passwd, sudoers.
Setup:WordPress installed in /var/www/html or /srv/wordpress/.

Why and When

  • Why it matters: Prevent accidental or malicious changes outside project scope.
  • Why this approach: A secure setup for multiple developers on one VPS.
  • When to use it: Onboarding new devs, agencies, contractors.

Core Principles of Least Privilege

  1. Separation of duties – no shared accounts.
  2. Group-based access – devs only access project files.
  3. No root for devs – only lead/admin can sudo.
  4. Auditability – track who did what.
  5. Temporary access – auto-expire contractor accounts.
  6. Key-based auth – avoid weak passwords.

Step-by-Step Implementation

Create a group for developers

sudo groupadd wpdevs
getent group wpdevs

Output:

wpdevs:x:1005:

Add developers to group

sudo useradd -m -s /bin/bash -G wpdevs dev1
sudo useradd -m -s /bin/bash -G wpdevs dev2
id dev1

Output:

uid=1001(dev1) gid=1001(dev1) groups=1001(dev1),1005(wpdevs)

Assign WordPress ownership to web server + dev group

sudo chown -R www-data:wpdevs /var/www/html
sudo chmod -R 775 /var/www/html

Output:

drwxrwxr-x 5 www-data wpdevs 4096 Sep 27 10:00 html

Explanation: Web server = www-data, devs = wpdevs.

Restrict sudo to only lead developer

sudo visudo

Add:

dev1 ALL=(ALL) ALL
%wpdevs ALL=(ALL) NOPASSWD: /usr/bin/wp

Explanation:

  • dev1 = lead dev → full sudo.
  • Other devs (wpdevs) can only run wp CLI.

Restrict contractors with expiry

sudo useradd -m -e 2025-12-31 -G wpdevs contract1
chage -l contract1 | grep "Account expires"

Output:

Account expires : Dec 31, 2025

Enforce no-login for service accounts

sudo usermod -s /usr/sbin/nologin www-data
grep www-data /etc/passwd

Output:

www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin

Use ACLs for fine-grained access (optional)

sudo setfacl -m u:dev2:rwx /var/www/html/wp-content/themes
getfacl /var/www/html/wp-content/themes | grep dev2

Output:

user:dev2:rwx

Track current sessions

w

Output:

USER TTY FROM LOGIN@ WHAT
dev1 pts/0 192.168.1.10 10:30 -bash

View login history

last -n 3

Output:

dev2 pts/1 192.168.1.20 Fri Sep 27 09:00 still logged in

Check privileges of devs

sudo -l -U dev2

Output:

User dev2 may run the following commands:
(ALL : ALL) /usr/bin/wp

WordPress-Specific Access Scenarios

ScenarioSetupBenefit
Theme developerACL → rwx on wp-content/themesDev can edit only themes
Plugin devACL → rwx on wp-content/pluginsPrevents touching core WP
Media managerGroup access only to uploads/Contractor can upload media
Lead devFull sudo via visudoHandles upgrades & server restarts
CI/CD botSFTP chroot + wp CLIAutomated deploys, no shell access

Best Practices

  1. Use group-based permissions for simplicity.
  2. Give least possible sudo rules (e.g., only systemctl restart nginx).
  3. Regularly audit with id, groups, w, last.
  4. Rotate contractor accounts with expiry (e).
  5. Log and monitor /var/log/auth.log for sudo activity.
  6. Disable root SSH login, enforce sudo.
  7. Use key-based SSH for all dev accounts.

Quick Lab

# Create group
sudo groupadd wpdevs

# Add devs
sudo useradd -m -s /bin/bash -G wpdevs dev1
sudo useradd -m -s /bin/bash -G wpdevs dev2

# Assign WordPress ownership
sudo chown -R www-data:wpdevs /var/www/html
sudo chmod -R 775 /var/www/html

# Verify access
id dev1
ls -ld /var/www/html

Expected Highlights:

uid=1001(dev1) gid=1001(dev1) groups=1001(dev1),1005(wpdevs)
drwxrwxr-x 5 www-data wpdevs 4096 Sep 27 10:00 /var/www/html

Cheat Sheet

CommandPurpose
groupadd wpdevsCreate developer group
useradd -G wpdevs dev1Add developer
chown -R www-data:wpdevs /var/www/htmlSet WP ownership
chmod -R 775 /var/www/htmlAllow group writes
visudoConfigure sudo rules
useradd -e 2025-12-31 contract1Expiring contractor
setfacl -m u:dev2:rwx pathFine-grained access
wView current sessions
lastView login history
sudo -l -U userCheck sudo rights

Mini Quiz

  1. Why should each developer get a separate account instead of sharing one?
  2. What is the benefit of putting WordPress files under www-data:wpdevs with 775 permissions?
  3. How do you ensure contractors lose access after a project ends?
  4. Which command checks if a developer has sudo rights?
  5. Why is it dangerous to give all developers full sudo access?