Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Ubuntu User Management Guide

By Kokil Thapa | Last reviewed: August 2026

Managing user accounts securely is the foundation of any production Linux server. Whether you are deploying a Laravel application, hosting a WooCommerce store, or running a legal-tech portal, improper access controls lead to compromised systems and data breaches. This Ubuntu User Management Guide provides the exact commands and workflows I use daily on Ubuntu 24.04 LTS servers to create isolated accounts, delegate privileges safely, and enforce SSH-only authentication without relying on root.

On real client projects, from Laravel development to complex eCommerce platforms, I never deploy code as root. Every deployment pipeline uses a dedicated service account with restricted permissions. If you are setting up infrastructure for Nepali businesses or global clients, treating user management as an afterthought creates technical debt that compounds during audits or security incidents. The steps below reflect battle-tested patterns for Ubuntu 22.04 and 24.04 LTS environments current in 2026.

How do you create and configure standard users in Ubuntu?

Creating users correctly prevents permission issues later. While adduser offers an interactive wizard, useradd is preferable for automation scripts and CI/CD pipelines because it is non-interactive and deterministic. On a production web server hosting PHP applications, every developer or service needs its own account with a predictable home directory structure.

Create a user with proper defaults

// Create user with home directory and bash shell
sudo useradd -m -s /bin/bash -c "Deploy Account" deployer

// Set password (only if password auth is required temporarily)
sudo passwd deployer

// Verify user creation and groups
id deployer
getent passwd deployer

The -m flag creates the home directory (/home/deployer) and populates it with skeleton files from /etc/skel. Without this flag, the user exists but has no home directory, breaking SSH key placement and application config storage. The -s /bin/bash ensures an interactive shell; omitting it assigns /bin/sh which lacks features developers expect.

Understanding primary vs supplementary groups

Ubuntu assigns each user a private primary group matching their username. For web applications, add users to shared groups like www-data so they can read/write application files without changing ownership:

// Add existing user to www-data group
sudo usermod -aG www-data deployer

// Verify group membership (requires new session)
groups deployer
User Creation Workflowuseradd -m -sCreate Account/home/userHome + SkeletonPrimary Groupuser:userusermod -aGAdd to www-dataReady for SSH
Ubuntu User Management Guide: Standard user creation flow from account setup through group assignment to SSH readiness

A common mistake is forgetting the -a (append) flag with usermod -G. Without it, the user gets removed from all other supplementary groups, potentially breaking existing permissions. Always verify with groups username after modification, noting that changes only take effect in new login sessions.

How do you configure sudo privileges securely?

Granting blanket sudo access violates the principle of least privilege. In my experience maintaining legal-tech portals and eCommerce systems, most users need only specific commands: restarting PHP-FPM, clearing caches, or managing systemd services. Configure granular sudo rules instead of adding everyone to the sudo group.

Create dedicated sudoers files

Never edit /etc/sudoers directly. Use /etc/sudoers.d/ drop-in files validated with visudo -cf before saving:

// Create restricted sudo rule for deployer
sudo visudo -f /etc/sudoers.d/deployer-web

// Allow restart of php-fpm and nginx without password
deployer ALL=(ALL) NOPASSWD: /usr/sbin/service php8.3-fpm restart
deployer ALL=(ALL) NOPASSWD: /usr/sbin/service nginx reload

// Validate syntax before saving
sudo visudo -cf /etc/sudoers.d/deployer-web

This approach isolates permissions per role. If a deployer account is compromised, the attacker cannot install packages, modify system configs, or escalate beyond service restarts. For full-stack developers needing broader access during initial setup, grant temporary elevated privileges and revoke them once configuration stabilizes.

Sudo group vs custom rules comparison

Criteriasudo Group MembershipCustom Sudoers Rules
Scope of AccessUnrestricted root equivalentSpecific commands only
Audit Trail ClarityAll actions logged genericallyGranular command logging
Risk if CompromisedFull system takeoverLimited blast radius
Maintenance OverheadLow (add/remove group)Moderate (manage rule files)
Best ForSenior admins, emergency accessDevelopers, CI runners, services

For Nepali SMEs with small teams, I often see developers added to the sudo group for convenience. This works until a credential leak exposes the entire server. Invest time upfront defining precise rules; the maintenance cost pays off during security reviews or when onboarding junior staff who should not have unrestricted root access.

How do you set up SSH key authentication properly?

Password authentication is insecure and slow. Every production server I manage enforces SSH key-only access. Keys provide cryptographic proof of identity resistant to brute-force attacks, and they integrate cleanly with deployment tools like Deployer 7 and GitLab CI runners.

Generate and deploy keys correctly

// Generate Ed25519 key (preferred over RSA in 2026)
ssh-keygen -t ed25519 -C "deployer@project" -f ~/.ssh/id_ed25519_deploy

// Copy public key to remote server
ssh-copy-id -i ~/.ssh/id_ed25519_deploy.pub deployer@server-ip

// Or manually append to authorized_keys
cat ~/.ssh/id_ed25519_deploy.pub | ssh deployer@server-ip \
  "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

Ed25519 keys are faster and more secure than RSA-2048. They produce shorter signatures and resist side-channel attacks better. For legacy systems requiring RSA, use at least 4096 bits. Never reuse keys across environments; generate unique keys per project or service to limit exposure if one is compromised.

Set correct file permissions

SSH refuses keys with overly permissive file modes. This is the most frequent cause of "Permission denied (publickey)" errors on fresh setups:

  • ~/.ssh directory: 700 (drwx------)
  • ~/.ssh/authorized_keys: 600 (-rw-------)
  • Private keys locally: 600 (-rw-------)
  • Public keys: 644 (-rw-r--r--) — safe to share
// Fix permissions on remote server
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown -R deployer:deployer ~/.ssh
SSH Key Authentication FlowClient MachineUbuntu Serverssh-keygenPrivate KeyPublic KeyCopy to Serverauthorized_keyssshd ValidatesAccess Granted
Ubuntu User Management Guide: SSH key authentication sequence from local generation through server validation to access grant

If keys still fail, check /var/log/auth.log for PAM or sshd errors. Common culprits include SELinux/AppArmor blocking .ssh access, encrypted home directories preventing pre-login key reads, or mismatched ownership after copying files as root. For automated deployments, consider using ssh-agent forwarding or dedicated deploy keys stored securely in CI/CD secret managers rather than embedding private keys in repositories.

How do you harden SSH and disable root login?

Once key authentication works for non-root users, lock down SSH to prevent direct root access and password-based attacks. This is non-negotiable for any internet-facing server hosting business-critical applications. I apply these settings to every Ubuntu instance before deploying application code.

Edit sshd_config safely

// Backup original config
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F)

// Edit configuration
sudo nano /etc/ssh/sshd_config

Apply these critical directives:

  • PermitRootLogin no — Blocks direct root SSH entirely
  • PasswordAuthentication no — Enforces key-only access
  • PubkeyAuthentication yes — Explicitly enables key auth
  • MaxAuthTries 3 — Limits brute-force attempts per connection
  • AllowUsers deployer admin — Whitelists permitted accounts
  • Port 2222 — Optional: Move off default port to reduce noise

Validate and restart sshd

Always validate configuration before restarting to avoid locking yourself out:

// Test config syntax
sudo sshd -t

// Restart service if valid
sudo systemctl restart sshd

// Verify active settings
sudo sshd -T | grep -E 'permitrootlogin|passwordauthentication'
SSH Hardening Decision TreeIncoming SSHPermitRootLogin no?YESContinueNODENYPasswordAuth no?YESKey OnlyNODENYIn AllowUsers?YESACCESS OKNODENY
Ubuntu User Management Guide: SSH hardening decision flow checking root login, password auth, and user whitelist before granting access

Keep an active SSH session open while testing changes in a second terminal. If the new config breaks connectivity, revert using the backup file without losing access. For teams managing multiple servers, automate this via Ansible or Deployer recipes to ensure consistency and eliminate manual drift across environments.

How do you audit and maintain user accounts over time?

User management is not a one-time setup. Accounts accumulate as team members join, contractors finish work, and services evolve. Regular audits prevent orphaned accounts from becoming attack vectors. On long-term client engagements, I schedule quarterly reviews of user lists and sudo configurations.

List and review active accounts

// List all human users (UID >= 1000)
awk -F: '$3 >= 1000 {print $1, $3, $7}' /etc/passwd

// Check last login times
lastlog | grep -v "Never"

// Find accounts with empty passwords (security risk)
sudo awk -F: '($2 == "") {print $1}' /etc/shadow

// Review sudo rules
sudo ls -la /etc/sudoers.d/
sudo cat /etc/sudoers.d/*

Disable or remove departed users

When someone leaves a project, disable immediately rather than deleting outright. Deletion removes home directories and audit trails; disabling preserves evidence while revoking access:

// Lock account and expire password
sudo usermod -L -e 1 former-user

// Kill active sessions
sudo pkill -u former-user

// Remove sudo rules
sudo rm /etc/sudoers.d/former-user

// Archive home directory before eventual deletion
sudo tar czf /backup/former-user-$(date +%F).tar.gz /home/former-user

For Nepali law firms and legal-tech platforms handling sensitive client data, maintaining audit trails of who accessed what and when is often a compliance requirement. Disabling accounts with preserved logs satisfies both security and regulatory needs better than immediate deletion. Document your offboarding process alongside your server security checklist to ensure nothing slips through during staff transitions.

Implementing Secure Ubuntu User Management

Secure user management combines disciplined account creation, granular privilege delegation, mandatory SSH key authentication, and ongoing auditing. Following this Ubuntu User Management Guide eliminates the most common server compromise vectors: weak passwords, excessive root access, and forgotten accounts. Start by creating dedicated non-root users today, enforce key-only SSH, and schedule your first audit within 90 days. If you need help securing production infrastructure or implementing these practices across your team's servers, reach out to discuss your specific requirements.

Frequently Asked Questions

Run sudo adduser username to interactively create a user with a home directory, set a password, and populate default profile files. Use useradd -m username for non-interactive scripting without prompts.

Add the user to the sudo group using sudo usermod -aG sudo username. This grants full administrative rights via the standard /etc/sudoers configuration included in Ubuntu 24.04 and 22.04 LTS releases.

useradd is a low-level binary that creates accounts without home directories or passwords unless flagged. adduser is a Perl wrapper providing interactive prompts, automatic home directory creation, skeleton file copying, and password setting for safer manual administration.

Use sudo deluser username to remove the account while preserving the home directory and mail spool. Always back up /home/username first, as reassigning ownership later requires knowing the original UID. Never use --remove-home unless you have verified backups exist and no other services reference those files.

The user likely lacks membership in the required group owning that directory. Check current groups with id username, then add them using sudo usermod -aG groupname username. The user must log out and back in for supplementary group changes to take effect; new sessions only load updated group memberships at authentication time.

Install libpam-pwquality and configure /etc/security/pwquality.conf with minlen=12, dcredit=-1, ucredit=-1, lcredit=-1, ocredit=-1. This enforces complexity at the PAM level during passwd commands and SSH keyless login setup. On production servers I manage, I also set PASS_MAX_DAYS 90 in /etc/login.defs to require periodic rotation, balancing security with operational reality for small teams.

Yes, but carefully. Use sudo usermod -l newname oldname to change the login name, then sudo usermod -d /home/newname -m newname to move the home directory. File ownership uses numeric UIDs, not names, so existing files remain accessible. However, cron jobs, systemd user units, and application configs referencing the old username path will break and need manual updates.

Run sudo passwd -l username to prefix the password hash with !, preventing password authentication while preserving the account and home directory. Unlock later with sudo passwd -u username. This is preferable to deletion for employees on leave or under investigation, as audit trails and file ownership remain intact for compliance or legal review.

The username was removed but entries remain in /etc/passwd, /etc/shadow, or NSS caches. Verify with getent passwd username and check /var/lib/sss/db if using SSSD. Clear stale entries manually or run sudo sss_cache -E. On systems I maintain, this typically happens after interrupted deluser operations or LDAP sync failures, requiring careful verification before forcing recreation.

Create individual user accounts per developer, never share credentials. Add each to a developers group with restricted sudo via /etc/sudoers.d/developers allowing only specific commands. Deploy SSH keys to ~/.ssh/authorized_keys with chmod 700 on .ssh and 600 on authorized_keys. Disable password authentication in /etc/ssh/sshd_config. I use this pattern on client staging servers to maintain auditability while enabling collaborative deployment workflows.

Check direct sudo group members with getent group sudo, then inspect /etc/sudoers and all files in /etc/sudoers.d/ for additional grants. Use sudo -l -U username to verify effective permissions for specific accounts. On production systems, I run this audit monthly because package upgrades or configuration management tools sometimes inject unexpected sudoers entries that expand privilege beyond intended scope.

Export account metadata with getent passwd username and recreate with identical UID/GID on the target system to preserve file ownership. Transfer home directories via rsync -aHAXS to maintain permissions, ACLs, and extended attributes. Migrate crontabs from /var/spool/cron/crontabs/. Test thoroughly before decommissioning the source. I have used this approach during server migrations for legal-tech portals where document ownership integrity was legally significant.

Set the user's shell to /usr/sbin/nologin and configure an internal-sftp subsystem in /etc/ssh/sshd_config with ChrootDirectory pointing to their jailed root. Ensure the chroot directory is owned by root with 755 permissions, with a writable subdirectory owned by the user. This prevents shell escape while allowing secure file transfers, a pattern I implement for client document upload portals where full SSH access would violate security requirements.

Linux loads supplementary groups only at session initialization. Existing shells retain the old group list until logout. Use newgrp groupname to activate a single group in the current session without reconnecting, or sg groupname -c command to execute one command with alternate group context. For automated scripts, always spawn fresh sessions rather than assuming runtime group updates propagate to running processes.

Basic user provisioning and sudo configuration costs Rs 5,000–15,000 (~USD 37–112) for small setups. Comprehensive hardening with PAM policies, SSH lockdown, audit logging, and documentation runs Rs 25,000–50,000 (~USD 187–375). Ongoing maintenance retainer starts around Rs 8,000/month (~USD 60). Pricing varies based on user count, compliance requirements, and whether integration with centralized authentication like LDAP is needed for growing teams.

Share this article

Quick Contact Options
Choose how you want to connect me: