Posted to Infrastructure on

Maintenance, Validation, and the Known-Good Fedora Server Baseline

Close the build by proving the host and VM survive reboot, recover through the intended administration paths, start the right services, and report a clean baseline.

#fedora#linux#local-server#maintenance#validation#systemd#tailscale#libvirt

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:

  1. unlock the main Fedora LUKS volume if root encryption was chosen;
  2. unlock secondary storage if you want it mounted immediately;
  3. allow Fedora to finish booting;
  4. 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.
  • [ ] sshd is 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/storage behaves as designed.
  • [ ] Cockpit is disabled unless intentionally used.
  • [ ] systemctl --failed reports no unexpected failed units.

VM

  • [ ] Fedora Server boots automatically when intended.
  • [ ] The root filesystem is sized as intended.
  • [ ] sshd is hardened.
  • [ ] Tailscale starts automatically.
  • [ ] Direct Tailnet SSH works.
  • [ ] Tailnet Lock is verified if adopted.
  • [ ] Cockpit is disabled unless intentionally used.
  • [ ] systemctl --failed reports 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

Footnotes

Scroll to article content with footnote reference 1

systemd's systemd.special(7) documentation defines sleep.target, suspend.target, hibernate.target, and hybrid-sleep.target and how they participate in sleep transitions.

Scroll to article content with footnote reference 1 Scroll to article content with footnote reference 1
Scroll to article content with footnote reference 2

Cockpit's official startup documentation explains that cockpit-ws starts on demand through cockpit.socket, normally on port 9090, and explicitly says the socket can be disabled when browser access is not desired.

Scroll to article content with footnote reference 2
Scroll to article content with footnote reference 4

Fedora's SELinux troubleshooting guide documents the audit/setroubleshoot workflow for understanding AVC denials rather than disabling SELinux globally.

Scroll to article content with footnote reference 4
Scroll to article content with footnote reference 6

Tailscale's security best practices recommend identity-provider MFA/passkeys, least privilege, policy tests, client updates, and appropriate device/network firewalling.

Scroll to article content with footnote reference 6
Scroll to article content with footnote reference 7

Libvirt's domain documentation, network documentation, and storage documentation describe these as separate managed object classes with distinct persistence and lifecycle state.

Scroll to article content with footnote reference 7
Scroll to article content with footnote reference 8

systemd's crypttab(5) and systemd.mount(5) references define the two nofail behaviors used for an optional encrypted secondary mount.

Scroll to article content with footnote reference 8
Scroll to article content with footnote reference 9

Tailscale's connection-types documentation explains direct, DERP-relayed, and peer-relayed connections and how Tailscale continues connecting peers when direct paths are unavailable.

Scroll to article content with footnote reference 9
Scroll to article content with footnote reference 10

GNOME's Automatic Suspend user documentation describes desktop idle suspend. The GNOME System Administration Guide documents org.gnome.settings-daemon.plugins.power settings such as sleep-inactive-ac-timeout and sleep-inactive-ac-type, including the nothing action; GNOME's GDM administration documentation describes the separate gdm dconf profile used by the login greeter.

Scroll to article content with footnote reference 10 Scroll to article content with footnote reference 10

Down the rabbit hole

Fedora Local Server Guide

Posted to Infrastructure on
Browse all posts

Map the system you need

Describe the product, workflow, integration, or operation you are building—and where the current system loses power. Include the people, tools, boundaries, constraints, and outcome that matter.

Every message is reviewed. Responses are limited.

Press Escape to close preview popover.