LearnRHCSA (EX200)Users and Groups

/etc/skel and Login Shells

useradd - a hands-on Linux lab on a real virtual machine.

Master the two halves of a new account: the /etc/skel template and the login shell. /etc/skel is the skeleton copied into every new home at creation time (add a file there and every future user inherits it, while existing users stay untouched). The 7th field of /etc/passwd is the login shell, read with getent passwd. Give humans /bin/bash and give service accounts useradd -s /sbin/nologin so they exist and run but can never log in interactively. Serves EX200 users-groups: create, delete, and modify local user accounts.

You create a new account for a colleague, they log in for the first time, and something is off. Their arrow keys print junk, their tab completion is dead, and the friendly colored prompt everyone else has is missing. They ask you why their shell feels broken. It is not broken. Their home directory is missing the small starter files that make a shell behave like a shell, the ones that were supposed to be copied in when the account was created.

Those starter files come from one directory: /etc/skel. It is the template that gets stamped into every brand-new home directory. When it is right, every new user inherits a working shell, your standard config, even a welcome file if you put one there. When it is wrong or empty, new users start out crippled. This lesson shows you exactly how that template works, and it covers the other half of a new account: which shell the user actually gets, and how to hand out an account that can run a service but can never log in.

The black boxes below are a practice terminal: a safe sandbox that checks the one command each step teaches. The outputs are from a real RHEL 10 machine (AlmaLinux 10.2). A few values, like UIDs, GIDs, and the fact that this image already has a student account, depend on the specific machine, so treat those as illustrative. What is stable everywhere is the SHAPE: /etc/skel holds a fixed set of dotfiles, useradd copies them into each new home, and the 7th field of /etc/passwd names the login shell.

/etc/skel is the skeleton directory. Think of it as a cookie cutter. Every time you create a user, the system copies the entire contents of /etc/skel into that new user's home directory. Whatever sits in /etc/skel at the moment of creation becomes the starting contents of the new home.

The name is short for skeleton: the bare frame a new home is built on. By default it holds three hidden files that configure the shell, and because they start with a dot they are hidden from a plain ls. Remember from the ls lesson that -A shows the hidden dotfiles (everything except . and ..). Look inside the skeleton:

ls -A /etc/skel

prompt: [root@servera ~]# answer: ls -A /etc/skel output: .bash_logout .bash_profile .bashrc hint: List with the hidden files shown: ls -A, then the path /etc/skel

Three files, all hidden, all shell configuration. .bashrc runs every time an interactive shell opens and is where aliases and the prompt live. .bash_profile runs at login and usually pulls in .bashrc. .bash_logout runs when the user logs out. These are exactly the files whose absence made that colleague's shell feel broken. When a new account gets a clean copy of these three, it gets working tab completion, history, and prompt out of the box. This is the default skeleton, and it is the same on every fresh RHEL 10 install.

You reach for /etc/skel when you want every future user to start with the same setup, without visiting each account by hand. Company shell aliases, a standard .vimrc, a README that explains the machine, a pre-seeded .ssh directory: drop it in /etc/skel once and every account you create from then on inherits it automatically.

There is one rule that trips people up, and the exam loves it. /etc/skel is copied only at the moment a user is created. Editing /etc/skel does nothing to accounts that already exist; their home directories were stamped in the past and never look at the template again. The template shapes the future, never the past.

Editing /etc/skel never touches existing users. If ten accounts already exist and you now add a file to /etc/skel, those ten homes stay exactly as they were. Only users created AFTER your edit receive it. To give an existing user the same file you must copy it into their home yourself and fix its ownership with chown. Do not expect a /etc/skel change to ripple backward. It never does.

The cleanest way to understand /etc/skel is to watch it work. You add one new file to the skeleton, then create a fresh user, then look inside that new user's home. If the template really is copied at creation, your new file will be sitting there next to the three default dotfiles.

This one line does all three moves in order: write welcome into a new file /etc/skel/WELCOME.txt, create the user bob, then list bob's home. Watch the new file appear:

echo welcome > /etc/skel/WELCOME.txt ; useradd bob ; ls -A /home/bob

prompt: [root@servera ~]# answer: echo welcome > /etc/skel/WELCOME.txt ; useradd bob ; ls -A /home/bob output: .bash_logout .bash_profile .bashrc WELCOME.txt hint: Three commands chained with ; write the file into /etc/skel, then useradd bob, then ls -A /home/bob

There it is: WELCOME.txt now sits in /home/bob alongside the three default dotfiles. That proves the whole idea. useradd bob created the account, and as part of that it copied the entire contents of /etc/skel, including the WELCOME.txt you had just added, into bob's brand-new home. The three semicolons simply run the commands one after another. The key insight: the file made it into bob's home because it existed in /etc/skel at the instant bob was created. Any user made before that edit would not have it.

The useradd bob line prints nothing on success, which is why you do not see output from it above; the only output is from the final ls -A. That silence is normal for useradd. If the account already exists you would instead see useradd: user 'bob' already exists, which is your cue that the name is taken.

Every account has a login shell: the program that runs when the user logs in and gives them a command line. For a normal person that is almost always /bin/bash. That choice is recorded in /etc/passwd, the file that lists every account on the system, one line per user.

Each passwd line is seven fields separated by colons: name, password placeholder, UID, GID, comment, home directory, and last of all the login shell. The seventh and final field is the shell. Rather than eyeball the whole line and count colons, ask for exactly that field: pipe getent passwd bob into cut -d: -f7, where -d: splits on the colon and -f7 prints the seventh piece. Read bob's login shell:

getent passwd bob | cut -d: -f7

prompt: [root@servera ~]# answer: getent passwd bob | cut -d: -f7 output: /bin/bash hint: Query one account with getent passwd bob, then pipe into cut -d: -f7 to print the seventh colon-separated field

The seventh colon-separated field is the login shell, and for bob it prints /bin/bash, the interactive shell a normal user expects. getent passwd bob asks the system's account database for exactly one user's full line, which is cleaner than grepping the whole file; cut -d: -f7 then slices out just the shell so you do not have to count colons by eye. Why it matters: this one field decides whether logging in drops you at a usable prompt or somewhere useless. Change this field and you change what happens when the user connects, which is the exact trick the next step uses.

Drop the | cut -d: -f7 and plain getent passwd bob prints the whole seven-field line, which also carries bob's UID and GID. On this image those numbers land wherever the next free ID is (this machine already has a student account, which nudges the numbers up), so your UID and GID for a new user will differ from any specific value you see. The field that never varies for a normal interactive user is the one you just isolated: /bin/bash.

Not every account belongs to a human. Services like a web server or a database run under their own accounts, and those accounts should never be able to log in interactively. If nobody can log in as that account, an attacker who steals its password has nowhere to go. You enforce that by giving the account a login shell that refuses to start a session.

That special shell is /sbin/nologin. Instead of a prompt it prints a polite refusal and exits. You set it at creation time with useradd -s, where -s chooses the shell. Create a service account named svc whose shell is /sbin/nologin:

useradd -s /sbin/nologin svc

prompt: [root@servera ~]# answer: useradd -s /sbin/nologin svc output: hint: useradd with the shell flag -s set to /sbin/nologin, then the account name svc

No output means the account was created cleanly, just like useradd bob earlier. The difference is invisible here but decisive: svc's seventh passwd field is now /sbin/nologin instead of /bin/bash. If anyone tries to log in as svc, /sbin/nologin prints This account is currently not available. and immediately hangs up. The account still works perfectly for running a service in the background; it simply cannot open an interactive session. -s is the same shell flag you would use to give a human /bin/bash; here you point it at a shell that says no.

Setting the shell to /sbin/nologin blocks interactive login, not the account's ability to own files and run processes. That is exactly what you want for a service. Do not confuse it with locking a password: a nologin shell stops the login session no matter what the password is, while locking a password (with usermod -L or passwd -l) stops only password logins and leaves the shell alone. For a service account you usually want the nologin shell.

Scaffolding off. No command is printed this time. You have every piece you need.

A task hands you this: create an account named svc for a background service. It must exist so the service can own its files and run, but nobody must ever be able to log in interactively as it. You know the login shell is the seventh passwd field, you know useradd sets it, and you know the one shell whose whole job is to refuse a session. Which single command creates svc with that non-login shell in one shot?

prompt: [root@servera ~]# answer: useradd -s /sbin/nologin svc output: hint: It is useradd, the shell flag is -s, the refusing shell is /sbin/nologin, and the name is svc.

useradd -s /sbin/nologin svc creates the account and sets its login shell to /sbin/nologin in the same command, so the service exists but no one can open a session as it. That is the standard way to provision a service account on the exam and in real work. The -s flag is the whole trick: it writes your chosen shell into the seventh passwd field at creation time, and /sbin/nologin is the shell that turns a login attempt away.

You earned this cheat sheet. Every row is a form you just ran or built:

The two things to burn in for the exam: /etc/skel is copied only at creation time and never touches existing users, and the login shell lives in the 7th passwd field, where /sbin/nologin blocks interactive login.

To see the shell field directly instead of counting colons, run getent passwd svc | cut -d: -f7. The -d: sets the colon as the delimiter and -f7 prints the seventh field, which is the login shell. It is a fast way to confirm a service account really got /sbin/nologin without eyeballing the whole line.

The practice terminal walked you through the whole account-creation picture. ls -A /etc/skel to see the template, an add-then-create-then-inspect chain to prove the skeleton is copied at creation, getent passwd to find the login shell in the 7th field, and useradd -s /sbin/nologin to hand out an account that can run a service but never log in. Every one of those you typed yourself.

Operation Roster is where you run these against a real RHEL 10 machine. A full VM boots for you, with real accounts to build and a real /etc/passwd to read. The mission hands you a roster of users and service accounts to provision: create the humans with working shells, seed the skeleton so they all start with your standard files, and stand up the service accounts with /sbin/nologin so they exist but cannot log in. One difference from this lesson: the mission shows no commands. You read the objective, recall the useradd, -s, and getent forms, and type them. That recall is what makes it stick on exam day.

Finish the other users-groups lessons, then go build a real roster in Operation Roster.

Practice /etc/skel and Login Shells in a real Linux terminal at The Linux Camp. Progress is verified automatically as you type commands on the machine.