SATELLITEOffline Build Guide
Start Building
SAT01 Β· RHEL 9.8 Β· FIPS ● STIG PROFILE APPLIED AIR GAP
Let's build something secure together

Disconnected Satellite & STIG‑Hardened RHEL

A hand-held build guide: from an empty vSphere VM to a working Red Hat Satellite 6.19 server with no internet, FIPS mode, and the DISA STIG profile. Every command, every flag, and every symbol is explained in plain English.

Start the Build
11Stages
100+Checklist tasks
0Internet required
Step 0

Start Here: What You're Building and How to Read This Guide

Your organization runs many Red Hat Enterprise Linux (RHEL) servers on a network with no internet connection. That's called an air-gapped or disconnected network. Those servers still need software and updates. Red Hat Satellite is the answer: it's a private "app store and update center" that lives inside your network. You load software into Satellite by hand (from DVDs and approved transfer media), and every other server gets its software from Satellite instead of the internet.

In this guide you build that Satellite server from nothing: an empty virtual machine, the operating system, the network, the security hardening, and finally Satellite itself.

πŸ’‘ Why is this so careful?

This server is built to DISA STIG rules. STIGs are the U.S. Department of Defense's security checklists, and they decide things like how disks are split up, how passwords work, and which ports can be open. Many steps look "extra." They exist because an auditor will check them.

Words to know

You'll see these words on every page. Come back here whenever one feels fuzzy.

WordWhat it means in plain English
Server / VMA computer that provides a service to other computers. A VM (virtual machine) is a computer made of software, running on a bigger physical machine called an ESXi host. You manage VMs in vSphere.
ISOA single file that is an exact copy of a DVD. You "insert" it into the VM's virtual DVD drive.
Terminal / shellThe text screen where you type commands. The program reading your commands is called the shell (on RHEL it's called bash).
CommandOne instruction you type and run by pressing Enter, like ls ("list files").
Flag / optionExtra settings added to a command, usually starting with - or --. ls -l means "list files, long format."
rootThe all-powerful administrator account on Linux. Like "Administrator" on Windows.
sudo"Do this one thing as root." You type your own password, not root's.
File pathA file's address. /etc/fstab means "the file fstab inside the folder etc, which is inside the top folder /." Linux uses forward slashes. / by itself is the very top folder.
DirectoryLinux's word for a folder.
Partition / filesystemA disk split into separate sections. Each section has its own fixed size and can't overflow into another.
MountConnecting a disk (or ISO) to a folder so you can open it. Like plugging in a USB stick and having it show up as a drive letter on Windows, except on Linux it shows up as a folder.
Package / RPMA piece of software packed into one installable file (.rpm). Like an .msi on Windows.
Repository (repo)A collection of packages the system is allowed to install from. Like a shelf in a store.
dnfRHEL's package installer. It finds packages in repos and installs them. (yum is its older name and still works.)
ServiceA program that runs in the background all the time, like a web server.
systemd / systemctlsystemd starts and stops every service. systemctl is the command you use to talk to it.
IP addressA computer's number on the network, like a street address (for example 10.10.208.50).
PortA numbered door on a server. One IP can run many services, each behind its own port. Web pages use 443, SSH uses 22, and Cockpit uses 9090 by default.
FirewallThe gatekeeper that decides which ports outside computers may knock on. On RHEL it's firewalld.
SELinuxA second, stricter guard inside the server. Even if the firewall lets traffic in, SELinux decides which programs may use which ports and files.
DNSThe network's phone book: it turns names into IP addresses and back.
FQDNFully Qualified Domain Name: a server's full name, like sat01.lab.example, not just sat01.
CertificateA digital ID card that proves a server is who it says it is. Your browser checks it before showing a secure page.
CACertificate Authority: the trusted office that signs ID cards. If your computer trusts the CA, it trusts every certificate the CA signed.
PKIPublic Key Infrastructure: the whole system of CAs, rules, and people that issues certificates. The DoD runs its own, called the DoD PKI.
Private keyThe secret half of a server's identity. Whoever has it can pretend to be the server, so it never leaves the server.
CockpitA web page for managing a Linux server from your browser (logs, terminal, files).

How to read a command (the symbols)

Commands are built from small pieces. Here are the symbols this guide uses. You don't need to memorize them, since each command block explains its own pieces again.

SymbolWhat it doesEveryday comparison
>Send the command's output into a file, erasing whatever was in the file before.Pouring water into a glass after dumping out what was in it.
>>Send the output into a file, adding to the end and keeping what's there.Topping off the glass.
|"Pipe": hand one command's output to the next command.An assembly line: station 1 passes its work to station 2.
&&Run the next command only if the first one worked."Unlock the door, and if that worked, walk in."
;Run the next command no matter what happened."Do this, then do that."
\ at line end"This command continues on the next line." It lets one long command be written on several lines.A hyphen at the end of a line in a book.
# at line startA comment. The computer ignores the line. It's a note for humans.A sticky note.
*Wildcard: "anything." *.rpm means "every file ending in .rpm."A blank in a crossword that any letter fits.
' ' single quotes"Take this text exactly as written. Don't interpret any symbols in it."Putting something in a sealed envelope.

Flags: when to use one dash (-) or two (--)

Flags are the extra settings after a command. You'll see two styles, and they usually do the same job. One is short and quick to type; the other is a full word that's easier to read.

πŸ”’ The fixed rules
  1. One dash + one letter = a short flag. ls -a means "list all files."
  2. Two dashes + a word = a long flag. ls --all is the exact same thing, spelled out.
  3. Short flags can be stacked behind one dash. ss -tlnp is the same as ss -t -l -n -p. Long flags can never be stacked; each one gets its own --: ss --tcp --listening --numeric --processes.
  4. Some flags need a value after them. Short: a space, then the value: findmnt -o TARGET. Long: an = or a space: findmnt --output=TARGET.
  5. Two dashes all alone (--) means "no more flags after this." Everything after it is treated as a name, even if it starts with a dash.
  6. A letter only means something inside its own command. -p is a good example. It means something different in almost every command (see the table below). Never assume. Check the command's help.
πŸ”€ Which one should you use?
  • Typing at the terminal: short flags. They're faster, and it's what you'll see in most examples.
  • Writing scripts, Ansible playbooks, or documentation: long flags. Someone reading --human-readable six months from now knows what it does; -h makes them look it up.
  • Both work the same. It's a readability choice, not a right-or-wrong choice.

The same letter, different meanings: -p

CommandWhat -p means thereLong formExample
mkdirMake parent folders too, and don't complain if it already exists--parentsmkdir -p /media/rhel
mkdir --parents /media/rhel
ssShow the process (program) behind each port--processesss -tlnp
ss --tcp --listening --numeric --processes
semanage portThe network protocol (tcp or udp)--protosemanage port -a -t websm_port_t -p tcp 9091
semanage port --add --type websm_port_t --proto tcp 9091
systemctl showWhich property to show--propertysystemctl show cockpit.socket -p Listen
systemctl show cockpit.socket --property=Listen
sshWhich port to connect to(none)ssh -p 22 @

Short and long forms of the flags this guide uses

CommandShortLongWhat it doesExample (short β†’ long)
ls-a--allInclude hidden filesls -a /media/rhel
ls --all /media/rhel
ls-d--directoryShow the folder itself, not what's insidels -ld /var/local/rpm-staging
ls -l --directory /var/local/rpm-staging
df-h--human-readableSizes in G/T instead of raw numbersdf -h /var/lib/pulp
df --human-readable /var/lib/pulp
dnf-y--assumeyesAnswer "yes" automaticallydnf install -y cockpit
dnf install --assumeyes cockpit
grep-i--ignore-caseUpper/lower case doesn't mattergrep -i error app.log
grep --ignore-case error app.log
grep-n--line-numberShow line numbersgrep -n ' /tmp ' /etc/fstab
grep --line-number ' /tmp ' /etc/fstab
grep-E--extended-regexpAllow "either/or" patterns like a|bgrep -E 'pool|server' /etc/chrony.conf
grep --extended-regexp 'pool|server' /etc/chrony.conf
grep-q--quietPrint nothing; just succeed or failgrep -q '^server' /etc/chrony.conf
grep --quiet '^server' /etc/chrony.conf
grep-w--word-regexpMatch whole words onlygrep -w 9091
grep --word-regexp 9091
grep-l--files-with-matchesShow only file names that matchgrep -l '^enabled=1' /etc/yum.repos.d/*.repo
grep --files-with-matches '^enabled=1' /etc/yum.repos.d/*.repo
ss-t -l -n--tcp --listening --numericTCP only, listening only, numbers not namesss -tln
ss --tcp --listening --numeric
curl-s--silentNo progress barcurl -s https://localhost:9091
curl --silent https://localhost:9091
curl-k--insecureSkip the certificate checkcurl -k https://localhost:9091
curl --insecure https://localhost:9091
curl-I--headFetch only the page headercurl -I https://
curl --head https://
semanage port-a / -t / -l--add / --type / --listAdd a rule / its SELinux type / list rulessemanage port -l
semanage port --list
sed-i--in-placeSave the edit into the filesed -i 's/^pool /#pool /' /etc/chrony.conf
sed --in-place 's/^pool /#pool /' /etc/chrony.conf
tail-f--followKeep showing new lines as they arrivetail -f /var/log/secure
tail --follow /var/log/secure
journalctl-u / -b--unit / --bootWhich service / since last bootjournalctl -u cockpit -b
journalctl --unit=cockpit --boot
findmnt / lsblk-o--outputChoose which columns to showfindmnt -o TARGET,OPTIONS /tmp
findmnt --output=TARGET,OPTIONS /tmp
findmnt-t--typesOnly these filesystem typesfindmnt -t iso9660
findmnt --types=iso9660
mount-o--optionsMount optionsmount -o ro /dev/sr1 /media/sat6
mount --options ro /dev/sr1 /media/sat6
rpm-q / -K--query / --checksigAsk about packages / check signaturesrpm -K pkg.rpm
rpm --checksig pkg.rpm
hostname-f--fqdnPrint the full namehostname -f
hostname --fqdn
systemctl(none)--nowAlso start it right nowsystemctl enable --now cockpit.socket (only a long form exists)
firewall-cmd(none)--permanent, --reload, …firewall-cmd only has long flagsfirewall-cmd --permanent --add-service=cockpit

The two-dash stop sign: -- by itself

Sometimes a file name starts with a dash, and the command thinks it's a flag. Putting -- in front says "flags are over; what follows is just a name."

bash β€” exampletouch -- -test.txt
ls -l -- -test.txt
rm -- -test.txt
touch -- -test.txt
Create an empty file literally named -test.txt. Without --, touch would complain that -t is a flag it wasn't expecting like that.
ls -l -- -test.txt
-l is a real flag (before the stop sign). -test.txt comes after it, so it's a file name.
rm -- -test.txt
Delete it, same idea.
πŸ“£ Commands that break the rule
  • One dash + a whole word: some older tools do this. find /var -type f -name '*.rpm' (not --type), and openssl req -new -key cockpit.key -out cockpit.csr. For these, -name is one flag, not -n -a -m -e.
  • No dashes at all: subcommands are plain words. systemctl restart, nmcli connection modify, hammer repository list. The words come first; flags come after.
  • PowerShell (Windows): always one dash + a word, and capital letters don't matter: Test-NetConnection -ComputerName sat01 -Port 9091.

How to look up any flag yourself

bashss --help
man ss
--help
Almost every command prints a short list of its flags, both short and long forms side by side, like -p, --processes.
man ss
Opens the full manual. Inside it, type /-p and press Enter to jump to -p, press n for the next match, and press q to quit.
πŸ’‘ What does cat > file <<'EOF' really mean? (You'll use it a lot.)

Many steps need you to create a small settings file. The usual way is to open a text editor, but editors are clumsy inside the vSphere console. This trick lets you type the whole file right in the terminal instead:

examplecat > /etc/example.conf <<'EOF'
line one of the file
line two of the file
EOF

Read it left to right like a sentence:

  1. cat means "take what I give you and hand it back out." By itself it just repeats text.
  2. > /etc/example.conf means "don't show that text on screen. Put it into this file instead." If the file already exists, it is replaced.
  3. << means "the text I'm giving you is coming right here, on the next lines, not from another file." This is called a here-document ("the input is here").
  4. EOF is the stop word. It stands for "End Of File." It tells the shell: "keep reading lines until you see a line that says only EOF." The stop word isn't saved into the file. You could use any word, like DONE. EOF is just the tradition, so everyone recognizes it.
  5. The quotes around 'EOF' mean "copy every line exactly." Without them, the shell would try to "fill in" anything starting with $ (it would think $HOME is a variable and swap in your home folder). With the quotes, what you type is what goes in the file.

In one sentence: "Create this file, and here is everything that goes in it, up to the word EOF."

πŸ“£ The final EOF line must be alone on its line, with no spaces before or after it. If the terminal shows a > prompt and seems stuck, it's still waiting for that line. Type EOF and press Enter.

Your values

Every environment has its own names and addresses. Type yours below and every command in this guide updates to use them. Text highlighted like is one of these values. They are saved only in this browser.

πŸ“£ Keep real values out of GitHub

The defaults are made-up lab values. Type real hostnames and IPs only here in your browser. Never commit them to the repo or show them in portfolio screenshots.

Rules this guide always follows

πŸ”’ Always true in this guide
  • You work as root. Log in as your normal user, then type sudo -i once. sudo means "as the administrator," and -i means "give me a full administrator session." After that, the prompt ends in # instead of $, and you never need to type sudo again.
  • Keep the vSphere console open. It's like plugging a keyboard and monitor straight into the server. It still works when the network, SSH, or Cockpit are broken.
  • Check before moving on. Every step ends with a βœ” Checkpoint. If a checkpoint fails, stop and fix it first. Problems pile up otherwise.
  • Order matters. For example, Cockpit must move off port 9090 before Satellite is installed, because Satellite needs 9090.

What you need before you start

  1. Permission in vSphere to create a VM on the approved host, folder, and datastore (the datastore is the storage where VM disks and ISOs live).
  2. rhel-9.8-x86_64-dvd.iso, the full RHEL DVD (not the small "boot" ISO), uploaded to the datastore.
  3. Satellite-6.19.1-rhel-9-x86_64.dvd.iso uploaded to the datastore.
  4. Your approved server name, IP addresses, gateway, DNS servers, and time server, typed into the form above.
  5. Someone who can add records in Windows DNS.
  6. A PKI contact (the people who run your certificate authority). Only needed for the trusted certificate in Step 6.
  7. The approved process for moving files onto the air-gapped network.
πŸ“£ Three wrong passwords locks you out

STIG locks an account after 3 failed logins, and it usually stays locked until an admin unlocks it. That can include root. Know your root password and keep vSphere console access before you start. The unlock steps are on the Troubleshooting tab.

Step 1

Create the Empty VM in vSphere

First you build the "computer": an empty VM with the right amount of processing power, memory, and disks. Nothing is installed yet. Think of it as buying the hardware.

πŸ’‘ Why two separate disks?

The small disk (200 GB) holds only the operating system. The big disk (2 TB) holds Satellite's software library, which keeps growing. If the library ever fills its disk, the operating system is on a different disk, so the server can still boot and you can still log in to fix it. It's like keeping your kitchen and your warehouse in separate buildings.

1a. Name, location, and operating system type

  1. In vSphere, right-click the approved ESXi host β†’ New Virtual Machine β†’ Create a new virtual machine β†’ Next.
  2. Name it and pick the approved folder β†’ Next.
  3. Confirm the host (the "compute resource") β†’ Next.
  4. Pick the approved datastore β†’ Next.
  5. Compatibility: use your environment's approved level β†’ Next.
  6. Guest OS family Linux, version Red Hat Enterprise Linux 9 (64-bit) β†’ Next. This tells vSphere which drivers to expect.

1b. The virtual hardware

SettingValuePlain-English reason
CPU8 vCPUProcessing power. Satellite needs at least 4; 8 makes installs and syncs faster.
Memory32 GiBWorking memory. 32 GiB is Satellite's documented minimum.
Hard disk 1200 GBThe operating system's disk.
Hard disk 2 (Add New Device)2 TBSatellite's library, database, and logs.
Network adapter 1208 Network, Connected uncheckedThe network "cable" is unplugged on purpose, so nothing reaches the network during install. You plug it in during Step 4.
USB controller (Add New Device)xHCIUSB 3 support for approved transfer drives. Don't swap it for the older EHCI+UHCI type.
CD/DVD drive 1Datastore ISO File β†’ rhel-9.8-x86_64-dvd.iso, Connect At Power On checked"Inserts" the RHEL DVD so the VM boots from it.
VM Options β†’ Boot Options β†’ FirmwareEFIThe modern startup system (replaces old "BIOS"). Set it now. Changing it after install breaks booting.
  1. Set every value in the table.
  2. Compare the summary page against the table, then click Finish.
βœ” Checkpoint 1
  1. The VM has 8 vCPU, 32 GiB memory, EFI, a 200 GB disk, a 2 TB disk, and xHCI USB.
  2. Network adapter 1 is on the 208 Network and not connected. The DVD drive holds the RHEL ISO.
πŸ”§ If this happens
  • xHCI isn't in the list β†’ the VM's compatibility level is too old. Ask your vSphere admin. Don't downgrade the USB type.
  • You can't find the ISO β†’ you're in the wrong datastore, or your account can't browse it.
Step 2

Test That the VM Boots From the RHEL DVD

Before installing anything, make sure the right DVD is in the drive and it works. This takes two minutes and catches the most common setup mistake: the wrong ISO.

  1. Select the VM β†’ Launch Remote Console (or Launch Web Console). This is your screen and keyboard for the VM.
  2. Power on the VM.
  3. You should see a menu with Install Red Hat Enterprise Linux 9.8.
  4. Choose it and wait for the installer's Installation Summary screen. (The installer is called Anaconda.) Don't start installing yet.
  5. Look at Installation Source. It should say Local media with no warning. That means the installer found all the software on the DVD.
  6. Power off the VM from vSphere.
πŸ”§ If this happens
  • You see a Satellite screen or a "rescue" menu β†’ the Satellite ISO is in the drive. It can't boot a computer. Swap it for rhel-9.8-x86_64-dvd.iso.
  • Installation Source shows an error β†’ you used the small "boot" ISO, which has no software on it. Use the full DVD ISO.
βœ” Checkpoint 2
  1. The installer reached Installation Summary, the source said "Local media," and the network was still unplugged.
  2. Screenshot saved for your portfolio.
Step 3

Install RHEL 9.8: FIPS, STIG, and Separate Partitions

Now you install the operating system. Three security choices happen here, and they're hard to add later. FIPS means only government-approved encryption. STIG means the DoD security checklist is applied automatically. Separate partitions means each important folder gets its own fenced-off space on the disk.

πŸ’‘ Why does STIG want separate partitions?

Picture one big room where everything is stored. If one pile grows out of control, like logs from a noisy program, it fills the whole room and the system crashes. Separate partitions are walls: each folder gets its own room with a fixed size. If the log room fills up, the operating system's room is untouched.

Walls also let you put rules on each room, called mount options:

  • noexec: "nothing in this room may run as a program." It stops an attacker from dropping a program into a temp folder and running it.
  • nosuid: "ignore special 'run as admin' markers on files here." It blocks a common privilege trick.
  • nodev: "no device files here." Device files are special files that talk directly to hardware.

Those rules can only be set on a whole partition, never on a single folder. That's why STIG requires the walls.

3a. Start the installer in FIPS mode

  1. Power on the VM. At the menu, highlight Install Red Hat Enterprise Linux 9.8 and press e ("edit this boot option").
  2. Find the line that starts with linuxefi or linux. Move to the end of that line and type a space, then fips=1.
  3. Press Ctrl+X to start with that change.
πŸ’‘ What is FIPS, and why turn it on this early?

FIPS 140 is a U.S. government standard that lists which encryption methods are approved. fips=1 tells the installer "use only approved encryption from the first second." During install, the system creates its own secret keys (for example, SSH keys that prove the server's identity). If FIPS is already on, those keys are made the approved way. Turning FIPS on later would leave keys that were made the unapproved way. Also, since RHEL 9.6, picking the STIG profile no longer turns FIPS on for you, so you must do this yourself.

3b. Software and security profile

  1. Software Selection β†’ Server (no desktop) or Minimal Install. Add nothing extra. Less software means fewer things to patch and secure.
  2. Security Profile β†’ select DISA STIG for Red Hat Enterprise Linux 9 β†’ Select profile β†’ Done. The installer will now apply hundreds of security settings for you.
  3. Leave Network & Host Name alone. The network is unplugged on purpose.
  4. Time & Date: pick your time zone. The time server comes in Step 4.

3c. Split up the disks

This is the biggest part of the install. You'll use LVM (Logical Volume Manager). LVM pools a disk's space into a volume group, then carves that pool into logical volumes (the "rooms"). The big advantage: you can make a room bigger later without reinstalling.

πŸ”’ Always true for the disk layout
  • The 200 GB disk gets its own pool named rhel (operating system). The 2 TB disk gets its own pool named data (Satellite). The two never mix.
  • These folders must each get their own room (STIG): /boot, /boot/efi, /home, /tmp, /var, /var/log, /var/log/audit, /var/tmp.
  • Satellite's two heaviest folders also get their own rooms: /var/lib/pulp (the software library) and /var/lib/pgsql (the database).
  • Leave some of the data pool unused, so you have room to grow later.
πŸ”€ Your choice

The sizes below are a sensible start, not a rule. You can grow any room later. What must not change is which folders get their own room.

Folder (mount point)SizeTypeDisk / poolWhat lives there
/boot/efi600 MiBEFI System Partition200 GB diskStartup files the EFI firmware reads first
/boot2 GiBXFS, standard partition200 GB diskThe Linux kernel (core of the OS)
swap4 GiBLVMrhelOverflow space when memory is full
/150 GiBXFS, LVMrhelThe operating system itself ("root" folder)
/home10 GiBXFS, LVMrhelUsers' personal folders
/var250 GiBXFS, LVMdataData that changes: caches, queues, service data
/var/lib/pulp1200 GiBXFS, LVMdataSatellite's software library (the biggest)
/var/lib/pgsql50 GiBXFS, LVMdataSatellite's database
/var/log20 GiBXFS, LVMdataLog files
/var/log/audit20 GiBXFS, LVMdataSecurity audit records (who did what)
/var/tmp20 GiBXFS, LVMdataTemporary files that survive a reboot
/tmp20 GiBXFS, LVMdataTemporary files

XFS is the type of filesystem ("the way files are organized inside a room"). It's RHEL's default. The data pool uses about 1,600 GiB of roughly 1,860 GiB, leaving about 260 GiB to grow into.

First, the operating system disk

  1. Installation Destination β†’ check only the 200 GB disk. Leave the 2 TB disk unchecked for now.
  2. Under Storage Configuration choose Custom β†’ Done.
  3. In the partitioning scheme dropdown pick LVM.
  4. Click + and add /boot/efi 600 MiB, then /boot 2 GiB. Click each one and set Device Type to Standard Partition. (The computer must read these before LVM starts, so they can't be inside LVM.)
  5. Add swap 4 GiB, / 150 GiB, and /home 10 GiB. Check that each shows Volume Group rhel.
  6. Done β†’ Accept Changes.

Then, the data disk

  1. Open Installation Destination again. Check both disks β†’ Custom β†’ Done.
  2. Add /var 250 GiB. In its Volume Group dropdown choose Create a new volume group.
  3. Name it data, select only the 2 TB disk, leave RAID as is, set Size policy to As large as possible β†’ Save.
  4. Check that /var now says Volume Group data.
  5. Add the rest, each in pool data: /var/lib/pulp 1200 GiB, /var/lib/pgsql 50 GiB, /var/log 20 GiB, /var/log/audit 20 GiB, /var/tmp 20 GiB, /tmp 20 GiB.
  6. Compare every row with the table β†’ Done β†’ Accept Changes.
πŸ”§ If this happens
  • / or the rhel pool is on both disks β†’ click Reset All and redo "First, the operating system disk." Nothing is written to disk until you click Begin Installation, so this is safe.
  • The dropdown only shows rhel β†’ you haven't created data yet. Pick Create a new volume group.
  • The STIG profile shows a partition warning β†’ one of the required folders is missing. Compare with the table.

3d. Accounts

  1. Root Password: set the approved root password.
  2. User Creation: create your admin account and check Make this user administrator (this lets it use sudo).
πŸ“£ The console can mistype symbols

The vSphere console sends which key you pressed, not which letter you meant. If your computer's keyboard layout doesn't match what the VM expects, symbols like @ # $ \ | can come out different. Password typing is hidden, so you'd never see it, and 3 misses locks you out.

For your first login, pick a password (STIG still needs 15+ characters with upper, lower, a number, and a symbol) whose symbol you've tested in the console first. Safe bets are - and .. Change it later from SSH or Cockpit if you like.

3e. Install and first boot

  1. Check that every item on the summary is ready β†’ Begin Installation. This is when the disks are actually written.
  2. When it finishes, don't click Reboot yet. In vSphere: Edit Settings β†’ CD/DVD drive 1 β†’ uncheck Connect At Power On β†’ OK. Otherwise the VM boots from the DVD again and restarts the installer.
  3. Now click Reboot System.
  4. Log in on the console as , then type sudo -i and your password. The prompt should end in #, which means you're root.

3f. Check the install worked

bashcat /etc/redhat-release
cat /proc/sys/crypto/fips_enabled
fips-mode-setup --check
getenforce
cat
"Show me what's inside this file."
/etc/redhat-release
A one-line file that says which RHEL version is installed.
/proc/sys/crypto/fips_enabled
A live "switch" the kernel exposes as a file. 1 = FIPS on, 0 = off.
fips-mode-setup --check
A FIPS tool. --check means "just tell me the status, don't change anything."
getenforce
"Is SELinux enforcing its rules right now?"
You should see: Red Hat Enterprise Linux release 9.8 (Plow), then 1, then FIPS mode is enabled., then Enforcing.
bash β€” check that every room existsfindmnt -t xfs,vfat -o TARGET,SOURCE,SIZE,OPTIONS
lsblk -o NAME,SIZE,TYPE,MOUNTPOINTS
vgs
findmnt
"Find mounts": lists every connected filesystem (every room).
-t xfs,vfat
type filter: only show XFS rooms and the vfat (EFI) room. Hides dozens of internal system entries.
-o TARGET,SOURCE,SIZE,OPTIONS
output only these columns: the folder, the disk piece behind it, its size, and its rules (mount options).
lsblk
"List block devices": draws a tree of disks β†’ pieces β†’ LVM rooms, so you can see which disk each room sits on.
-o NAME,SIZE,TYPE,MOUNTPOINTS
Only these columns.
vgs
"Volume groups summary": shows each pool and how much is still unused (VFree).
You should see: one line per folder from the table. In lsblk, rhel-… rooms appear only under the 200 GB disk and data-… rooms only under the 2 TB disk. vgs shows free space left in data.

3g. Check the STIG room rules

The STIG profile already wrote these rules into /etc/fstab. fstab ("filesystem table") is the list the server reads at every boot to know which room connects to which folder, and with what rules. Confirm the rules took effect:

FolderSTIG expects
/bootnodev, nosuid
/boot/efinosuid
/homenodev, nosuid, noexec
/tmpnodev, nosuid, noexec (see the Satellite exception below)
/varnodev
/var/log, /var/log/audit, /var/tmpnodev, nosuid, noexec
/dev/shm (lives in memory, not on disk)nodev, nosuid, noexec
bashfindmnt -o TARGET,OPTIONS /tmp /var/tmp /home /var/log /var/log/audit /dev/shm
findmnt
List mounted rooms.
-o TARGET,OPTIONS
Only show the folder and its rules.
/tmp /var/tmp …
Naming folders limits the list to just these.
πŸ“£ The one place STIG and Satellite disagree: /tmp

STIG says /tmp should be noexec (no programs run there). Satellite's installer needs to run small helper programs from /tmp and fails without that. The accepted fix: remove noexec from /tmp only, keep nodev and nosuid, and write it down as an approved exception (a POA&M or risk acceptance) with your ISSO. That way an auditor sees a documented decision, not a mistake.

bash β€” only if /tmp shows noexecgrep -n ' /tmp ' /etc/fstab
sed -i '/[[:space:]]\/tmp[[:space:]]/ s/noexec,\?//; /[[:space:]]\/tmp[[:space:]]/ s/,\([[:space:]]\)/\1/' /etc/fstab
grep -n ' /tmp ' /etc/fstab
systemctl daemon-reload
mount -o remount,exec /tmp
findmnt -o TARGET,OPTIONS /tmp
grep
"Search for text." Finds lines in a file that contain what you typed.
-n
Show the line number, so you can see exactly which line you're about to change.
' /tmp '
The text to find. The spaces stop it from matching /var/tmp.
sed
"Stream editor": finds and replaces text automatically.
-i
Edit the file in place (save the change), instead of just printing the result.
s/noexec,\?//
s/old/new/ means "substitute." Here it replaces noexec (and a comma after it, if there is one) with nothing, which deletes it. The part before s limits this to the /tmp line only.
second s/…/
Tidies up a leftover comma if noexec was last in the list.
systemctl daemon-reload
Tells systemd "re-read your settings." systemd builds its mount list from fstab, so it has to re-read after any edit.
mount -o remount,exec /tmp
-o passes options. remount means "change the rules now without disconnecting." exec means "allow programs again."
You should see: the /tmp line in fstab and the findmnt output both show nodev,nosuid and no noexec. If the sed result looks wrong, fix the line by hand with vi /etc/fstab. A broken fstab line can stop the next boot.
βœ” Checkpoint 3
  1. RHEL 9.8, FIPS = 1, SELinux Enforcing.
  2. Every folder from the table is its own room, in the right pool.
  3. STIG rules are in place, and /tmp has no noexec (exception written down).
Step 4

Give the Server Its Network, Name, and Clock

A server on a network needs three things to be trusted: a fixed address (IP), a name everyone agrees on (DNS), and the correct time. Satellite is picky about all three.

πŸ’‘ Why does Satellite care so much?

When Satellite installs, it writes its own name into its ID cards (certificates), its database, and dozens of settings. If the name, the DNS "phone book" entry, and the reverse lookup (IP back to name) don't all agree, the install fails or builds a broken server. Time matters because ID cards have start and end dates. If the server's clock is wrong, it thinks valid cards are expired or not valid yet.

4a. Plug in both network "cables"

πŸ“£ Don't forget adapter 1

Adapter 1 has been unplugged since Step 1. If you only add adapter 2, the main address, gateway, and DNS never work, and it looks like everything else is broken.

  1. vSphere β†’ Edit Settings β†’ Network adapter 1 (208 Network): check Connected and Connect At Power On.
  2. Add New Device β†’ Network Adapter β†’ pick the .210 repository network β†’ check Connected and Connect At Power On.
  3. Click OK.

4b. Set the server's name

bashhostnamectl set-hostname 
hostnamectl status --static
hostnamectl
The tool that controls the server's name.
set-hostname
"Set the permanent name to this." It's saved in /etc/hostname.
status --static
"Show me only the permanent (static) name."
You should see: . Always the full name, never the short one.

4c. Find what the network cards are called

bashnmcli device status
nmcli connection show
nmcli
The command-line tool for NetworkManager, the program that manages network settings on RHEL.
device status
Lists the network cards (hardware) and whether each is connected.
connection show
Lists saved connections (settings profiles). A card is the hardware; a connection is the settings that card uses.
You should see: two ethernet cards, often named ens192 and ens224. Type the .208 one in the NIC1 field at the top of the page and the .210 one in NIC2.

4d. Main network card (.208): fixed address, gateway, DNS

bashnmcli connection modify  \
  ipv4.method manual \
  ipv4.addresses / \
  ipv4.gateway  \
  ipv4.dns " " \
  ipv4.dns-search  \
  connection.autoconnect yes
nmcli connection up 
connection modify NAME
"Change the settings of this connection." Nothing takes effect until the up command at the end.
\
"This command continues on the next line." All seven lines are one command.
ipv4.method manual
"I'll set the address myself." No DHCP, which is the automatic address handout. Servers need addresses that never change.
ipv4.addresses IP/PREFIX
The server's address. The /24 part (the prefix) says how big the local network is. It's required.
ipv4.gateway
The router, the "exit door" to reach other networks. Only this card gets one.
ipv4.dns "A B"
The two phone-book (DNS) servers. Quotes keep both addresses together as one value.
ipv4.dns-search
If you type a short name like sat01, add this domain to it automatically.
connection.autoconnect yes
Turn this connection on by itself at every boot.
connection up NAME
"Turn it on now," applying the new settings.

4e. Second card (.210): the repository network

bashnmcli connection add con-name repository-network ifname  type ethernet \
  ipv4.method manual \
  ipv4.addresses  \
  ipv4.never-default yes \
  connection.autoconnect yes
nmcli connection up repository-network
connection add
"Create a new settings profile."
con-name repository-network
The name you're giving the profile. Any name works; this one describes its job.
ifname NIC2
Which network card (interface) it belongs to.
type ethernet
The kind of connection. Wired cards are always ethernet.
ipv4.method manual
Fixed address, no DHCP.
ipv4.addresses
The address with its /24. There's no gateway line on purpose.
ipv4.never-default yes
"Never use this card as the main exit door." All normal traffic keeps using .208, which avoids confusing routing.
connection.autoconnect yes
Turn on at every boot.
connection up
Turn it on now.
πŸ”§ If this happens
  • nmcli connection show already lists something like "Wired connection 1" on NIC2 β†’ RHEL made an automatic profile. Delete it first with nmcli connection delete "Wired connection 1" (the quotes keep the spaces together as one name). Otherwise two profiles fight over the same card.

4f. Check the network

baship -4 address show
ip -4 route show
cat /etc/resolv.conf
ip
The low-level network tool.
-4
Only show IPv4 (the familiar 4-number addresses). Hides IPv6 noise.
address show
Which address each card has.
route show
The "map" of where traffic goes. The default line is the main exit door.
cat /etc/resolv.conf
Shows the DNS servers the system is actually using.
You should see: on NIC1 and the .210 address on NIC2. Exactly one line starting default via . Both DNS servers in resolv.conf.

4g. Add the server to the DNS phone book (Windows DNS)

Two entries are needed. An A record is name β†’ IP ("look up sat01, get 10.10.208.50"). A PTR record is IP β†’ name, the reverse lookup. Satellite checks both.

  1. On an approved DNS server, open DNS Manager β†’ Forward Lookup Zones β†’ right-click your zone β†’ New Host (A or AAAA).
  2. Name: the first part of your FQDN. Check that the full name shown reads .
  3. IP: . Check Create associated pointer (PTR) record β†’ Add Host.
  4. Open Reverse Lookup Zones and confirm the PTR record is there. If not, the reverse zone doesn't exist yet. Ask the DNS admin.
bash β€” back on the servergetent hosts 
getent hosts 
hostname -f
getent hosts NAME
"Look up this name the same way the system would." This is a forward lookup, name β†’ IP.
getent hosts IP
The reverse lookup, IP β†’ name.
hostname -f
"What's my full name?"
You should see: all three agree on ↔ . If they don't, stop here. Don't go on to Satellite until they match.
Optional: let this lab look up names in a production DNS zone

Only if the lab must find names in production. It needs a network path and port 53 (DNS) open from the lab's DNS servers to production's.

  1. On the lab DNS server: DNS Manager β†’ right-click Conditional Forwarders β†’ New Conditional Forwarder. (This says "for names ending in X, ask those servers.")
  2. Enter the production zone name and both production DNS server IPs. Only choose "store in Active Directory" if the DNS team approves.
  3. Test from the server: getent hosts <a-production-name>.

4h. Set the clock source (chrony)

πŸ’‘ Why the clock needs a source

Computer clocks drift a few seconds a day. Normally servers correct themselves from internet time servers, but this network has no internet. So you point the server at an internal time server your team runs. The time program on RHEL is chrony, and its settings file is /etc/chrony.conf.

bashgrep -nE '^(pool|server)' /etc/chrony.conf
sed -i 's/^pool /#pool /' /etc/chrony.conf
grep -q '^server ' /etc/chrony.conf || echo 'server  iburst' >> /etc/chrony.conf
systemctl restart chronyd
chronyc sources -v
chronyc tracking
grep -nE '^(pool|server)'
Show the lines that name time sources. -n adds line numbers. -E turns on "either/or" patterns. ^ means "at the start of the line," and (pool|server) means "pool OR server."
sed -i 's/^pool /#pool /'
Adds a # in front of every pool line, turning them into comments. Those are internet time servers this network can't reach.
grep -q … ||
-q means "quiet: just tell me yes or no." || means "if the answer was no, run the next part." So the server line is added only if it isn't already there.
echo '…' >> file
echo prints the text, and >> adds it to the end of the file.
iburst
"Send a quick burst of requests at startup," so the clock syncs in seconds instead of minutes.
systemctl restart chronyd
Restart the time service so it reads the new setting. (chronyd is the service; the d means "daemon," a background program.)
chronyc sources -v
List the time sources. -v (verbose) adds a legend explaining the symbols.
chronyc tracking
Shows how far off the clock currently is.
You should see: your time server marked ^* (the * means "currently using this one") and a tiny "System time" offset in tracking. If STIG already added approved server lines, keep them.
βœ” Checkpoint 4
  1. Both network cards connected. One default route, via .208.
  2. Name, forward lookup, and reverse lookup all match.
  3. chrony is synced to the internal time server.
Step 5

Build an Offline Software Shelf and Install Cockpit

To install anything, dnf needs a repository, a shelf of packages. Normally that shelf is on Red Hat's website. Here you turn the RHEL DVD itself into the shelf, and make sure it's still there after every reboot.

5a. Put the RHEL DVD back in the drive

  1. vSphere β†’ Edit Settings β†’ CD/DVD drive 1 β†’ Datastore ISO File = rhel-9.8-x86_64-dvd.iso. Check Connected and Connect At Power On again. You turned Connect At Power On off in Step 3.

5b. Connect the DVD to a folder, permanently

πŸ’‘ Why use the DVD's label?

Linux names DVD drives /dev/sr0, /dev/sr1, and so on, in the order it finds them. When you add a second DVD in Step 7, those names can swap after a reboot, and you'd connect the wrong disc. Every ISO also has a label (like a name written on the disc) that never changes. Connecting by label always gets the right one.

bashblkid /dev/sr0
blkid
"Block ID": shows a disk's label, its unique ID, and its filesystem type.
/dev/sr0
The first DVD drive. /dev is where Linux lists all hardware.
You should see: something like LABEL="RHEL-9-8-0-BaseOS-x86_64". Copy the exact label into the RHEL ISO label field at the top of the page.
bashmkdir -p /media/rhel
echo 'LABEL= /media/rhel iso9660 ro,nofail 0 0' >> /etc/fstab
systemctl daemon-reload
mount /media/rhel
ls -a /media/rhel
mkdir -p /media/rhel
"Make directory": creates the folder where the DVD will appear. -p means "don't complain if it already exists."
echo '…' >> /etc/fstab
Adds one line to the boot-time mount list. It must be >> (add). A single > would erase every other line, and the server wouldn't boot.
LABEL=…
"Find the disc by this label," not by its drive name.
/media/rhel
The folder where the DVD's contents will show up.
iso9660
The type of filesystem DVDs use.
ro
Read-only. You can't write to a DVD anyway.
nofail
"If the DVD isn't there, keep booting." Without it, a missing DVD would freeze the boot in emergency mode.
0 0
Two old settings: "don't back this up" and "don't disk-check it at boot."
systemctl daemon-reload
Makes systemd re-read fstab.
mount /media/rhel
Connect it now. Giving only the folder makes mount look up the rest in fstab, which also proves your new line works.
ls -a
"List" the folder. -a shows all files, including hidden ones that start with a dot.
You should see: .treeinfo, media.repo, BaseOS, and AppStream. If BaseOS or AppStream is missing, it's the wrong ISO.

5c. Tell dnf about the shelf (one file, used for the whole build)

RHEL splits its software into two shelves: BaseOS (the core operating system) and AppStream (applications and tools). You create one settings file that points dnf at both. This uses the <<'EOF' trick from Step 0.

bashcat > /etc/yum.repos.d/rhel-local.repo <<'EOF'
[rhel-local-baseos]
name=RHEL 9.8 BaseOS (local ISO)
baseurl=file:///media/rhel/BaseOS
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release

[rhel-local-appstream]
name=RHEL 9.8 AppStream (local ISO)
baseurl=file:///media/rhel/AppStream
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release
EOF
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release
dnf clean all
dnf repolist
cat > FILE <<'EOF'
"Create this file with everything I type until the word EOF." See Step 0.
/etc/yum.repos.d/
The folder where dnf looks for shelf definitions. Any file ending in .repo here is read.
[rhel-local-baseos]
The shelf's ID, its short unique name. The square brackets start a new shelf.
name=
A friendly description for humans.
baseurl=file:///…
Where the shelf is. file:// means "a folder on this machine" instead of a website. (The third / is the start of the path.)
enabled=1
Turn this shelf on. 1 = on, 0 = off.
gpgcheck=1
Check Red Hat's digital signature on every package before installing, like checking the tamper seal on a medicine bottle. Keep it on. STIG requires it.
gpgkey=
Where Red Hat's public "seal checker" key is stored. It's already on the system from the install.
rpm --import
Tell the package system "trust packages sealed with this key."
dnf clean all
Throw away any old saved shelf lists so dnf reads the new file fresh.
dnf repolist
List the shelves dnf can use right now.
You should see: rhel-local-baseos and rhel-local-appstream in the list. A message about "subscription management" is harmless, because this server isn't registered with Red Hat online.

5d. Install Cockpit and the SELinux tool

bashdnf install -y cockpit cockpit-files policycoreutils-python-utils
dnf install
"Install these packages" (plus anything they depend on).
-y
Answer "yes" automatically when it asks "Is this OK?" Leave it off if you want to read the list first.
cockpit
The web management page.
cockpit-files
Adds a file browser to Cockpit (used in the Secret Mission).
policycoreutils-python-utils
Contains semanage, the tool that changes SELinux rules. You need it in Step 6.
πŸ”§ If this happens
  • "No match for argument: cockpit-files" β†’ that package isn't on your DVD. Install the other two and skip the file browser.
  • "Cannot find a valid baseurl" β†’ the DVD isn't connected. Run findmnt /media/rhel to check.
  • dnf hangs trying to reach the internet β†’ see Troubleshooting: dnf hangs.
βœ” Checkpoint 5
  1. The DVD connects from fstab by label, so it survives a reboot.
  2. One repo file, both shelves listed, signature checking on.
  3. Cockpit and semanage installed.
Step 6

Move Cockpit to Port 9091 and Give It a Trusted ID

Cockpit normally answers on port 9090. Satellite also needs 9090 for one of its own services (the Capsule/foreman-proxy). Two programs can't share one door, so Cockpit moves next door to 9091 now, before Satellite arrives.

πŸ”’ The three-layer rule for ANY port change

On a hardened RHEL server, a port change has to pass three separate checkpoints. Miss one and it fails, usually with no error message.

  1. The internal guard (SELinux): is the program allowed to use this door?
  2. The outer fence (firewall): may outside traffic reach this door?
  3. The service itself (systemd): is the program actually standing behind this door?

This is always true, for every service. Moving SSH to 2222 or Apache to 8080 works the same way; only the names change.

6a. Make sure 9091 is free

bashss -tlnp | grep -E ':909[01]\b'
semanage port -l | grep -w 9091
ss
"Socket statistics": shows which doors (ports) are open and which program is behind each.
-t
Only TCP connections (web traffic is TCP).
-l
Only doors that are listening, waiting for visitors.
-n
Show port numbers (9090) instead of names.
-p
Show the program behind each door.
| grep -E ':909[01]\b'
Keep only lines for port 9090 or 9091. [01] means "0 or 1," and \b stops it matching 90901.
semanage port -l
List (-l) every port SELinux knows about and who may use it.
grep -w
Match the whole word 9091 only.
You should see: nothing about 9091 in either. If something already uses 9091, stop and pick another port.

6b. Layer 1: the internal guard (SELinux)

bashsemanage port -a -t websm_port_t -p tcp 9091
semanage port
"Manage SELinux's port rules."
-a
Add a new rule.
-t websm_port_t
The type, the SELinux "badge" Cockpit carries. websm is short for "web systems management." Any port with this badge is one Cockpit may use.
-p tcp
The protocol.
9091
The port getting the badge.
πŸ”§ If this happens
  • "Port tcp/9091 already defined" β†’ it was added earlier. That's fine, keep going.

6c. Layer 2: the outer fence (firewall)

bashfirewall-cmd --permanent --add-service=cockpit
firewall-cmd --permanent --service=cockpit --add-port=9091/tcp
firewall-cmd --permanent --service=cockpit --remove-port=9090/tcp
firewall-cmd --reload
firewall-cmd --info-service=cockpit
firewall-cmd --list-services
firewall-cmd
The tool that controls the firewall.
--permanent
"Save this change so it survives a reboot." Permanent changes don't take effect until --reload.
--add-service=cockpit
"Let Cockpit traffic through the fence."
--service=cockpit --add-port=9091/tcp
Changes what "Cockpit" means to the firewall: add port 9091 to its definition.
--remove-port=9090/tcp
Take 9090 out of Cockpit's definition, freeing it for Satellite.
--reload
"Apply the saved changes now."
--info-service=cockpit
Show which ports the "cockpit" definition now includes.
--list-services
Show every service allowed through the fence.
You should see: ports: 9091/tcp for cockpit, and cockpit in the services list.

6d. Layer 3: the service itself (systemd)

Cockpit uses socket activation: systemd stands at the door on Cockpit's behalf and wakes Cockpit up only when someone knocks. So you tell systemd which door to stand at. You do it with a small override file called a drop-in, instead of editing Cockpit's original file, so software updates won't undo your change.

bashmkdir -p /etc/systemd/system/cockpit.socket.d
cat > /etc/systemd/system/cockpit.socket.d/listen.conf <<'EOF'
[Socket]
ListenStream=
ListenStream=9091
EOF
systemctl daemon-reload
systemctl enable --now cockpit.socket
systemctl restart cockpit.socket
systemctl show cockpit.socket -p Listen
ss -tlnp | grep -E ':909[01]\b'
mkdir -p …cockpit.socket.d
Creates the drop-in folder. Any folder named <unit>.d holds overrides for that unit.
cat > … <<'EOF'
Create the override file with the next three lines (see Step 0).
[Socket]
"These settings are about the door."
ListenStream= (blank)
"Forget the doors you were told about before." This erases the built-in 9090. Without this line, Cockpit would answer on both 9090 and 9091.
ListenStream=9091
"Now stand at door 9091."
systemctl daemon-reload
Make systemd re-read its settings files.
enable --now
enable means "start at every boot." --now means "and start it right now too."
restart
Stop and start again so it moves to the new door.
show -p Listen
Show one property, the door it's listening on.
ss -tlnp | grep …
Double-check from the outside, same as 6a.
You should see: Listen=[::]:9091 (Stream), and ss shows 9091 owned by systemd, with nothing on 9090. Seeing systemd instead of cockpit is correct, since systemd is holding the door.
πŸ”€ Your choice: systemctl edit vs. this method

systemctl edit cockpit.socket does the same job through a text editor, but saves to a file named override.conf. Pick one method. If both files exist, both apply, which gets confusing.

6e. Test it, from the inside out

Always test the closest thing first (the server itself), then work outward to your browser. The first test that fails tells you which layer is broken. The full checklist is in Troubleshooting β†’ port won't load.

bash β€” on the servercurl -skI https://localhost:9091 | head -1
curl
A command-line web browser.
-s
Silent: no progress bar.
-k
Skip the certificate (ID card) check. This test only asks "is Cockpit answering at all?"
-I
Only fetch the page's header, not the whole page.
https://localhost:9091
localhost means "this same machine."
| head -1
Show only the first line.
You should see: a line starting with HTTP/1.1 200. 200 means "OK."
PowerShell β€” on the Windows jump serverClear-DnsClientCache
Test-NetConnection -ComputerName  -Port 9091
Clear-DnsClientCache
Makes Windows forget names it looked up earlier, so it asks DNS fresh.
Test-NetConnection
Windows' "can I reach it?" tester.
-ComputerName
Which server. Using the full name tests DNS at the same time.
-Port 9091
Try to knock on this door.
You should see: TcpTestSucceeded : True. Then open Edge to https://:9091.

6f. Install the trusted certificate chain (recommended)

Right now Cockpit shows your browser a self-signed certificate, an ID card it made for itself. Edge doesn't trust that and shows a warning. The fix is to get a card signed by your organization's certificate authority.

Your Windows DNS servers also run Active Directory Certificate Services (AD CS), so the organization already has an internal certificate authority. DNS publishes the VM's name, while the CA signs proof that the name belongs to this server.

πŸ“£ Keep private keys separate

A private key proves the server's identity. Keep it in its service-specific, root-only location on the server.

  • Never transfer /root/cockpit_cert/cockpit.key to AD CS.
  • Never place it in /etc/pki/ca-trust/source/anchors/. That folder is for public CA certificates only.

Rule: public certificates travel; private keys never leave the server.

Show the certificate steps

Step A: Get the CA's public certificate

  1. Ask the PKI owner whether the AD CS instance is the root CA (the top of the chain of trust) or an issuing CA (a middle CA that the root trusts).
  2. If it's an issuing CA, use the approved root CA server for the next steps.
  3. On the root CA server, open Windows PowerShell as Administrator (right-click β†’ Run as administrator).
  4. Export the root CA's public certificate to your Desktop with the commands below.
PowerShell β€” on the root CA serverSet-Location "$HOME\Desktop"
certutil -ca.cert internal-root-ca.cer
Set-Location
PowerShell's "go to this folder" (like cd).
"$HOME\Desktop"
$HOME is your user folder, so this is your Desktop. The quotes keep the path together.
certutil
Windows' built-in certificate tool.
-ca.cert
"Export this CA's own public certificate."
internal-root-ca.cer
The file name to save it as.
πŸ’‘ Where do the CA files come from?

The exported internal-root-ca.cer file contains the root CA's public certificate. It does not contain the CA's private key, so it's safe to copy around.

If AD CS uses an issuing CA, get that public intermediate certificate from the PKI owner as well. The issuing certificate connects the Cockpit certificate to the trusted root, like a middle link in a chain: root β†’ intermediate β†’ Cockpit.

Step B: Teach the RHEL server to trust your CA

  1. Move the .cer file(s) through the approved transfer process into /etc/pki/ca-trust/source/anchors/ on the server. They must be in PEM (Base-64) format. If head -1 on the file shows -----BEGIN CERTIFICATE-----, it is.
bashupdate-ca-trust extract
update-ca-trust extract
"Rebuild the server's list of trusted CAs, including anything new in the anchors folder."

Step C: Make the private key and the certificate request on the server

You create two things. The private key is the secret, and it stays here. The CSR (Certificate Signing Request) is a form that says "please sign an ID card for this name." Only the CSR goes to the CA.

bashmkdir -p /root/cockpit_cert && chmod 700 /root/cockpit_cert
openssl genrsa -out /root/cockpit_cert/cockpit.key 4096
chmod 600 /root/cockpit_cert/cockpit.key
cat > /root/cockpit_cert/openssl.cnf <<'EOF'
[ req ]
prompt = no
distinguished_name = dn
req_extensions = v3_req
[ dn ]
CN = 
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = DNS:
EOF
openssl req -new -key /root/cockpit_cert/cockpit.key -config /root/cockpit_cert/openssl.cnf -out /root/cockpit_cert/cockpit.csr
mkdir -p … && chmod 700
Make a folder, and if that worked (&&) lock it so only root can open it. 700 = owner can do everything, nobody else can do anything.
openssl
The Swiss-army knife for keys and certificates.
genrsa
"Generate an RSA private key." RSA is a FIPS-approved key type.
-out FILE
Where to save the result.
4096
Key size in bits. Bigger means harder to break.
chmod 600
Lock the key file so only root can read or change it. 600 = owner read and write, nobody else anything.
prompt = no
"Don't ask me questions; take the answers from this file."
CN =
"Common Name": the server's name on the card.
basicConstraints CA:FALSE
"This card can't sign other cards." It's a server ID, not a CA.
keyUsage / extendedKeyUsage serverAuth
"This card may only be used to prove a server's identity."
subjectAltName = DNS:…
The names the card is valid for. Browsers check this field, so it must match the URL you type exactly.
req -new
"Make a new certificate request."
-key
Which private key to build the request from.
-config
Which settings file to use (the one you just wrote).
-out
Where to save the CSR.
  1. Transfer only cockpit.csr to AD CS. Have it signed with the approved web server template, in Base-64 (PEM) format.
  2. Bring the signed card back and save it as /root/cockpit_cert/cockpit.crt.

Step D: Give the new ID card to Cockpit

bashcat /root/cockpit_cert/cockpit.crt > /etc/cockpit/ws-certs.d/50-internal.cert
# only if you have an intermediate CA:
# cat /etc/pki/ca-trust/source/anchors/intermediate.pem >> /etc/cockpit/ws-certs.d/50-internal.cert
install -m 600 /root/cockpit_cert/cockpit.key /etc/cockpit/ws-certs.d/50-internal.key
/usr/libexec/cockpit-certificate-ensure --check
systemctl restart cockpit.socket
cat … > …50-internal.cert
Copy the signed card into Cockpit's certificate folder. > creates or replaces the file.
# lines
Comments, which do nothing. If you have an intermediate, remove the # from the second one. Its >> adds the intermediate after your card, forming the chain.
install -m 600
Copy the key and lock it to root-only in one step (-m = set mode, meaning permissions).
50-internal.cert / .key
Cockpit picks the card and key that share the same name and come last alphabetically. The 50- makes sure yours wins.
cockpit-certificate-ensure --check
"Which card will you use, and does the key match?" It only checks and changes nothing.
systemctl restart cockpit.socket
Restart so Cockpit picks up the new card.

Step E: Teach the Windows workstation to trust your CA

  1. Press Win+R, type mmc β†’ File β†’ Add/Remove Snap-in β†’ Certificates β†’ Computer account β†’ Local computer.
  2. Look in Trusted Root Certification Authorities for your internal root CA. If it's missing, right-click β†’ Import internal-root-ca.cer there.
  3. Import any intermediate into Intermediate Certification Authorities.
  4. Open Edge to https://:9091. There should be no warning.

6g. Lab vs. production: what changes when DoD issues the certificate

In this lab, your own internal CA (AD CS) signs the certificate. In production on a DoD network, you don't sign it yourself. You send the request to the DoD PKI (Public Key Infrastructure, the DoD's official certificate system), and it sends back an official DoD certificate. The steps on the server look almost the same. What changes is who signs, who is trusted, and how much paperwork is involved.

πŸ’‘ Three levels of ID card
  • Self-signed (Cockpit's default): the server made its own ID card. Like writing your own name on a sticky note. Nobody has a reason to trust it, so browsers warn.
  • Internal CA (this lab): your organization's own office signs it. Trusted only by computers you told to trust that office. Fine for a lab or a small enclave.
  • DoD PKI (production): the Department of Defense's official office signs it. DoD computers already trust the DoD root CAs (they're installed by the DoD InstallRoot tool or by group policy), so every DoD workstation trusts your server with no extra setup. Auditors expect this on DoD systems.
WhatLab (internal CA)Production (DoD PKI)
Who signsYour AD CS server.A DoD issuing CA (for servers, usually one of the DOD SW CA series).
Who you send the CSR toWhoever runs your AD CS.Your organization's PKI sponsor or Registration Authority (RA) / Trusted Agent, through the enrollment process your command uses. You can't just sign it yourself.
ApprovalUsually immediate.A formal request that checks you own the server and the name. Expect days, not minutes. Plan it into the schedule.
Root of trustYour internal root CA (you import it everywhere).The DoD Root CAs. Already trusted by DoD Windows machines. Not trusted by RHEL out of the box, so you add them (below).
ChainRoot β†’ (maybe) your issuing CA β†’ server.DoD Root CA β†’ DOD SW CA (intermediate) β†’ your server. You must send the intermediate with your certificate.
Name on the cardWhatever you put in the CSR.The DoD CA may rewrite the subject into DoD format (e.g. CN=…, OU=PKI, OU=DoD, O=U.S. Government, C=US). What browsers check is the SAN (the DNS name), so that must still match your FQDN exactly.
Key rulesYour choice.Must follow DoD policy (RSA 2048 is the common minimum). Ask your RA which key sizes they accept before generating the key, because some enrollment systems reject sizes they don't expect.
Revocation checkingUsually skipped.DoD requires checking whether certificates were cancelled (CRLs, the "cancelled cards" lists). On an air-gapped network you have to bring updated CRLs in regularly, or checks start failing when the old list expires.
ExpirationWhatever you set.Fixed by DoD policy. Put the expiry date in your calendar and start the renewal request weeks early, since approval takes time.
Which networkLab.On NIPRNet (unclassified) it's the DoD PKI. On SIPRNet (classified) it's a separate system, the NSS PKI, with its own roots and its own RA. The steps are the same shape, but the CAs and contacts are different.
What gets a certCockpit only (optional).Cockpit and Satellite's own web page (port 443). Satellite part below.
πŸ”’ Always true in lab and production
  • The private key is made on the server and never leaves it. Only the CSR travels. That's exactly the same with DoD.
  • The SAN must match the name people type in the browser.
  • You install the certificate plus its intermediate chain, and the key stays chmod 600.

Production step 1: Teach RHEL to trust the DoD roots

DISA publishes the DoD root and intermediate CA certificates as a downloadable bundle on the public DoD Cyber Exchange (public.cyber.mil, PKI/PKE section). Download it on an approved connected system, bring it across with the approved transfer process, then:

bashls *.p7b
openssl pkcs7 -in  -print_certs -out /etc/pki/ca-trust/source/anchors/dod-cas.pem
grep -c 'BEGIN CERTIFICATE' /etc/pki/ca-trust/source/anchors/dod-cas.pem
update-ca-trust extract
trust list | grep -i 'DoD Root'
ls *.p7b
Find the bundle file. .p7b (PKCS#7) is a "bag" that holds many certificates in one file.
openssl pkcs7
Open a PKCS#7 bag.
-in FILE
Which bag. Use the file whose name ends in .pem.p7b. If you only have a plain .p7b, add -inform DER ("the file is in binary format").
-print_certs
"Take every certificate out of the bag and write them as normal text certificates."
-out FILE
Save them straight into the trust anchors folder.
grep -c 'BEGIN CERTIFICATE'
-c = count matching lines. Each certificate starts with that line, so this counts how many you got.
update-ca-trust extract
Rebuild the server's trusted list with the new CAs.
trust list | grep -i 'DoD Root'
trust list shows every trusted CA. grep -i finds DoD roots, ignoring upper/lower case.
You should see: a count of several dozen certificates, and DoD Root CA entries in the trust list.
πŸ“£ Only trust what came from DISA

Take the bundle only from the official DISA source through your approved transfer process. Adding a CA to the anchors folder tells the server "trust anything this CA signs," so a fake CA there would be a serious hole.

Production step 2: Make the key and CSR

Same as Step C above. Only change the key size if your RA requires it (for example 2048 instead of 4096), and use the exact name format they ask for. Then send only cockpit.csr to your PKI sponsor or RA using your command's process.

Production step 3: Check what DoD sent back

You'll get your server certificate, and often the DOD SW CA intermediate. Before installing, check the card is right:

bashopenssl x509 -in /root/cockpit_cert/cockpit.crt -noout -subject -issuer -enddate -ext subjectAltName
openssl verify -CAfile /etc/pki/tls/certs/ca-bundle.crt /root/cockpit_cert/cockpit.crt
diff <(openssl x509 -in /root/cockpit_cert/cockpit.crt -noout -pubkey) <(openssl pkey -in /root/cockpit_cert/cockpit.key -pubout)
openssl x509 -in FILE
Read this certificate.
-noout
Don't print the scrambled certificate text.
-subject
Show the name the card was issued to.
-issuer
Show who signed it. It should be a DOD SW CA.
-enddate
Show the expiration date. Put it in your calendar.
-ext subjectAltName
Show the DNS names it's valid for. It must include your FQDN.
openssl verify
"Does this card chain up to a CA I trust?"
-CAfile …ca-bundle.crt
Use the server's full trusted list, which now includes the DoD roots and intermediates from step 1.
diff <(…) <(…)
diff compares two things and prints only differences. <( ) means "treat this command's output like a file." It compares the public key inside the certificate with the public key made from your private key.
openssl pkey -in KEY -pubout
Read the private key and print only its public half.
You should see: the issuer is a DoD CA, the SAN has your FQDN, verify says OK, and diff prints nothing (nothing printed = the key matches the card). If diff prints lines, this certificate was made from a different key. Don't install it.

Production step 4: Install it for Cockpit

Same as Step D. Put your certificate first, then the DOD SW CA intermediate after it with >> (remove the # on that line). The DoD intermediate is not optional.

Production step 5: Give Satellite's own web page the DoD certificate

In production, Satellite's main page (port 443) needs an official certificate too, not the one it made for itself during install. Satellite's certificate must include the Satellite FQDN in its SAN, so you can reuse the same request process with its own key and CSR (for example in /root/satellite_cert/).

bashcat   > /root/satellite_cert/dod-chain.pem
katello-certs-check \
  -c /root/satellite_cert/satellite.crt \
  -k /root/satellite_cert/satellite.key \
  -b /root/satellite_cert/dod-chain.pem
cat A B > chain.pem
Glue the intermediate and the root into one "chain" file. > creates it.
katello-certs-check
Satellite's certificate checker. It only checks, changing nothing, and at the end prints the exact installer command to use.
-c
Your server certificate.
-k
Its private key.
-b
The CA bundle (the chain file).
You should see: "Validation succeeded," followed by a ready-made satellite-installer command. Run the command it prints. It will look like this:
bash β€” example; use the one katello-certs-check printssatellite-installer --scenario satellite \
  --certs-server-cert /root/satellite_cert/satellite.crt \
  --certs-server-key /root/satellite_cert/satellite.key \
  --certs-server-ca-cert /root/satellite_cert/dod-chain.pem \
  --certs-update-server --certs-update-server-ca
--scenario satellite
Same setup as before, just updating it.
--certs-server-cert
The DoD certificate for the web page.
--certs-server-key
Its private key.
--certs-server-ca-cert
The DoD chain that signed it.
--certs-update-server
"Replace the current web certificate with this one."
--certs-update-server-ca
"Also update the CA that clients are told to trust," so registered clients trust the new certificate.
πŸ“£ Clients need the new CA too

Servers already registered to Satellite trusted the old self-made certificate. After this change, update them. The simplest way is to re-run the registration command from Satellite (Hosts β†’ Register Host) or reinstall the katello-ca-consumer package from https://FQDN/pub/. Do this in a planned maintenance window, because clients can't check in until they trust the new chain.

βœ” Checkpoint 6
  1. ss shows 9091 listening and nothing on 9090.
  2. Cockpit loads at https://FQDN:9091, you can log in, and Cockpit's Terminal shows the right name for hostname -f.
Step 7

Install Satellite's Software From Its DVD

Satellite comes on its own DVD. You "insert" it as a second DVD drive, connect it, and run Red Hat's script, which installs Satellite and pulls any extra pieces it needs from the RHEL shelf you built in Step 5.

  1. vSphere β†’ Edit Settings β†’ Add New Device β†’ CD/DVD Drive β†’ Datastore ISO File β†’ Satellite-6.19.1-rhel-9-x86_64.dvd.iso. Check Connected and Connect At Power On β†’ OK.
bashlsblk -o NAME,SIZE,TYPE,LABEL,MOUNTPOINTS
lsblk
List disks and drives.
-o NAME,SIZE,TYPE,LABEL,MOUNTPOINTS
Only these columns. TYPE rom means a DVD drive. LABEL tells the two discs apart.
You should see: two rom drives. The one not connected to /media/rhel, with a Satellite label, is the new one, usually sr1.
bashmkdir -p /media/sat6
mount -o ro /dev/sr1 /media/sat6
findmnt -t iso9660
ls /media/sat6
mkdir -p /media/sat6
Make a folder for the Satellite DVD.
mount
Connect a disk to a folder.
-o ro
Options: read-only. No fstab line this time, because you only need this DVD during install.
/dev/sr1 /media/sat6
"Connect drive sr1 to this folder." Swap in sr0 if lsblk showed that.
findmnt -t iso9660
List every connected DVD (-t filters by type).
ls
List what's on the DVD.
You should see: both /media/rhel and /media/sat6, and an install_packages file on the Satellite DVD.
bashdnf upgrade -y
cd /media/sat6
./install_packages
dnf upgrade -y
Bring every installed package up to the newest version on your shelves. -y means auto-yes. It usually finds nothing, since you installed from the same DVD.
cd /media/sat6
"Change directory": go into the Satellite DVD folder. The script expects to run from there.
./install_packages
./ means "the file right here in this folder." Linux doesn't run programs from the current folder unless you say so, for safety. The script creates a temporary shelf from the DVD and installs Satellite.
You should see: it ends with Install is complete. Please run satellite-installer --scenario satellite.
πŸ”§ If this happens
  • "No match" or a missing dependency β†’ check both DVDs are connected (findmnt -t iso9660) and both RHEL shelves are listed (dnf repolist).
  • One specific package is truly missing β†’ bring that exact RPM over through the approved transfer process, then run the script again.
βœ” Checkpoint 7
  1. The script finished with "Install is complete."
Step 8

Set Up Satellite and Open It to Client Servers

The software is installed but not set up yet. Now you run satellite-installer, which creates the database, the web interface, the ID cards, and all the services. Before that, do one last check that everything it depends on is right.

8a. Pre-flight check (everything must pass)

bashhostname -f
getent hosts $(hostname -f)
getent hosts 
chronyc tracking | grep -E 'Reference|System time'
df -h /var/lib/pgsql /var/lib/pulp /tmp
findmnt -o OPTIONS /tmp
ss -tlnp | grep -E ':9090\b'
hostname -f
The server's full name.
$( … )
"Run the command inside first and put its answer here." So this looks up whatever hostname -f printed.
getent hosts IP
Reverse lookup, IP β†’ name.
chronyc tracking | grep -E '…|…'
Clock status, trimmed to the time-source line and the "how far off" line. | inside the quotes means "or."
df -h
"Disk free": how full each room is. -h = human-readable sizes (G, T) instead of raw numbers.
findmnt -o OPTIONS /tmp
Just the rules on /tmp.
ss -tlnp | grep ':9090\b'
Is anything behind door 9090? It must print nothing.
You should see: name and IP match both ways, the clock is synced, pgsql and pulp are separate rooms, /tmp has no noexec, and nothing on 9090.

8b. Run the Satellite installer

πŸ“£ The organization name is forever

The first organization's internal label can't be changed later. Confirm the approved name before you press Enter.

bashsatellite-installer --scenario satellite \
  --foreman-initial-organization "" \
  --foreman-initial-location "" \
  --foreman-initial-admin-username 
satellite-installer
Red Hat's setup program for Satellite.
--scenario satellite
"Build a full Satellite server" (with its own local database), not a smaller Capsule.
--foreman-initial-organization
The first organization, the top-level container for everything. Foreman is the open-source project Satellite's web interface is built on, which is why the options start with "foreman."
--foreman-initial-location
The first location (usually a site or building).
--foreman-initial-admin-username
The first admin login name.
\
The command continues on the next line.
πŸ’‘ Why isn't there a password option?

Anything you type in a command is saved in your command history (~/.bash_history), where anyone with root can read it later, and STIG auditors check that file. If you leave the password out, the installer makes up a strong random one and shows it at the end. Save it in your approved password vault, then change it after your first login.

You should see: after 20 to 40 minutes, a success message with the Satellite web address, the admin name, and the generated password.
πŸ”§ If it fails
  • Read the log. The last error lines name the part that broke: grep -n ERROR /var/log/foreman-installer/satellite.log | tail -20. Here grep -n finds lines with ERROR and shows line numbers, and tail -20 shows only the last 20 of them.
  • After fixing the cause β†’ run the exact same command again. The installer is safe to re-run.
bash β€” check every Satellite service is runningsatellite-maintain service status --brief
satellite-maintain
Satellite's maintenance tool.
service status
Check every Satellite service (web server, database, content service, and others).
--brief
One line per service instead of pages of detail.
You should see: every line ending in [OK].

8c. Put away the install DVD

bashcd /
umount /media/sat6
findmnt -t iso9660
cd /
Leave the DVD folder first. You can't disconnect a disk while you're "standing in" it; you'd get "target is busy."
umount
"Un-mount": disconnect it. Note the spelling: umount, not "unmount."
findmnt -t iso9660
Confirm only /media/rhel is left.

Then remove the Satellite DVD drive in vSphere.

πŸ”€ Your choice: keep or remove the RHEL DVD
  • Keep it (default): future dnf install commands keep working from the RHEL shelf.
  • Remove it: then switch the shelves off, or every dnf command errors: sed -i 's/^enabled=1/enabled=0/' /etc/yum.repos.d/rhel-local.repo. Here sed -i edits the file in place, s/old/new/ swaps text, and ^ means "at line start." Also delete or comment out (#) the /media/rhel line in fstab.

8d. Log in to Satellite

  1. In Edge go to https://. Always use the full name, never the IP.
  2. A certificate warning is normal here. Satellite made its own CA during install. Continue only if the certificate shows your server's name.
  3. Log in, check the organization and location, then change the admin password.

8e. Let approved client servers reach Satellite

Right now the firewall only lets in SSH and Cockpit. Your client servers need to reach Satellite's web ports. You'll open them only for the approved client network, not for everyone.

bashfirewall-cmd --get-active-zones
--get-active-zones
Firewall rules are grouped into zones. This shows which zone each network card uses.
You should see: a zone name with NIC1 listed under it. Type that zone in the firewalld zone field.
bashfirewall-cmd --permanent --zone= --add-rich-rule='rule family="ipv4" source address="" service name="https" accept'
firewall-cmd --permanent --zone= --add-rich-rule='rule family="ipv4" source address="" service name="http" accept'
firewall-cmd --reload
firewall-cmd --zone= --list-all
--permanent
Save it so it survives reboots.
--zone=
Which zone to change.
--add-rich-rule='…'
A "rich rule" is a rule with conditions. The single quotes keep the whole rule together as one piece.
rule family="ipv4"
This rule is about IPv4 traffic.
source address="CIDR"
"Only from this network." A CIDR like 10.10.220.0/24 means a whole range of addresses.
service name="https"
Port 443, the secure web port clients use to register and download.
service name="http"
Port 80, also used for downloads and one registration step.
accept
Let matching traffic in.
--reload
Apply the saved rules now.
--list-all
Show everything configured in that zone.
You should see: two rich rules for your client network. Also make sure the output does not show target: ACCEPT or plain http/https under services. Either of those would let everyone in and undo your restriction.
πŸ”’ Always true for ports on this server
  • Client servers β†’ Satellite: 443 and 80 only, and only from approved networks.
  • Admins only: 22 (SSH) and 9091 (Cockpit).
  • Every other port stays closed until the matching feature is approved and turned on.
bash β€” from a client server inside the approved networkgetent hosts 
curl -I --connect-timeout 10 http:///
curl -I --connect-timeout 10 https:///
getent hosts
Can the client find Satellite's address?
curl -I
Fetch just the page header.
--connect-timeout 10
Give up after 10 seconds instead of waiting forever.
You should see: the right IP, then a header for both. A timeout means a firewall or network path problem. A certificate error means the client doesn't trust Satellite's CA yet (normal until the client is registered).
βœ” Checkpoint 8
  1. All services [OK], and the dashboard loads by full name.
  2. A client in the approved network gets a response on 80 and 443.
Step 9

Lock Satellite Offline and Load Your Own Packages

Two last jobs. First, tell Satellite it will never talk to Red Hat online, so it stops trying. Second, load a set of approved packages (RPMs) into Satellite so client servers can install them.

9a. Switch Satellite to offline mode

  1. Content β†’ Subscriptions β†’ Manage Manifest β†’ CDN Configuration tab β†’ choose Export Sync β†’ Update. (This means "content arrives by exported files, not by download.")
  2. Administer β†’ Settings β†’ Content tab β†’ Subscription Connection Enabled = No. Reload the page and confirm it saved.

9b. Make a drop-off folder on the big disk

πŸ’‘ Why not your home folder?

/home is small on purpose (10 GiB) and has noexec. A real batch of packages can fill it quickly. /var lives on the 2 TB data disk, so the drop-off folder goes there.

bashmkdir -p /var/local/rpm-staging
chown : /var/local/rpm-staging
chmod 750 /var/local/rpm-staging
ls -ld /var/local/rpm-staging
mkdir -p
Create the folder (no error if it exists).
chown user:group
"Change owner": make your admin user the owner, so it can upload files there.
chmod 750
"Change mode" (permissions). Each digit is one audience: 7 = owner can read, write, and open; 5 = the group can read and open; 0 = everyone else gets nothing.
ls -ld
List with details (-l), showing the folder itself (-d) rather than what's inside it.
You should see: drwxr-x--- … … /var/local/rpm-staging. The letters are the 750 permissions written out: d = directory, rwx = owner, r-x = group, --- = everyone else.

9c. Copy the packages over with WinSCP

WinSCP is a Windows program for copying files to Linux over SSH (the encrypted remote-login protocol).

  1. WinSCP β†’ New Site β†’ protocol SFTP, host , port 22, user β†’ Login.
  2. WinSCP shows the server's fingerprint, a short code unique to this server. Accept it only if it matches the one from the server itself: run ssh-keygen -lf /etc/ssh/ssh_host_ecdsa_key.pub. Here -l means "show the fingerprint" and -f means "of this file." This protects you from connecting to an impostor.
  3. Right panel: go to /var/local/rpm-staging. Left panel: the approved package share. Upload, and wait until the queue is empty.
bashfind /var/local/rpm-staging -type f -name '*.rpm' | sort
rpm -K /var/local/rpm-staging/*.rpm
find FOLDER
Search this folder and every folder inside it.
-type f
Only regular files (not folders).
-name '*.rpm'
Only names ending in .rpm. The quotes stop the shell from expanding * too early.
| sort
Put the list in alphabetical order, so it's easy to compare with the source.
rpm -K
Check each package's tamper seal (digest and signature). OK is good. NOT OK means damaged in transit or unsigned. Unsigned may be fine for in-house packages if approved.

9d. Create a product and repository in Satellite

In Satellite, a product is a labeled box, and a repository is a shelf inside it that holds packages.

  1. Content β†’ Products β†’ Create Product β†’ Name Offline Custom Packages β†’ Save.
  2. Repositories tab β†’ New Repository β†’ Name Approved RPMs, Type yum, leave Upstream URL empty (there's no internet source), HTTP Proxy Policy No HTTP Proxy β†’ Save.
bashhammer repository list --organization "" --product "Offline Custom Packages"
hammer
Satellite's command-line tool, which does what the web page does, from the terminal. The installer already saved root's login for it.
repository list
"List repositories."
--organization "…"
Only in this organization. Quotes keep names with spaces together.
--product "…"
Only in this product.
You should see: a table row for Approved RPMs. Type its ID number into the Custom repo ID field.
bashhammer repository upload-content --id  --path /var/local/rpm-staging
hammer repository info --id  | grep -A3 -i 'content counts'
upload-content
"Put packages onto this shelf." Satellite builds the shelf's index for you.
--id
Which repository (the number from the last step).
--path
Where the packages are. A folder uploads everything in it.
repository info
Show the repository's details.
grep -A3 -i 'content counts'
Find the "Content Counts" section. -i ignores upper/lower case; -A3 also shows the 3 lines After it.
You should see: a Packages: number equal to how many RPMs you uploaded. In the web page, Products β†’ Approved RPMs β†’ Packages lists them by name.
βœ” Checkpoint 9
  1. Export Sync selected and Subscription Connection = No.
  2. Package count matches what you uploaded, and there's no upstream URL.
Bonus

Secret Mission and Cleanup

Secret mission: move a file using only your browser

  1. In Cockpit (:9091) open File browser β†’ go to /var/tmp β†’ upload an approved, non-sensitive test file.
  2. In Cockpit's Terminal run ls -l /var/tmp/<file> (list with details) and stat -c '%n %s bytes' /var/tmp/<file>. stat shows file facts; -c sets a custom format, where %n is the name and %s the size.
  3. Take a screenshot, then delete the file.

Cleanup

If you want to…Do this
Keep it runningKeep Export Sync on. Empty /var/local/rpm-staging per your retention policy. Check df -h /var/lib/pulp now and then, because the library grows.
Pause itOn the console run satellite-maintain service stop (stops every Satellite service cleanly), then shut the VM down from vSphere.
Delete itDelete the VM from disk in vSphere, remove its A and PTR records from DNS, and remove any lab-only CA from Windows certificate stores.