Create Missing Network User Home Directories with pam_mkhomedir
Nothing kills a first login from a network account faster than a missing home directory, and pam_mkhomedir builds one on the fly. It copies the selected skeleton files, applies a predictable directory mode, and leaves the directory in place after logout. These examples use Linux-PAM from Ubuntu package libpam-modules version 1.5.3-5ubuntu5.7.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about 15 minutes, plus one test login. You need root access, a readable skeleton directory, and a PAM service your users actually use, such as SSH or a display manager. This changes authentication-session configuration, so keep an existing root shell or console session open while testing.
Safety warning
A malformed PAM file can prevent logins. Back up the service file before editing it, change one service at a time, and do not close your working administrative session until a new login has succeeded.
1. Confirm the module and choose the PAM service
Check that the package and module are installed:
$ dpkg-query -W -f='\${Package} \${Version}\n' libpam-modules:amd64
libpam-modules:amd64 1.5.3-5ubuntu5.7
$ test -r /usr/lib/x86_64-linux-gnu/security/pam_mkhomedir.so && echo 'module present'
module present
The PAM service file controls when the module runs. For SSH that is normally /etc/pam.d/sshd; for a text console it may be /etc/pam.d/login. Inspect the file you intend to change and confirm it has a session section:
$ sudo sed -n '1,220p' /etc/pam.d/sshd
Replace sshd in the command with the service used by your central-login path. Do not add this line to an unrelated service and assume it will affect every login.
2. Inspect the skeleton and permission defaults
Files in /etc/skel are copied into a newly created home directory. Review them before enabling the module, because a skeleton can contain shell startup files and other user-visible defaults:
$ sudo find /etc/skel -maxdepth 2 -printf '%M %u:%g %p\n'
$ grep -E '^(HOME_MODE|UMASK)[[:space:]]' /etc/login.defs
On this machine, HOME_MODE 0750 and UMASK 022 are present. Without an explicit umask= option, the installed module uses HOME_MODE when it is available. If it is absent, it computes a mode from UMASK; if neither setting exists, the documented fallback is 0755.
This is a directory permission decision, not just a formatting option. A mode such as 0750 keeps unrelated users from reading the home directory, but it may not suit every shared-group arrangement. Decide the policy before touching PAM.
3. Back up the service file
Run this as root, substituting the service you selected:
$ sudo cp --preserve=mode,ownership,timestamps /etc/pam.d/sshd /etc/pam.d/sshd.before-pam_mkhomedir
$ sudo ls -l /etc/pam.d/sshd /etc/pam.d/sshd.before-pam_mkhomedir
The backup gives you a direct recovery path. If a later login test fails, restore it from the still-open administrative session with:
$ sudo cp --preserve=mode,ownership,timestamps /etc/pam.d/sshd.before-pam_mkhomedir /etc/pam.d/sshd
4. Add the session rule
Edit the chosen PAM file as root and add one line in its existing session section:
session required pam_mkhomedir.so skel=/etc/skel/ umask=0022
The session module type is the only one pam_mkhomedir provides. The required control means failure is reported as a PAM failure, although PAM may still run later session modules before returning. This example makes the creation mask explicit and uses the normal skeleton directory. If you want the service to follow HOME_MODE and UMASK instead, omit umask=0022:
session required pam_mkhomedir.so skel=/etc/skel/
Use an alternative skeleton only when you have deliberately created and reviewed it, for example skel=/srv/login-skel/. The path must be readable by the session process.
Warning
Do not put passwords, private keys or machine-specific secrets in any skeleton directory. Everything in it gets copied into every new home.
Checkpoint
Inspect the finished session section before testing. Look for a single correctly spelt pam_mkhomedir.so line, the intended control flag, and a skeleton path that exists.
5. Test with a user whose home is missing
Start a new login through the service you changed, using a real centrally managed account whose home directory does not already exist. If you have a disposable test account, confirm its home path first:
$ getent passwd EXAMPLE_USER
EXAMPLE_USER:x:20001:20001:Example User:/home/EXAMPLE_USER:/bin/bash
$ sudo test ! -e /home/EXAMPLE_USER && echo 'home is absent'
home is absent
Warning
Do not delete an existing home directory just to force a test. That destroys user data.
After the new session opens, check the result from the retained administrative session:
$ sudo stat -c '%A %a %U:%G %n' /home/EXAMPLE_USER
drwxr-x--- 750 EXAMPLE_USER:EXAMPLE_USER /home/EXAMPLE_USER
$ sudo find /home/EXAMPLE_USER -maxdepth 1 -mindepth 1 -printf '%f\n' | sort
.bash_logout
.bashrc
.profile
The exact skeleton file list depends on your host. What matters is that the directory owner and group match the account, its mode matches your policy, and the expected skeleton files were copied. The module does not remove the directory when the user logs out.
6. Diagnose a failed session
If the login fails with a PAM error, restore the backup first, then investigate. Check without changing anything:
$ getent passwd EXAMPLE_USER
$ sudo namei -l /home/EXAMPLE_USER
$ sudo test -r /etc/skel/.profile && echo 'skeleton readable'
$ sudo journalctl -b --no-pager | grep -iE 'pam_mkhomedir|pam|EXAMPLE_USER' | tail -n 40
- PAM_PERM_DENIED means the module could not create the home directory or read the skeleton. Check the parent directory, the selected skeleton, and the account's home path.
- PAM_USER_UNKNOWN means the underlying authentication stack does not know the user at the point this session module runs. Fix identity lookup and account ordering rather than creating a directory by hand.
A home that already exists is not recreated; check its ownership and permissions separately. The optional silent argument suppresses informative messages. The optional debug argument sends diagnostic information to syslog: use it briefly when your logging policy permits it, then remove it after diagnosis. It does not repair permissions or create a home outside the PAM session.
Done means
- Module confirmed. The installed pam_mkhomedir.so module and package version were checked.
- Service correct. The right PAM service has one reviewed session rule.
- Policy matched. The skeleton directory and home-directory mode match your access policy.
- Test login succeeded with the right owner, group and permissions on the new home.
- Backup kept until the change has been observed in normal use.