A Server Baseline Has to Survive Reality
A server build is not complete because packages installed successfully. It is complete when the machine survives reboot, reconnects through its intended administration paths, starts its workloads, mounts expected storage, and reports a clean service state.
This guide closes the baseline by making desktop-oriented behavior explicit, removing unnecessary management surfaces, inspecting firmware state, and recording final host and VM health.
This guide assumes you completed Convert an Encrypted Secondary SSD into Server Storage, or deliberately skipped that optional storage layer, and that the host, VM, SSH paths, and Tailscale administration from the previous guides are already working.
Example values: Hostnames, usernames, addresses, interface names, device paths, and other identifiers are illustrative unless explicitly described as software defaults. Discover the values on your own systems before running commands.
An Always-On Server Should Not Suspend Itself
A desktop-oriented installation may suspend when idle. That is usually wrong for an always-on local server even if the attached display is allowed to blank or power down.
Mask the system sleep targets and immediately verify the result:
sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
systemctl is-enabled sleep.target suspend.target hibernate.target hybrid-sleep.target
When the policy is active, all four targets report masked.
systemd defines these special targets as synchronization points for sleep, suspend, hibernate, and hybrid-sleep transitions.1 Masking them prevents normal activation through systemd while leaving display power management as a separate concern.
The desktop layer can still have its own idle-power policy. GNOME exposes automatic-suspend settings through org.gnome.settings-daemon.plugins.power, and GDM runs its greeter with its own dconf profile.10 That means an SSH session can still receive a broadcast such as The system will suspend now! from gdm-greeter even when the systemd sleep targets remain masked. Treat the broadcast as evidence that the graphical layer requested suspend, not by itself as proof that the server actually entered sleep.
If you see that message, verify the four targets are still masked and inspect the boot journal before changing the server-side safety net. If the host should never even request automatic suspend, configure the GNOME/GDM idle policy deliberately as a separate layer: the desktop setting stops the request, while the systemd mask remains the server-side backstop.1:110:1
To reverse the systemd decision:
sudo systemctl unmask sleep.target suspend.target hibernate.target hybrid-sleep.target
Every Management Surface Should Be Intentional
Fedora Server commonly advertises Cockpit, and some installations enable cockpit.socket automatically.
Cockpit is a legitimate web administration interface. It should still be present because you chose it, not because the distribution happened to offer it. Cockpit's own documentation says the web service normally starts on demand through cockpit.socket, usually on TCP 9090, and that systems not intended for browser access can leave the socket disabled.2
Check on the host and inside the VM:
systemctl is-enabled cockpit.socket
systemctl is-active cockpit.socket
If SSH is the intended administration surface and Cockpit is not part of the design:
sudo systemctl disable --now cockpit.socket
systemctl is-enabled cockpit.socket
systemctl is-active cockpit.socket
After disabling the socket, the final state is disabled and inactive.
If you later enable Cockpit, expose TCP 9090 deliberately through the host firewall and/or Tailnet policy instead of opening it by habit.
Firmware State Deserves a Periodic Look
Refresh fwupd metadata and inspect both actual upgrades and recognized devices:
sudo fwupdmgr refresh --force
fwupdmgr get-upgrades
fwupdmgr get-devices
A device can be marked Updatable because fwupd knows how to update it while still having no newer firmware available. The fwupdmgr reference defines get-upgrades/get-updates as the operation for real available updates.3
The Linux Vendor Firmware Service (LVFS) is the normal metadata and firmware source fwupd uses on supported hardware.3:1 Do not run a blanket firmware update until you understand which device is targeted, whether a reboot is required, and whether the update comes through an expected LVFS or vendor path.
SELinux Should Still Be Enforcing at the End
Check the state:
getenforce
You want Enforcing.
If a service fails because of an SELinux denial, investigate the denial instead of switching the whole machine to permissive mode:
sudo ausearch -m AVC -ts recent
sudo journalctl -t setroubleshoot --since "10 minutes ago"
Fedora's SELinux troubleshooting guidance explicitly frames AVC inspection and policy diagnosis as the correct first path rather than global disablement.4
Firewall Boundaries Should Still Match the Architecture
Inspect active zones and the physical-server zone:
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --zone=local-server --list-all
A finished policy may resemble:
local-server
interfaces: <WIRED_INTERFACE>
rich rules:
source <TRUSTED_LAN_CIDR> service ssh accept
libvirt
interfaces: virbr0
firewalld's zone model associates interfaces and sources with trust policy, while rich rules allow source-specific service permissions such as the SSH rule used in this series.5
Check the rich rules for source subnets left over from an old router, and remove any that no longer describe a trusted network. An empty services: line is not a problem worth solving with a broader firewall rule.
Tailscale Is Healthy Only When Policy and Clients Agree
On the physical host:
tailscale version
tailscale status
tailscale lock status
systemctl is-enabled tailscaled
systemctl is-active tailscaled
Run the equivalent checks inside the VM. From the admin workstation, open and exit the primary host session first:
ssh local-server
Back on the admin workstation, open and exit the guest session separately:
ssh server-vm-01
If you intentionally kept LAN fallbacks, test them one at a time too. Start with the physical host fallback:
ssh local-server-lan
After you exit, test the guest fallback from the admin workstation:
ssh server-vm-01-lan
Tailscale's security guidance recommends least-privilege access policy, MFA or passkeys at the identity-provider layer, policy tests, and timely client updates. Tailnet Lock and host firewall policy complement those controls rather than replacing them.6
Tailnet Policy Should Reflect Real Device Roles
For a small administrative Tailnet, verify in the current admin console that:
- only users you recognize belong to the Tailnet;
- only devices you recognize are admitted;
- Tailnet Lock is enabled, if you adopted it, and its trusted signing nodes are known;
- least-privilege Grants are present;
- policy tests are present;
- server key-expiry choices are deliberate;
- client update policy is deliberate.
Do not infer a setting from memory. Check the current Machines, Users, and Policies state.
The exact policy can evolve as services are introduced, but the baseline rule should hold: add reachability because a use case requires it, not because two devices happen to share a Tailnet.
Validate Virtualization Health
On the physical host, inspect domains, networks, and storage pools independently:
sudo virsh -c qemu:///system list --all
sudo virsh -c qemu:///system net-list --all
sudo virsh -c qemu:///system pool-list --all
If autostart is part of the design, the primary VM is running after a normal host boot.
Libvirt treats domains, networks, and storage pools as separate persistent objects; a running VM does not prove all three layers are healthy.7
Optional Storage Can Be Absent Without Making the Host Unhealthy
If the secondary LUKS volume was unlocked during boot:
findmnt /srv/storage
df -h /srv/storage
lsblk -o NAME,SIZE,FSTYPE,LABEL,UUID,MOUNTPOINTS
If you skipped the secondary passphrase intentionally, the host can still be healthy while /srv/storage is unavailable because this series uses nofail for both the encrypted mapping and the mount.8
To unlock later, use the LUKS UUID recorded in Guide 05 instead of falling back to a transient /dev/sdX name:
sudo cryptsetup open /dev/disk/by-uuid/<SECONDARY_LUKS_UUID> server-storage
sudo mount /srv/storage
The distinction is simple:
main encrypted root unavailable → Fedora cannot complete boot
optional secondary volume absent → Fedora may still boot normally
The Full Reboot Test Is the Baseline Gate
Service restarts are useful. They are not a substitute for a real reboot.
sudo reboot
At the physical console:
- unlock the main Fedora LUKS volume if root encryption was chosen;
- unlock secondary storage if you want it mounted immediately;
- allow Fedora to finish booting;
- do not rely on logging into GNOME to start server services.
From the admin workstation, reconnect to the host:
ssh local-server
On the physical host, verify the system-level services and VM state:
systemctl is-active sshd
systemctl is-active tailscaled
sudo virsh -c qemu:///system list --all
systemctl --failed
Return to the admin workstation, connect to the guest, and then verify the guest itself:
ssh server-vm-01
Inside the VM:
systemctl is-active sshd
systemctl is-active tailscaled
systemctl --failed
If VM autostart is configured, opening virt-manager and clicking Start should not be part of normal recovery.
Off-LAN Administration Proves the Router Is No Longer the Identity Layer
Connect the admin workstation through another Internet connection, such as a phone hotspot. With Tailscale connected, verify both peers:
tailscale ping local-server
tailscale ping server-vm-01
Open the host session from the admin workstation:
ssh local-server
Exit that session, return to the admin workstation, and test the guest separately:
ssh server-vm-01
If both sessions work, routine administration no longer depends on the current LAN subnet, an ISP-router DHCP lease, router port forwarding, the VM's libvirt address, or physical presence on the local network.
Tailscale's connection model is designed to preserve private peer connectivity across changing underlying networks, using direct paths where possible and relay infrastructure where necessary.9
A Known-Good Baseline Makes Future Failures Comparable
A plain-text snapshot gives you something concrete to compare against later:
{
echo "===== HOST ====="
hostnamectl
echo
echo "===== TAILSCALE ====="
tailscale version
tailscale status
tailscale ip
echo
echo "===== TAILNET LOCK ====="
tailscale lock status
echo
echo "===== NETWORK ====="
ip -br address
ip route
echo
echo "===== FIREWALL ====="
sudo firewall-cmd --get-active-zones
echo
echo "===== LIBVIRT ====="
sudo virsh -c qemu:///system list --all
sudo virsh -c qemu:///system net-list --all
sudo virsh -c qemu:///system pool-list --all
echo
echo "===== STORAGE ====="
lsblk -o NAME,SIZE,FSTYPE,LABEL,MOUNTPOINTS
findmnt /srv/storage || true
echo
echo "===== SERVICES ====="
systemctl is-active tailscaled
systemctl is-active sshd
systemctl --failed
} 2>&1 | tee ~/local-server-baseline.txt
Inside the VM, capture a smaller guest-specific equivalent.
Treat Baseline Output as Sensitive
Before sharing or publishing these logs, scrub:
- real Tailnet and LAN addresses;
- machine IDs, serial numbers, and UUIDs;
- SSH host-key fingerprints;
- internal hostnames and usernames that reveal private naming;
- Tailnet Lock key material;
- credentials, auth URLs, tokens, and other secrets.
The guide examples are intentionally generic. Your generated baseline is not automatically safe to publish.
The Mac Can Pull a Remote Baseline Without Moving Files Around
From a Mac shell:
ssh local-server 'cat ~/local-server-baseline.txt' | pbcopy
pbcopy runs on the Mac side of the pipe, not on the Fedora server. For the VM, use the guest's actual baseline filename.
The baseline file lives on the machine that generated it, not on the Mac. When you no longer need the host copy, delete it from the admin workstation over SSH:
ssh local-server 'rm ~/local-server-baseline.txt'
Remove the guest's baseline file the same way, using its actual filename and the guest alias.
The Baseline Is Complete When the System Tells the Same Story Everywhere
Use these as completion checks, not as a script to satisfy mechanically. The baseline is complete when every check that applies to your design is true; skip checks for layers you chose not to adopt, such as Tailnet Lock or the optional storage layer.
Host
- [ ] Fedora boots reliably after any required LUKS unlock.
- [ ] The system is updated.
- [ ] Firmware state has been reviewed.
- [ ] SELinux is enforcing.
- [ ] firewalld is active.
- [ ] Suspend/hibernate targets are masked, and desktop/GDM automatic-suspend behavior is intentional for an always-on host.
- [ ]
sshdis enabled and public-key-only. - [ ] LAN SSH is restricted to the intended source subnet.
- [ ] Tailscale starts automatically.
- [ ] Tailnet Lock is verified if adopted.
- [ ] Restrictive Grants are validated.
- [ ] Tailnet users and devices are all expected.
- [ ] KVM/libvirt is functioning.
- [ ] The intended VM autostarts.
- [ ] The intended libvirt network is healthy.
- [ ] The intended storage pool is healthy.
- [ ]
/srv/storagebehaves as designed. - [ ] Cockpit is disabled unless intentionally used.
- [ ]
systemctl --failedreports no unexpected failed units.
VM
- [ ] Fedora Server boots automatically when intended.
- [ ] The root filesystem is sized as intended.
- [ ]
sshdis hardened. - [ ] Tailscale starts automatically.
- [ ] Direct Tailnet SSH works.
- [ ] Tailnet Lock is verified if adopted.
- [ ] Cockpit is disabled unless intentionally used.
- [ ]
systemctl --failedreports no unexpected failed units.
Administration
- [ ] Primary Tailnet SSH aliases work.
- [ ] Off-LAN SSH works.
- [ ] LAN fallback aliases work if retained.
- [ ] No public router port forwarding is required for SSH.
Once these checks pass, future work is no longer basic Fedora setup. It becomes operating and extending the server: backups, observability, applications, containers, additional VMs, storage services, or a dedicated network edge.
A baseline is useful because it gives future change something stable to push against.
LUCKGRID
Multiply the power of your workforce