Last Update 4 hours ago Total Questions : 17
The Linux Foundation Certified System Administrator (LFCS) content is now fully updated, with all current exam questions added 4 hours ago. Deciding to include LFCS practice exam questions in your study plan goes far beyond basic test preparation.
You'll find that our LFCS exam questions frequently feature detailed scenarios and practical problem-solving exercises that directly mirror industry challenges. Engaging with these LFCS sample sets allows you to effectively manage your time and pace yourself, giving you the ability to finish any Linux Foundation Certified System Administrator (LFCS) practice test comfortably within the allotted time.
Task
Using libvirt (virt-install), create a new virtual machine named cool-moray from an existing disk image at /vms/cool-moray/jammy-server-cloudimg-amd64.img with the following specifications:
Setting
Value
Memory in MB
1024
You must use --noautoconsole for the installation to complete and exit.
See the complete solution in Explanation.
Objective: Create a new virtual machine using the existing Ubuntu 22.04 disk image, allocate 1024 MiB of RAM, register the virtual machine with libvirt, and ensure virt-install exits without opening an interactive console.
The correct solution uses virt-install with the --import and --noautoconsole options. The --import option is essential because the task provides an existing operating system disk image rather than requesting a fresh installation.
Step 1: Connect to the correct Linux server.
The video specifies that this task must be completed on host lfcs00083.
From the candidate terminal, execute:
ssh lfcs00083
This connects to the virtualization host where the VM must be created.
All subsequent commands must be executed on this host.
Step 2: Verify that virtualization tools are available.
Check the virt-install utility:
virt-install --version
Check the virsh utility:
virsh --version
Also check the QEMU image-management utility:
qemu-img --version
These tools serve different purposes:
virt-install creates and configures virtual machines.
virsh manages and inspects virtual machines through libvirt.
qemu-img examines and manages virtual disk images.
The task states that libvirt must be used, so creating the VM directly with a standalone qemu-system command would not be the appropriate solution.
Step 3: Verify connectivity to the libvirt hypervisor.
Execute:
sudo virsh --connect qemu:///system list --all
virsh communicates with the libvirt virtualization manager.
--connect qemu:///system selects the system-wide QEMU/KVM connection.
list --all displays both running and stopped virtual machines.
An illustrative result is:
Id Name State
--------------------------------
1 existing-vm running
- test-vm shut off
The actual VM list will depend on the host.
If libvirt cannot be contacted, check the host's libvirt services and sockets:
sudo systemctl status libvirtd
Some systems use modular libvirt daemons such as virtqemud, so inspect the installed service arrangement rather than assuming libvirtd is always present.
Step 4: Check whether cool-moray already exists.
Execute:
sudo virsh --connect qemu:///system list --all
Look for a virtual machine named:
cool-moray
You can check directly:
sudo virsh --connect qemu:///system dominfo cool-moray
If libvirt reports that the domain does not exist, proceed.
If the domain already exists, inspect it before making changes. Do not delete or recreate an existing machine without establishing why it is present.
The --name option of virt-install requires a name unique to the target libvirt connection.
Step 5: Verify that the existing disk image is present.
The task specifies the exact disk image path:
/vms/cool-moray/jammy-server-cloudimg-amd64.img
Execute:
ls -lh /vms/cool-moray/jammy-server-cloudimg-amd64.img
If normal user permissions do not allow inspection:
sudo ls -lh /vms/cool-moray/jammy-server-cloudimg-amd64.img
The image must exist before creating the VM.
Do not create an empty virtual disk in its place. The requirement is to use the existing disk image.
Step 6: Inspect the existing virtual disk image.
Execute:
sudo qemu-img info /vms/cool-moray/jammy-server-cloudimg-amd64.img
An example of the resulting information is:
image: /vms/cool-moray/jammy-server-cloudimg-amd64.img
file format: qcow2
virtual size: 2 GiB
disk size: 650 MiB
These size values are illustrative.
qemu-img info identifies the image's format, virtual size, actual allocated storage, and any backing image relationship.
Ubuntu cloud images commonly use QCOW2, but verify the actual image format instead of assuming it from the .img extension.
The existing image must remain intact.
Step 7: Confirm the guest operating-system type.
The disk filename contains:
jammy-server-cloudimg-amd64.img
jammy refers to Ubuntu 22.04 LTS, and amd64 indicates the x86-64 architecture.
Check the installed OS profiles:
virt-install --osinfo list
To find Ubuntu 22.04 specifically:
virt-install --osinfo list | grep -i ubuntu22
If ubuntu22.04 is available, it can be selected using:
--osinfo ubuntu22.04
This provides appropriate guest operating-system metadata and configuration defaults.
If that profile is unavailable, the upstream Ubuntu cloud-image procedure supports using:
--osinfo generic
Do not install a new operating system or download a different disk image merely to complete the task.
Step 8: Create the virtual machine using virt-install.
Once the disk exists, the libvirt connection works and the Ubuntu profile is supported, execute:
sudo virt-install \
--connect qemu:///system \
--name cool-moray \
--memory 1024 \
--disk path=/vms/cool-moray/jammy-server-cloudimg-amd64.img \
--osinfo ubuntu22.04 \
--import \
--noautoconsole
This is the principal solution.
If ubuntu22.04 is not recognized by the installed libosinfo database, substitute --osinfo generic, following the official Ubuntu cloud-image instructions.
The command leaves CPU count, network configuration and other parameters at their supported defaults because the visible task does not prescribe specific values for them.
Step 9: Understand every parameter in the command.
Parameter
Explanation
sudo
Executes with administrative privileges
virt-install
Creates and defines a VM through libvirt
--connect qemu:///system
Targets the system-wide QEMU/KVM hypervisor
--name cool-moray
Assigns the required VM name
--memory 1024
Allocates 1024 MiB of guest memory
--disk path=...
Attaches the existing virtual disk image
--osinfo ubuntu22.04
Selects the Ubuntu 22.04 operating-system profile
--import
Boots an existing OS image without running an installer
--noautoconsole
Prevents automatic attachment to the guest console and allows the command to return
Three arguments are especially important.
--memory 1024
The task specifies memory of 1024 MB. The virt-install utility interprets this parameter in MiB.
Therefore:
--memory 1024
sets the guest's configured RAM to 1024 MiB, equivalent to 1 GiB.
--import
This tells virt-install to create the VM around an existing disk image and skip the operating-system installation process.
Without an appropriate installation method such as --import, virt-install may expect installation media or fail to determine how the guest should be created.
--noautoconsole
The task explicitly requires this flag.
It prevents virt-install from automatically connecting to the guest's graphical or text console. Official documentation states that it also allows virt-install to exit promptly rather than waiting on an interactive console session.
Step 10: Verify that the creation command succeeds.
When virt-install succeeds, it normally prints messages indicating that the VM has been created and the domain is being started.
An illustrative successful message could be:
Starting install...
Creating domain...
Domain creation completed.
Do not treat these example messages as an actual result from the video.
Immediately after the command completes, check the exit status:
echo $?
Expected successful exit status:
0
If the command fails, read the actual error before attempting it again.
Common failure conditions include an existing VM name, inaccessible image path, unsupported OS profile, missing virtualization support or an unavailable default network.
Step 11: Verify that the new virtual machine is registered.
Execute:
sudo virsh --connect qemu:///system list --all
The output should now contain:
cool-moray
For example:
Id Name State
---------------------------
2 cool-moray running
The domain ID and runtime state may differ.
This command verifies that libvirt recognizes the VM.
Step 12: Verify the virtual machine's assigned memory.
Execute:
sudo virsh --connect qemu:///system dominfo cool-moray
Inspect the memory information.
For a VM configured with 1024 MiB, an expected value is:
Max memory: 1048576 KiB
Calculation:
\[ 1024 \times 1024 = 1,048,576 \text{ KiB} \]
This confirms that libvirt has the required memory allocation.
Also verify the VM name and general status in the same output.
Step 13: Verify the attached virtual disk.
Execute:
sudo virsh --connect qemu:///system domblklist cool-moray --details
The output should identify a disk whose source is:
/vms/cool-moray/jammy-server-cloudimg-amd64.img
This verifies that the VM uses the exact existing image required by the task.
Do not confuse creating a new blank disk with attaching the existing disk. The latter is required.
Step 14: Inspect the VM's persistent configuration.
Execute:
sudo virsh --connect qemu:///system dumpxml cool-moray
This displays the libvirt domain definition in XML format.
Look for the guest name:
< name > cool-moray < /name >
Also inspect the memory setting and the disk source.
The relevant configuration should contain the equivalent of:
< memory unit='KiB' > 1048576 < /memory >
And a disk source referencing:
< source file='/vms/cool-moray/jammy-server-cloudimg-amd64.img'/ >
The actual XML may include additional attributes, devices, generated addresses and machine-specific settings.
Step 15: Verify the VM's runtime state.
Execute:
sudo virsh --connect qemu:///system domstate cool-moray
A successful initial launch should normally report:
running
If it reports shut off, investigate the reason:
sudo virsh --connect qemu:///system dominfo cool-moray
You can also inspect the appropriate libvirt/QEMU logs.
Importing a cloud image registers and starts a guest, but it does not automatically establish guest login credentials or configure cloud-init user data. Those operations are not requested by this task.
Step 16: Verify that virt-install has returned control to the terminal.
Because --noautoconsole was specified, the virt-install command should return to the shell after initiating VM creation.
For example, the terminal prompt should become available again:
candidate@lfcs00083:~$
The presence of the normal shell prompt indicates that the creation utility is no longer occupying the terminal.
This is separate from the VM's own runtime state: the virtual machine may continue running after virt-install exits.
Step 17: Perform final verification.
Execute:
sudo virsh --connect qemu:///system list --all
sudo virsh --connect qemu:///system dominfo cool-moray
sudo virsh --connect qemu:///system domblklist cool-moray --details
sudo virsh --connect qemu:///system domstate cool-moray
Confirm the following:
Requirement
Expected result
VM name
cool-moray
Existing disk image
/vms/cool-moray/jammy-server-cloudimg-amd64.img
Memory
1024 MiB
Installation method
Existing image imported
Mandatory option
--noautoconsole used
VM registration
Present in libvirt
VM initial startup
Successful
Terminal
Returns to shell after creation
Final Solution
The essential commands are:
# Connect to the designated server
ssh lfcs00083
# Verify the existing disk image
ls -lh /vms/cool-moray/jammy-server-cloudimg-amd64.img
# Inspect the image
sudo qemu-img info /vms/cool-moray/jammy-server-cloudimg-amd64.img
# Check the VM name is available
sudo virsh --connect qemu:///system list --all
# Confirm the guest OS profile exists
virt-install --osinfo list
# Create the VM
sudo virt-install \
--connect qemu:///system \
--name cool-moray \
--memory 1024 \
--disk path=/vms/cool-moray/jammy-server-cloudimg-amd64.img \
--osinfo ubuntu22.04 \
--import \
--noautoconsole
# Verify the new VM
sudo virsh --connect qemu:///system list --all
sudo virsh --connect qemu:///system dominfo cool-moray
sudo virsh --connect qemu:///system domblklist cool-moray --details
sudo virsh --connect qemu:///system domstate cool-moray
Technical Verification and References
The solution is based on the official virt-install, libvirt and Ubuntu cloud-image documentation.
Ubuntu virt-install(1) Manual — Describes the --memory, --disk, --import, --osinfo and --noautoconsole options.
libvirt virsh Command Reference — Documents VM inspection commands, including list, dominfo, domblklist and domstate.
Ubuntu — Launch QCOW Cloud Images Using libvirt — Provides a practical example of launching an existing Ubuntu cloud image with virt-install, --import and --noautoconsole.
Video verification finding: At approximately 28:30, the recording shows Question 7 and the required host lfcs00083. The candidate begins entering the SSH command but cancels it and moves to Question 8. The recording therefore does not demonstrate a successful VM creation. The solution above is independently documentation-validated, not confirmed as executed in that recording.
Expected result: A virtual machine named cool-moray is created and registered through libvirt using the existing Ubuntu image, with 1024 MiB RAM. The VM starts successfully, and virt-install exits without attaching to the VM's console.
Task
Schedule a cron job for user james that:
- runs every day at 17:15
- executes the script /home/james/bin/scanfiles.sh
- sends its STDOUT output to /home/james/report.txt
See the complete solution in Explanation.
Step 1: Connect to the correct server.
The video specifies that the task must be completed on host lfcs00082.
From the candidate terminal, connect using:
ssh lfcs00082
This establishes an SSH session with the server where the cron job must be configured.
Step 2: Verify that the user james exists.
Execute:
id james
This displays the user's UID, primary GID, and group memberships.
An example of valid output is:
uid=1001(james) gid=1001(james) groups=1001(james)
The exact numerical IDs may differ. The important requirement is that the user james exists.
Step 3: Verify that the script exists.
Execute:
ls -l /home/james/bin/scanfiles.sh
This verifies the script's location, ownership, and permissions.
You can also check whether james has execute permission:
sudo -u james test -x /home/james/bin/scanfiles.sh
echo $?
An exit status of 0 confirms that the user can execute the script. If the check fails, investigate file and directory permissions.
The task does not require creating or modifying the script.
Step 4: Open the crontab for user james.
Execute:
sudo crontab -u james -e
- sudo provides the privileges needed to manage another user's crontab.
- crontab manages scheduled cron jobs.
- -u james selects the crontab belonging to user james.
- -e opens the selected crontab in a text editor.
This is important because the task explicitly requires scheduling the job for james, not for root or the candidate account.
Step 5: Add the cron job.
Insert the following entry into the crontab:
15 17 * * * /home/james/bin/scanfiles.sh > /home/james/report.txt
This is the exact scheduling command required to satisfy the task.
Step 6: Understand the cron expression.
The cron entry contains five scheduling fields followed by the command.
Field Value Description
Minute 15 Execute at minute 15
Hour 17 Execute at 17:00 (5 PM)
Day of month * Every day of the month
Month * Every month
Day of week * Every day of the week
Therefore, the script executes once daily at 17:15 according to the cron daemon's configured timezone.
The command portion is:
/home/james/bin/scanfiles.sh > /home/james/report.txt
It consists of:
- /home/james/bin/scanfiles.sh — the executable script.
- > — the shell's STDOUT redirection operator.
- /home/james/report.txt — the destination file for standard output.
The > operator creates the report file if it does not exist and the user has permission. If it exists, the output is overwritten on each execution.
Do not replace > with > > because > > appends output. Also, do not use 2 > & 1, because the task requests STDOUT only, not STDERR.
Step 7: Save the crontab.
If the crontab opens in Vim:
1. Press i to enter insert mode.
2. Add the cron entry.
3. Press Esc.
4. Type :wq and press Enter.
If it opens in Nano, press Ctrl+O, Enter, then Ctrl+X.
Once saved, the crontab command installs the updated schedule automatically.
Step 8: Verify the installed cron job.
Execute:
sudo crontab -u james -l
The output must include:
15 17 * * * /home/james/bin/scanfiles.sh > /home/james/report.txt
This verifies that the job is installed under the correct user account.
Step 9: Check the cron service.
On the Ubuntu system shown in the recording, execute:
systemctl status cron
The service should report:
Active: active (running)
If it is inactive, start it:
sudo systemctl start cron
To check whether the service is enabled for startup:
systemctl is-enabled cron
If cron is disabled and must remain operational after reboot, enable it:
sudo systemctl enable cron
Step 10: Verify the final configuration.
Run:
sudo crontab -u james -l
sudo -u james test -x /home/james/bin/scanfiles.sh
systemctl is-active cron
These commands verify that:
1. The required cron entry belongs to james.
2. The script is executable by james.
3. The cron service is active.
The report file is not necessarily present immediately after installing the cron entry. It will be created or overwritten when the scheduled job executes successfully.
Final Solution
The essential command is:
sudo crontab -u james -e
Add:
15 17 * * * /home/james/bin/scanfiles.sh > /home/james/report.txt
Then verify:
sudo crontab -u james -l
Technical verification: This solution follows the documented Linux crontab(1) and crontab(5) syntax. A user-specific crontab executes commands under the owner's account and uses five scheduling fields followed by the command.
Linux manual page
+1
Expected result: The script runs every day at 17:15 as james, directing its standard output to /home/james/report.txt. The schedule's configuration is verified; actual runtime success depends on the script, its permissions, and the target system.
Context
You are asked to organize existing SSL certificates in the filesystem.
Task
Identify the subject CN of the SSL certificate in the directory ~/relaxed-llama/ssl and move the certificate file into the corresponding subdirectory.
The sub-directory for the subject CN has already been created.
See the complete solution in Explanation.
Step 1: Connect to the correct server.
The video specifies that this task must be completed on host lfcs00094.
From the candidate terminal, execute:
ssh lfcs00094
This establishes an SSH connection to the designated Linux server.
All subsequent commands must be executed on this host.
Step 2: Navigate to the SSL certificate directory.
Execute:
cd ~/relaxed-llama/ssl
- cd changes the current working directory.
- ~ represents the current user's home directory.
- relaxed-llama/ssl is the directory specified in the task.
Verify the current directory:
pwd
Then list the contents:
ls -la
The directory should contain an SSL certificate file and existing subdirectories corresponding to certificate common names.
Step 3: Identify the SSL certificate file.
Execute:
find . -maxdepth 1 -type f -print
- find . searches from the current directory.
- -maxdepth 1 restricts the search to the current directory.
- -type f identifies regular files.
- -print displays their paths.
An SSL certificate commonly uses an extension such as .crt, .pem, or .cer, although other filenames are possible.
For example, a directory might contain:
/server.crt
/alpha.example.com/
/bravo.example.com/
/charlie.example.com/
These are illustrative filenames, not confirmed contents of the exam server.
Identify the actual certificate filename before continuing.
Step 4: Examine the SSL certificate using OpenSSL.
Once you have identified the certificate, run:
openssl x509 -in CERTIFICATE_FILENAME -noout -subject
Replace CERTIFICATE_FILENAME with the real filename.
For example, if the file is named server.crt:
openssl x509 -in server.crt -noout -subject
- openssl invokes the OpenSSL utility.
- x509 processes an X.509 certificate.
- -in server.crt specifies the certificate file.
- -noout suppresses the encoded certificate output.
- -subject displays the certificate's subject distinguished name.
An illustrative result is:
subject=C = US, ST = California, O = Example Corp, CN = bravo.example.com
The important field is:
CN = bravo.example.com
CN stands for Common Name, an attribute of the certificate's subject.
The actual value must come from the certificate on the designated host.
Step 5: Display the subject CN clearly.
For easier identification, execute:
openssl x509 -in CERTIFICATE_FILENAME \
-noout -subject -nameopt sep_multiline
This prints the subject attributes on separate lines.
Example:
subject=
countryName = US
stateOrProvinceName = California
organizationName = Example Corp
commonName = bravo.example.com
The commonName value is the information required to select the correct destination subdirectory.
Do not confuse the certificate's subject CN with its issuer CN or the Subject Alternative Name extension. The task specifically asks for the subject CN.
Step 6: Locate the matching subdirectory.
List the existing directories:
find . -maxdepth 1 -type d -print
If the certificate's subject CN is bravo.example.com, its matching destination should be:
~/relaxed-llama/ssl/bravo.example.com/
Verify that the matching directory exists:
ls -ld ~/relaxed-llama/ssl/bravo.example.com
Again, bravo.example.com is an example. Substitute the actual CN reported by OpenSSL.
The task states that the subdirectory has already been created.
Therefore, do not create a new directory unless you have established that the supplied environment differs from the task statement.
Step 7: Move the certificate into the correct subdirectory.
The Linux command for moving a file is mv.
Its basic syntax is:
mv SOURCE_FILE DESTINATION_DIRECTORY/
For example, if:
- Certificate filename: server.crt
- Subject CN: bravo.example.com
The command would be:
mv server.crt bravo.example.com/
This moves the certificate from:
~/relaxed-llama/ssl/server.crt
to:
~/relaxed-llama/ssl/bravo.example.com/server.crt
The original filename is preserved.
Before moving the actual file, ensure that the destination does not already contain a different file with the same name. You can use mv -i to request confirmation before overwriting an existing destination.
Do not copy the certificate using cp, because the task specifically requires moving it.
Step 8: Verify that the certificate was moved successfully.
Execute:
ls -l bravo.example.com/
The output should show the certificate inside the directory matching its CN.
Verify that the certificate no longer exists in the original location:
ls -l server.crt
For the illustrative filename, the expected response is:
ls: cannot access 'server.crt': No such file or directory
This indicates the original path no longer contains the file.
Step 9: Verify that the moved certificate is readable and unchanged.
Execute:
openssl x509 \
-in bravo.example.com/server.crt \
-noout -subject
The certificate's subject CN should be identical to the value obtained before the move.
For example:
subject=C = US, ST = California, O = Example Corp, CN = bravo.example.com
This confirms that the certificate is still readable and is located inside the corresponding CN directory.
Step 10: Perform the final directory verification.
Execute:
find ~/relaxed-llama/ssl -maxdepth 2 -type f -print
Confirm that the certificate appears at the expected destination.
The final directory structure should resemble:
~/relaxed-llama/ssl/
├── alpha.example.com/
├── bravo.example.com/
│ └── server.crt
└── charlie.example.com/
This directory structure is illustrative. The actual destination must match the CN obtained from the real certificate.
Final Solution
The essential command sequence is:
1. Navigate to the directory.
cd ~/relaxed-llama/ssl
2. List the files and directories.
ls -la
3. Identify the certificate's subject CN.
openssl x509 -in CERTIFICATE_FILENAME \
-noout -subject -nameopt sep_multiline
4. Move the certificate into its matching existing CN directory.
mv CERTIFICATE_FILENAME CN_DIRECTORY/
5. Verify the destination.
ls -l CN_DIRECTORY/
6. Confirm the certificate's subject again.
openssl x509 -in CN_DIRECTORY/CERTIFICATE_FILENAME \
-noout -subject
Replace CERTIFICATE_FILENAME and CN_DIRECTORY with the actual values discovered on the server.
Technical Verification and References
The solution is based on the officially documented behavior of OpenSSL and the GNU/Linux mv command.
- OpenSSL X.509: The -subject option displays the certificate subject; -noout suppresses certificate output; and -nameopt controls the format of the subject information.
OpenSSL Documentation
- GNU Coreutils: The mv command moves a file into an existing target directory while preserving its filename unless a new filename is explicitly supplied.
Official documentation: OpenSSL X.509 Certificate Command Reference.
Expected result: The existing SSL certificate is moved into the already-created subdirectory whose name matches the certificate's subject CN.
Important: The video reveals the task requirements but does not establish the actual certificate filename or subject CN from the target server. Therefore, assigning a particular destination without inspecting the certificate would be an unverified guess. The procedure above determines the correct destination directly from the certificate.
Task
First, create a user james with the password set to Foundation.
Next, create a group commander with GID 15002 and add user james.
Do not change user james's primary group.
Then, create a group pilot with GID 15001 and edit user james to use pilot as the primary group.
See the complete solution in Explanation.
Objective: Create the Linux user james, assign the specified password, create two groups with exact group IDs, and configure the user's primary and supplementary group memberships.
The task requires these operations to be performed in the specified order:
Requirement
Expected configuration
Username
james
Password
Foundation
Supplementary group
commander
Supplementary group GID
15002
Primary group
pilot
Primary group GID
15001
Important: Adding james to commander must not change the user's primary group. Only the final operation changes the primary group to pilot.
Step 1: Connect to the correct Linux server.
The video specifies host lfcs00091.
From the candidate terminal, execute:
ssh lfcs00091
This establishes an SSH connection to the designated Linux server.
All account and group-management operations must be performed on this host.
Step 2: Check whether user james already exists.
Execute:
id james
If the account does not exist, an expected message is:
id: ‘james’: no such user
You can also execute:
getent passwd james
This searches the configured user-account databases.
If the account already exists, inspect it before changing anything. Since the task explicitly requests creating the user, the normal exam starting state should not already contain the account.
Step 3: Create the user james.
Execute:
sudo useradd -m james
sudo runs the command with administrative privileges.
useradd creates a new Linux user account.
-m creates a home directory for the user.
james is the required username.
On a typical Ubuntu system configured for private user groups, the command creates an account with a home directory at:
/home/james
The default primary group is determined by the system's account-creation policy. It is commonly a private group named james.
The official Linux useradd(8) documentation confirms that -m creates a home directory and that default primary-group behavior depends on system configuration.
Linux manual page
Step 4: Verify that the user was created successfully.
Execute:
id james
An illustrative output is:
uid=1001(james) gid=1001(james) groups=1001(james)
The numerical UID and initial GID can differ on the actual system.
Check the account entry:
getent passwd james
Verify the home directory:
ls -ld /home/james
The account should exist before proceeding.
Step 5: Set the user's password to Foundation.
Execute:
sudo passwd james
The system will request a new password.
Enter:
Foundation
When prompted to confirm, enter:
Foundation
The password is case-sensitive.
A successful operation normally displays:
passwd: password updated successfully
The passwd command securely processes the supplied password and updates the account's password authentication information.
The official passwd(1) manual confirms that an administrator can assign a password to another user and that the utility requests the new password interactively.
Linux manual page
Step 6: Verify the user's password status.
Execute:
sudo passwd -S james
The output may resemble:
james P 2026-10-12 0 99999 7 -1
The date and password-aging fields will depend on the system.
The important value is:
P
This indicates that the account has a usable password.
This command does not reveal or independently confirm the plaintext password. To verify the actual credential, authenticate as james using Foundation through an appropriate login method.
Do not attempt to read the plaintext password from /etc/shadow. Linux stores password hashes rather than recoverable plaintext passwords.
Step 7: Check whether the group commander already exists.
Before creating the group, execute:
getent group commander
If the group does not exist, the command normally produces no output.
Also check whether GID 15002 is already allocated:
getent group 15002
If both checks produce no results, the requested group name and ID are available.
Step 8: Create group commander with GID 15002.
Execute:
sudo groupadd -g 15002 commander
groupadd creates a new Linux group.
-g 15002 assigns the exact numerical GID.
commander is the required group name.
The -g option explicitly controls the group's numerical identifier.
The official groupadd(8) documentation confirms that this option creates a group using the specified GID and normally requires it to be unique.
Linux manual page
Step 9: Verify that group commander was created.
Execute:
getent group commander
Expected output, before adding members:
commander:x:15002:
The fields in /etc/group are arranged as:
group_name:password:GID:user_list
Therefore:
commander is the group name.
x indicates the group password field is not stored directly in /etc/group.
15002 is the assigned GID.
The final field lists supplementary group members.
Step 10: Record james's current primary group.
Before adding james to commander, execute:
id -gn james
This displays the user's current primary group name.
To display its numerical GID:
id -g james
On a typical Ubuntu system, the group name may initially be:
james
The purpose of this step is to establish the primary-group value before making any changes to supplementary memberships.
Step 11: Add james to commander as a supplementary group.
Execute:
sudo usermod -aG commander james
This is one of the most important commands in the task.
Option
Purpose
usermod
Modifies an existing user account
-a
Appends to existing supplementary group memberships
-G commander
Specifies the supplementary group
james
Specifies the target user
The combination -aG adds commander to the user's supplementary memberships without changing the primary group.
The official usermod(8) manual confirms this behavior.
Linux manual page
Step 12: Understand why -aG is required.
Compare these commands:
sudo usermod -aG commander james
This is correct because it appends commander to the supplementary groups.
sudo usermod -G commander james
This can replace the user's existing supplementary group list with the specified list, removing memberships that were not included.
sudo usermod -g commander james
This would change the primary group to commander.
The last command is incorrect at this stage because the task explicitly states:
Do not change user james's primary group.
Therefore, use:
sudo usermod -aG commander james
Step 13: Verify supplementary group membership.
Execute:
id james
An illustrative result is:
uid=1001(james) gid=1001(james) groups=1001(james),15002(commander)
This confirms that commander was added as a supplementary group.
Check the group entry:
getent group commander
Expected:
commander:x:15002:james
Step 14: Verify that the primary group has not changed.
Execute:
id -gn james
Compare its output against the primary group recorded in Step 10.
The value must remain unchanged at this stage.
For example, if the original primary group was james, the output should remain:
james
Also check:
id -g james
This should return the original primary GID.
Do not proceed until both conditions are met: james belongs to commander, and the original primary group is unchanged.
Step 15: Check whether the group pilot already exists.
Execute:
getent group pilot
Check whether GID 15001 is available:
getent group 15001
The group name and numerical GID should be available for the requested group creation.
Step 16: Create group pilot with GID 15001.
Execute:
sudo groupadd -g 15001 pilot
groupadd creates a new group.
-g 15001 sets its numerical GID to 15001.
pilot is the requested group name.
The exact GID matters. Do not allow Linux to choose an automatically assigned GID.
Step 17: Verify group pilot.
Execute:
getent group pilot
Expected:
pilot:x:15001:
This verifies the group name and assigned numerical identifier.
At this stage, the group has been created, but the user's primary group has not yet been changed.
Step 18: Set pilot as the primary group for james.
Execute:
sudo usermod -g pilot james
This is the final account-modification command required by the task.
usermod modifies the existing user account.
-g pilot sets the primary login group to pilot.
james identifies the account being modified.
Unlike uppercase -G, which controls supplementary groups, lowercase -g specifies the primary group.
The official usermod(8) documentation distinguishes these options explicitly.
Linux manual page
The new primary group must already exist, which is why pilot was created first.
Step 19: Verify the user's new primary group.
Execute:
id -gn james
Expected output:
pilot
Verify the numerical GID:
id -g james
Expected:
15001
These commands establish that the account's primary group is now pilot.
Step 20: Verify that commander remains a supplementary group.
Execute:
id james
An illustrative final result is:
uid=1001(james) gid=15001(pilot) groups=15001(pilot),15002(commander)
The UID and any additional supplementary groups may differ.
The important conditions are:
Primary GID: 15001, belonging to pilot.
Supplementary membership: commander, GID 15002.
Changing the primary group with usermod -g should not remove the existing supplementary commander membership.
Step 21: Inspect the final account database entry.
Execute:
getent passwd james
An illustrative entry is:
james:x:1001:15001::/home/james:/bin/sh
The fourth field is the primary GID, which must be 15001.
The login shell and other fields may vary according to the system defaults.
Step 22: Verify the group definitions.
Execute:
getent group commander
getent group pilot
Expected group definitions:
commander:x:15002:james
pilot:x:15001:
It is normal for the pilot group entry not to list james explicitly in its final member field. A user's primary group is determined by the GID stored in the user-account record, while /etc/group lists explicit supplementary group membership.
The id james command is the most convenient way to verify both kinds of group membership together.
Linux manual page
Step 23: Verify the password status again.
Execute:
sudo passwd -S james
Confirm that the account still reports a usable password with status P.
The group modifications should not change the password.
Step 24: Perform the final verification.
Execute:
id james
id -gn james
id -g james
id -Gn james
getent group commander
getent group pilot
sudo passwd -S james
The required final configuration is:
Requirement
Expected result
User exists
james
Password configured
Foundation
commander exists
Yes
commander GID
15002
commander membership
Supplementary
pilot exists
Yes
pilot GID
15001
pilot membership
Primary
Other supplementary memberships
Preserved
Final Solution
Execute the following commands in order.
# Connect to the required server
ssh lfcs00091
# Create user james with a home directory
sudo useradd -m james
# Set password interactively to Foundation
sudo passwd james
# Create commander with GID 15002
sudo groupadd -g 15002 commander
# Add james to commander as a supplementary group
sudo usermod -aG commander james
# Verify primary group has not changed
id -gn james
# Create pilot with GID 15001
sudo groupadd -g 15001 pilot
# Change james's primary group to pilot
sudo usermod -g pilot james
# Verify the complete user configuration
id james
id -gn james
id -g james
# Verify the created groups
getent group commander
getent group pilot
# Verify the account has a usable password
sudo passwd -S james
When executing:
sudo passwd james
enter Foundation twice when prompted.
Expected final result:
uid=1001(james) gid=15001(pilot) groups=15001(pilot),15002(commander)
The UID is illustrative. The required group names, GIDs, and memberships must match exactly.
Technical Verification and References
The commands have been checked against the Linux account-management manuals:
Linux useradd(8)
— Creating user accounts.
Linux passwd(1)
— Assigning and checking user passwords.
Linux groupadd(8)
— Creating groups with specified GIDs.
Linux usermod(8)
— Managing primary and supplementary group memberships.
Linux id(1)
— Verifying user and group identities.
Video verification finding: Question 15 is visible at approximately 32:14–32:18 of the recording. Its full task statement and target host lfcs00091 are readable. The candidate moves to the next task without demonstrating these account-management commands, so the solution is independently documentation-verified rather than confirmed through successful execution in the video.
Expected result: User james has password Foundation, belongs to commander (GID 15002) as a supplementary group, and uses pilot (GID 15001) as the primary group.
next now
Worked for 4m 23s
Task
The task is presented as a network traffic redirection diagram in the video.
Original diagram extracted from the recording. Its lower portion is outside the visible exam window.
The visible diagram identifies incoming TCP port 80, traffic from 172.16.123.0/28, and destination port 8080. The candidate's terminal commands also reference destination port 9080.
Transcription limitation: The recording does not reveal the complete diagram or any instructions below it. Therefore, the exact full task statement cannot be reproduced without guessing. The solution below addresses the two redirection paths indicated by the visible diagram and candidate commands, with the rule-ordering error corrected.
See the complete solution in Explanation.
Objective: Configure Linux iptables to perform destination-port redirection using the NAT table.
The recording suggests this intended behavior:
Incoming source
Original destination port
Redirected local port
172.16.123.0/28
TCP 80
TCP 9080
All other IPv4 sources
TCP 80
TCP 8080
The second destination, 9080, comes from the candidate's terminal commands, not the fully visible task diagram. It must therefore be treated as an inferred requirement.
A crucial technical issue is rule priority: the more specific subnet rule must be evaluated before the general port-80 rule. Otherwise, the general rule captures the subnet traffic first.
Step 1: Connect to the correct Linux server.
The recording specifies host lfcs00074.
Execute:
ssh candidate@lfcs00074
This connects to the designated host on which the firewall and NAT configuration must be performed.
Step 2: Verify that iptables is available.
Execute:
sudo iptables --version
This displays the iptables version and may indicate whether the system uses the nf_tables or legacy backend.
For example:
iptables v1.8.x (nf_tables)
The actual version depends on the installed environment.
Step 3: Inspect the existing NAT configuration.
Execute:
sudo iptables -t nat -L -n -v
-t nat selects the Network Address Translation table.
-L lists rules.
-n displays numerical IP addresses and port numbers.
-v provides verbose output, including packet and byte counters.
The NAT table contains chains including PREROUTING, OUTPUT, and POSTROUTING.
For incoming connections being redirected to local services, the relevant chain is normally PREROUTING.
Step 4: Display the PREROUTING rules with line numbers.
Execute:
sudo iptables -t nat -L PREROUTING -n -v --line-numbers
This displays the order in which incoming packets encounter the NAT rules.
Also execute:
sudo iptables -t nat -S PREROUTING
The second command displays the rules in a format similar to the commands used to configure them.
Check whether there are already rules that redirect TCP port 80.
Avoid creating duplicate or contradictory rules.
Step 5: Understand the required redirection mechanism.
The Linux REDIRECT target changes the destination of a matching packet so that it is delivered to the local machine, optionally changing its destination port.
For example:
sudo iptables -t nat -A PREROUTING \
-p tcp --dport 80 \
-j REDIRECT --to-ports 8080
This redirects incoming TCP connections originally targeting port 80 to local port 8080.
The official iptables-extensions(8) manual confirms that REDIRECT is supported in the NAT table's PREROUTING and OUTPUT chains.
Linux manual page
Step 6: Configure the source-specific rule first.
For the inferred special handling of subnet 172.16.123.0/28, execute:
sudo iptables -t nat -I PREROUTING 1 \
-s 172.16.123.0/28 \
-p tcp --dport 80 \
-j REDIRECT --to-ports 9080
Option
Purpose
-t nat
Selects the NAT table
-I PREROUTING 1
Inserts the rule at position 1
-s 172.16.123.0/28
Matches packets originating from that subnet
-p tcp
Matches TCP traffic
--dport 80
Matches original destination port 80
-j REDIRECT
Redirects the packet to the local machine
--to-ports 9080
Changes the destination port to 9080
The -I PREROUTING 1 option is important because it places the specific rule at the beginning of the chain, ahead of broader rules appended later.
Do not run this command if an equivalent correct rule already exists; inspect and reconcile the existing configuration first.
Step 7: Configure the general port redirection.
Provided an equivalent general rule is not already present, execute:
sudo iptables -t nat -A PREROUTING \
-p tcp --dport 80 \
-j REDIRECT --to-ports 8080
This handles incoming TCP port-80 connections that did not match an earlier terminating rule.
Because the source-specific rule has higher priority, the expected behavior is:
Connections from 172.16.123.0/28 are redirected to 9080.
Other incoming TCP port-80 connections are redirected to 8080.
The general rule does not require a source restriction because it is the fallback rule.
Step 8: Understand why the rule order matters.
The candidate initially enters the broad redirect to 8080 and later adds the subnet-specific redirect to 9080.
That sequence is problematic.
Consider these two rules in this order:
sudo iptables -t nat -A PREROUTING \
-p tcp --dport 80 \
-j REDIRECT --to-ports 8080
sudo iptables -t nat -A PREROUTING \
-s 172.16.123.0/28 \
-p tcp --dport 80 \
-j REDIRECT --to-ports 9080
The first rule matches all incoming TCP port-80 connections, including those from the special subnet.
Since a REDIRECT target terminates further rule evaluation for that NAT decision, the later subnet rule will not receive those matching connections.
Correct order:
Rule 1: Subnet 172.16.123.0/28 → Port 9080
Rule 2: Other TCP port-80 connections → Port 8080
The Linux iptables manual documents sequential rule evaluation and matching behavior.
Linux manual page
Step 9: Verify the configured NAT rules.
Execute:
sudo iptables -t nat -L PREROUTING \
-n -v --line-numbers
The relevant rule sequence should resemble:
1 REDIRECT tcp -- 172.16.123.0/28 0.0.0.0/0 tcp dpt:80 redir ports 9080
2 REDIRECT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 redir ports 8080
The output format may vary.
If existing unrelated rules are present, preserve them. The two example lines do not imply that the real NAT table should contain only two rules.
Step 10: Correct any incorrectly ordered rules.
If the general port-80 rule is already first, the specific rule can be inserted ahead of it using:
sudo iptables -t nat -I PREROUTING 1 \
-s 172.16.123.0/28 \
-p tcp --dport 80 \
-j REDIRECT --to-ports 9080
Before doing so, make sure an identical subnet rule is not already present.
If the previous candidate commands created duplicate entries, list the chain:
sudo iptables -t nat -L PREROUTING -n --line-numbers
Then carefully remove only confirmed duplicate or erroneous entries by their current rule number:
sudo iptables -t nat -D PREROUTING RULE_NUMBER
Replace RULE_NUMBER with the actual displayed number.
Rule numbers can change after each deletion, so inspect the chain again before deleting another entry.
Do not flush the entire NAT table.
Step 11: Verify that the destination services are available.
Execute:
sudo ss -ltnp
To examine the relevant ports:
sudo ss -ltnp | grep -E ':(8080|9080)\b'
This checks whether processes are listening on TCP ports 8080 and 9080.
The iptables rules may be syntactically correct even if no service is currently listening. However, actual connection delivery requires an appropriate local service and any necessary firewall permission.
A NAT redirection rule does not automatically start the destination application.
Step 12: Check whether filtering rules permit redirected connections.
Execute:
sudo iptables -L INPUT -n -v
Check whether the existing INPUT chain allows connections to the effective destination ports.
The REDIRECT target changes the packet's destination, but a restrictive filter policy can still block delivery.
Do not add broad ACCEPT rules unless the actual task requires them and the existing firewall policy warrants the change.
Step 13: Test traffic from the specified subnet.
From a machine whose source address belongs to:
172.16.123.0/28
Initiate a fresh TCP connection to port 80 on the appropriate IP address of lfcs00074.
For an HTTP-based service, a test could use:
curl -v http://SERVER_IP:80/
Replace SERVER_IP with the real server address.
If the inferred subnet-specific rule is correct, the connection should reach the local service listening on port 9080.
A destination service's response or a packet trace can establish which port received the connection.
Step 14: Test traffic from outside the specified subnet.
From a client outside 172.16.123.0/28, initiate another new connection to the same server's TCP port 80.
The general rule should redirect that traffic to port 8080, provided no earlier rule intercepts it.
Do not rely only on a test from:
curl http://localhost:80
Locally generated traffic traverses the NAT OUTPUT chain rather than the incoming PREROUTING chain. It is therefore not a valid test of these PREROUTING rules.
Step 15: Inspect rule counters.
Execute:
sudo iptables -t nat -L PREROUTING \
-n -v --line-numbers
Review the packet and byte counters.
New matching connections should increment the applicable rule's counters.
Because NAT decisions are generally made for the initial packets of tracked connections, established connections may not increment counters in the way ordinary filter-chain traffic does.
Use fresh connections for testing.
Step 16: Preserve the rules if persistence is required.
The video shows the candidate using:
sudo service netfilter-persistent save
For a system with the appropriate netfilter-persistent plugins installed, the documented command is:
sudo netfilter-persistent save
This saves the active firewall rules through the installed persistence plugins.
Ubuntu's netfilter-persistent(8) manual documents the save operation.
Ubuntu Manpages
Before relying on it, check that the service and IPv4 plugin are installed:
command -v netfilter-persistent
ls -l /usr/share/netfilter-persistent/plugins.d/
If persistence is required, verify the saved IPv4 rules:
sudo grep -A 20 '^\*nat' /etc/iptables/rules.v4
The saved configuration should contain the correctly ordered rules.
Persistence is not explicitly visible in the task statement, so treat it as an additional measure suggested by the recorded candidate actions, not a proven requirement.
Step 17: Perform final verification.
Execute:
sudo iptables -t nat -S PREROUTING
sudo iptables -t nat -L PREROUTING -n -v --line-numbers
sudo ss -ltnp | grep -E ':(8080|9080)\b'
For the inferred two-rule requirement, the expected configuration is:
Verification
Expected behavior
Source subnet
172.16.123.0/28
Original destination
TCP port 80
Special-subnet destination
TCP port 9080
General destination
TCP port 8080
Specific rule priority
Before general rule
NAT table
nat
NAT chain
PREROUTING
Existing unrelated rules
Preserved
Final Solution
For the two redirection paths inferred from the recording, and assuming equivalent rules do not already exist, the essential command sequence is:
# Connect to the required server
ssh candidate@lfcs00074
# Inspect existing NAT rules
sudo iptables -t nat -S PREROUTING
# Specific subnet: TCP 80 → 9080
# This rule must have higher priority.
sudo iptables -t nat -I PREROUTING 1 \
-s 172.16.123.0/28 \
-p tcp --dport 80 \
-j REDIRECT --to-ports 9080
# General traffic: TCP 80 → 8080
sudo iptables -t nat -A PREROUTING \
-p tcp --dport 80 \
-j REDIRECT --to-ports 8080
# Verify rule ordering and counters
sudo iptables -t nat -L PREROUTING \
-n -v --line-numbers
# If persistence is required and configured
sudo netfilter-persistent save
Technical Verification and References
Linux iptables(8)
— Documents rule insertion, ordering, matching and chain operations.
Linux iptables-extensions(8)
— Defines the REDIRECT target and --to-ports option.
Ubuntu netfilter-persistent(8)
— Documents saving and restoring firewall rules.
Video verification finding: The candidate's commands reveal an attempted redirect from port 80 to 8080 and a separate source-specific redirect from port 80 to 9080. The specific rule was appended after the general rule, which would prevent the special-subnet redirect from taking effect as intended. The corrected sequence places the specific rule first.
Verification limitation: The full task diagram is never visible, so the inferred two-rule interpretation cannot be certified as the exact complete exam requirement. The command syntax and priority correction are validated against Linux documentation, but the final intended behavior requires the missing diagram portion and runtime connection tests.
next please
Worked for 3m 12s

