Create a User Home Safely with mkhomedir_helper
You will create a missing home directory for an existing Linux account, copy the skeleton files into it, and check the result without disturbing an existing home. This guide uses mkhomedir_helper from libpam-modules-bin version 1.5.3-5ubuntu5.7, installed on the reference system.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need an existing account whose home directory does not yet exist, a shell, and elevated privileges. The command changes filesystem state and ownership, so ordinary inspection can be unprivileged but the creation step normally needs sudo. There is no dry-run mode in the installed command.
1. Check the account before changing anything
Choose the account first. Replace NEWUSER with an account that already exists, not a name you want the helper to create:
$ getent passwd NEWUSER
NEWUSER:x:1001:1001:Example User:/home/NEWUSER:/bin/bash
$ home=$(getent passwd NEWUSER | cut -d: -f6)
$ printf 'home: %s\n' "$home"
home: /home/NEWUSER
$ test -e "$home"; printf 'home exists: %s\n' "$?"
home exists: 1
The helper uses the account's configured home path. The final status above is 1 when that path does not exist. Check the path carefully before using sudo. A typo in the username can select a different account, while a typo in a manually supplied path can put files somewhere unexpected.
Checkpoint: stop if the account is missing or the home already exists. The helper is deliberately conservative: it never touches a home directory that is already present.
2. Inspect the command shape and defaults
Read the installed manual page and confirm the binary you will run:
$ command -v mkhomedir_helper
/usr/sbin/mkhomedir_helper
$ dpkg-query -W -f='${Package} ${Version}\n' libpam-modules-bin
libpam-modules-bin 1.5.3-5ubuntu5.7
$ man 8 mkhomedir_helper
The syntax is:
mkhomedir_helper USER [UMASK [SKELDIR [HOME_MODE]]]
USER is required. If you omit the remaining values, the installed manual documents an umask of 0022, /etc/skel as the skeleton directory, and a home mode computed from the umask. The skeleton directory supplies the initial contents. Do not assume that an application-specific skeleton exists until you have checked it.
$ sudo test -d /etc/skel && echo '/etc/skel is available'
/etc/skel is available
$ sudo find /etc/skel -maxdepth 1 -mindepth 1 -printf '%f\n' | sort
The first command requires privilege only because the example asks sudo to perform the check. If your account can read the directory, test -d /etc/skel and find can be run without it.
3. Create the missing home with the defaults
Once the username and home path have passed the checks, run the helper with only the username:
$ sudo mkhomedir_helper NEWUSER
Normal completion is quiet. A zero exit status is the useful checkpoint:
$ printf 'helper status: %s\n' "$?"
helper status: 0
$ sudo stat -c 'owner=%U group=%G mode=%a path=%n' "$home"
owner=NEWUSER group=NEWUSER mode=<calculated mode> path=/home/NEWUSER
$ sudo find "$home" -maxdepth 1 -mindepth 1 -printf '%f\n' | sort
The exact mode and file list depend on the account, the installed defaults and the contents of /etc/skel. Verify ownership and permissions rather than copying the sample output as a promise. The helper copies the specified skeleton contents and applies ownership as part of creating the home; the command does not print a success report.
Do not run the command a second time expecting it to refresh dotfiles. Once the directory exists, the helper does nothing to it. This protects an existing home but also means that changing /etc/skel later does not update old accounts.
4. Use an explicit skeleton and mode only when required
Use the optional arguments when the account needs a different initial template or policy. For example, this command keeps the documented umask, selects a deliberately named skeleton directory, and passes a home mode explicitly:
$ sudo mkhomedir_helper NEWUSER 0022 /srv/skel/interactive 0750
Every optional argument is positional. You cannot provide HOME_MODE while omitting UMASK or SKELDIR. Check the custom directory before running the command:
$ sudo test -d /srv/skel/interactive && echo 'skeleton is available'
skeleton is available
$ sudo find /srv/skel/interactive -maxdepth 1 -mindepth 1 -printf '%f\n' | sort
This is another state-changing command and needs the same precondition as the default form: the target home must not already exist. Treat the skeleton as trusted input. Files copied into a new account home can affect shell startup and user configuration.
Use a leading zero for an octal-style value such as 0750, and keep the values aligned with your local policy. If an argument is malformed, the program reports a bogus value and exits without giving you a useful partial-success summary. Inspect the target afterwards rather than assuming that a shell error means every filesystem operation was undone.
5. Test the workflow in a disposable location
If you need to learn the behaviour before touching a real account, make a temporary account with a temporary home. This changes the local account database and creates files, so run it only on a test machine or with an approved maintenance window:
$ demo_user="mkhomedir-demo-$$"
$ demo_home="/tmp/$demo_user"
$ sudo useradd --no-create-home --home-dir "$demo_home" --shell /bin/sh "$demo_user"
$ sudo mkhomedir_helper "$demo_user"
$ sudo stat -c 'owner=%U group=%G mode=%a path=%n' "$demo_home"
owner=mkhomedir-demo-12345 group=mkhomedir-demo-12345 mode=<calculated mode> path=/tmp/mkhomedir-demo-12345
$ sudo find "$demo_home" -maxdepth 1 -mindepth 1 -printf '%f\n' | sort
Your process ID and resulting account identifiers will differ. The important checks are that the helper exits successfully, the configured temporary home now exists, and its owner matches the test account. Use a unique name and confirm it does not already exist before creating the account.
When finished, remove only this disposable account and the exact temporary home you just inspected:
$ sudo userdel "$demo_user"
$ sudo rm -rf -- "$demo_home"
$ test ! -e "$demo_home" && echo 'temporary home removed'
Warning
rm -rf is irreversible. Do not substitute a real home path, an empty variable, or a broad directory. If you need to keep the test account for another check, skip cleanup and remove it later through your normal account-management procedure.
6. Diagnose a failed creation
Capture the status immediately after the helper, before running another command:
$ sudo mkhomedir_helper NEWUSER
$ status=$?
$ printf 'helper status: %s\n' "$status"
helper status: 0
Status 0 indicates normal completion. A missing username or a home that cannot be used will fail instead. Recheck the account record, its configured home, the parent directory permissions and the skeleton path. Avoid guessing an option: the installed command accepts the positional arguments shown earlier and does not document a force, verbose or dry-run switch.
If the home now exists after a non-zero status, stop and inspect it before rerunning anything:
$ sudo stat -c 'owner=%U group=%G mode=%a path=%n' "$home"
$ sudo find "$home" -maxdepth 1 -mindepth 1 -printf '%f\n' | sort
Do not delete or overwrite a partially populated real home as an automatic recovery step. Preserve it for review, compare it with the expected skeleton, and use your account backup or change-control process if files must be restored. The helper's no-touch rule applies only when the home already existed before invocation; it is not a transaction system for every failure during creation.
Done means
- The account exists and its configured home path was checked before elevation.
- The home was absent before the helper ran, or the helper was correctly left alone because it already existed.
- The chosen skeleton and positional arguments were verified rather than guessed.
- The helper returned status
0, and ownership, mode and initial contents were inspected. - No real home was removed during recovery; disposable test data was cleaned up only after its exact path was confirmed.