RandyLinux Systems Administrator
OSRHEL (work) / Fedora KDE Plasma (personal)
Uptime~4 years in production environments
Shell/bin/bash
LocationPrague, Czech Republic — Relocating to Denmark, mid-2027
Statusstudying RHCSA → AZ-104

whoami

My path into IT wasn't a straight line. I trained in hospitality, spent a decade working service roles across Europe, and only moved into tech in 2018 — service desk work led to a systems administrator role at DHL IT Services in Prague, where I started on Windows and moved into the Linux team, which is where I've stayed. I'm currently formalizing that hands-on experience with the RHCSA certification, followed by Microsoft's AZ-104 to round out the Windows/cloud side.

This site is where I keep a running account of what I'm building toward, and a small public notebook of the fixes and configs I use often enough to want written down properly.

path

2001–2006
Hotel SchoolStudied hospitality management.
2006–2016
HORECA industryA decade in hospitality & service roles.
2016
Turin, ItalyRode a 125cc motorcycle there and worked in phone-based wine sales.
2017
Barcelona, SpainCustomer service, including card-blocking support (CardStop).
2018
Prague, Czech RepublicMoved into tech — service desk, Dutch-language support.
2021–now
DHL IT Services, PragueService desk → Windows sysadmin → Linux sysadmin (current).

experience

Systems Administrator — DHL IT Services, Prague2021 — Current
  • Administer and troubleshoot production RHEL servers, including account access, storage, networking, and service health
  • Manage storage infrastructure with LVM — volume expansion, swap configuration, and inode/capacity troubleshooting
  • Administer Veritas Cluster Server (VCS) service groups and Veritas Volume Replicator (VVR) replication health across clustered production systems
  • Manage user accounts, SSH key-based access, and sudo permissions across the Linux estate
  • Administer CUPS print services and resolve queue, driver, and connectivity issues for end users
  • Diagnose network and connectivity issues using firewalld, tcpdump, and DNS troubleshooting workflows
  • Monitor systemd services and investigate failures through journalctl and system logs
  • Write Bash automation for backups, housekeeping, and recurring maintenance tasks
  • Started in Windows systems administration before moving into the Linux team, where I've stayed since

currently

No fixed deadlines below on purpose — these are in-progress commitments, not promises.

In progress

RHCSA — Red Hat Certified System Administrator

Working through storage, networking, security, and automation fundamentals on RHEL, building toward the EX200 exam.

Finishing this week

AI Fluency

Started and wrapping up this certification within the week.

Planned next

AZ-104 — Microsoft Azure Administrator

Starting once RHCSA fundamentals are solid — identity, compute, storage, and networking on Azure, with a focus on Linux workloads in the cloud.

Ongoing

Relocating to Denmark

Preparing a move to Denmark in 2027 and building toward roles in Linux/hybrid systems administration there.

projects

Self-hosted homelab

Running on Docker: Immich for photo management, Radicale for CalDAV/CardDAV sync, and Vaultwarden as a self-hosted password manager — infrastructure I run and maintain myself, end to end.

error-404.cc/en

A public site I built with lessons on staying safer online, written for a general, non-technical audience.

field notes

Practical write-ups from day-to-day RHEL administration — the kind of thing worth having in one place instead of re-Googling every time.

Access & Identity

Creating a user with SSH key access access

Use when: onboarding a new account that needs password-less login

useradd -m -s /bin/bash USERNAME
chage -d 0 USERNAME                    # force password reset on first login

# on the server, for the user's public key:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

Gotcha: wrong permissions on .ssh or authorized_keys is the single most common reason key auth silently fails — always check permissions before assuming the key itself is wrong.

Checking and locking sudo/account access access

Use when: verifying what a user can do, or shutting off access without deleting the account

sudo -l
passwd -S USERNAME
usermod -L USERNAME
visudo -f /etc/sudoers.d/USERNAME

Gotcha: always edit sudo rules through visudo, never a normal editor — it validates syntax before saving, so you can't lock yourself out with a typo.

ed25519 vs RSA — the FIPS gotcha access

Use when: generating a new SSH key pair

ssh-keygen -t ed25519

# RHEL system running in FIPS mode:
ssh-keygen -t rsa -b 4096

Gotcha: ed25519 keys are rejected outright on RHEL boxes running in FIPS mode. Check FIPS status before generating the key, not after a confusing auth failure.

SSH config shortcuts & copying keys access

Use when: you manage several servers and don't want to type full ssh -i ... commands each time

# ~/.ssh/config
Host server01
    HostName server01.example.com
    User USERNAME
    IdentityFile ~/.ssh/server01_ed25519

ssh server01

ssh-copy-id -i ~/.ssh/server01_ed25519.pub USERNAME@SERVER_NAME

Note: ssh-copy-id is the fast path, but only works while password auth is still enabled — once it's locked down you're back to manually placing the key in authorized_keys.

Checking sshd security settings access

Use when: auditing or troubleshooting what a server actually allows for SSH login

grep -Ei "PasswordAuthentication|PubkeyAuthentication|PermitRootLogin|AllowUsers|AllowGroups" \
  /etc/ssh/sshd_config /etc/ssh/sshd_config.d/* 2>/dev/null

sshd -t

Gotcha: always run sshd -t before restarting sshd on a remote box, and keep a second session open — a bad config on restart can lock you out entirely.

Printing (CUPS)

Adding a network printer with CUPS printing

Use when: setting up a new network printer queue

lpadmin -p OfficePrinter -E -v ipp://192.168.1.50/ipp/print -m everywhere
lpstat -p
lpadmin -d OfficePrinter

Note: driverless IPP Everywhere is the preferred modern method — no vendor driver needed. Fall back to a PPD-based AppSocket queue (socket://IP:9100) only when the printer specifically requires it.

Troubleshooting a driverless printer printing

Use when: jobs show as processing but nothing prints

lpstat -t
tail -f /var/log/cups/error_log

Gotcha: most driverless failures trace back to the wrong PPD being assigned, or the printer dropping off mDNS — restarting cups-browsed often clears the second case.

Managing a stuck print queue printing

Use when: a queue needs pausing, or a job is stuck

cupsdisable PRINTER
cupsreject PRINTER
cancel JOB_ID
cancel -a PRINTER

Gotcha: cancel -a clears everything queued — confirm nobody else is waiting on a pending job first.

Changing printer settings (tray, paper size, duplex) printing

Use when: the default tray, paper size, or duplex mode needs changing for a queue

lpoptions -p PRINTER -l
lpadmin -p PRINTER -o InputSlot=Tray1
lpadmin -p PRINTER -o PageSize=A4
lpadmin -p PRINTER -o Duplex=DuplexNoTumble

Note: to change settings for a single print job without touching the default, use lp -d PRINTER -o PageSize=A4 file.pdf instead of lpadmin.

Checking printer network connectivity printing

Use when: a network printer is unreachable or won't accept a connection

ping -c 4 PRINTER_IP
nc -vz PRINTER_IP 631
nc -vz PRINTER_IP 9100

Note: 631 is IPP, 9100 is raw AppSocket/JetDirect, 515 is old-style LPD — knowing which port responds narrows down whether it's a network issue or a queue configuration issue.

Storage & Filesystems

Extending an LVM logical volume storage

Use when: a filesystem is full and the volume group has free space

vgs
lvextend -r -L +10G /dev/VG_NAME/LV_NAME

Note: the -r flag grows the filesystem automatically in the same step (XFS via xfs_growfs, ext4 via resize2fs). XFS can be grown online but never shrunk — size volumes with that in mind.

Adding a new disk into an existing VG storage

Use when: a new disk was attached and needs to join existing storage

lsblk
pvcreate /dev/sdb1
vgextend VG_NAME /dev/sdb1
lvextend -l +100%FREE /dev/VG_NAME/LV_NAME

Gotcha: misidentifying the disk in step one is the riskiest part of this entire workflow — double-check before running pvcreate on anything.

Expanding swap with a swap file storage

Use when: a system needs more swap without touching LVM

fallocate -l 4G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
# then add to /etc/fstab:
/swapfile none swap sw 0 0

Note: swap masks memory pressure, it doesn't fix a leak. If usage keeps climbing, check journalctl -k | grep -i "out of memory" for the real cause.

Diagnosing "no space left" with free disk space storage

Use when: df -h shows free space but writes still fail

df -i
find /path -xdev -type f | sed 's#/[^/]*$##' | sort | uniq -c | sort -n | tail

Gotcha: a filesystem with millions of tiny files can exhaust its inode table long before running out of actual space. Always list candidates with find ... -mtime +N -ls before adding -delete.

Mounting safely and reading /etc/fstab storage

Use when: testing fstab changes, or a mount won't release

mount -a
fuser -vm /mount/point

Note: a bad fstab entry found via mount -a today is far better than the same entry found during a 3am reboot.

Growing a disk that was resized at the hypervisor/SAN level storage

Use when: a virtual disk or SAN LUN was expanded, but Linux still sees the old size

echo 1 | tee /sys/class/block/sdb/device/rescan
lsblk
growpart /dev/sdb 1
pvresize /dev/sdb1

Note: this is different from adding a brand-new disk — here the same disk got bigger, so the OS needs a rescan before pvresize will see the extra space at all.

Networking & Diagnostics

Setting a static IP with nmcli networking

Use when: assigning a fixed IP to a server

nmcli con mod "Wired connection 1" \
  ipv4.addresses 192.168.1.20/24 \
  ipv4.gateway 192.168.1.1 \
  ipv4.dns 1.1.1.1 \
  ipv4.method manual

nmcli con up "Wired connection 1"

Gotcha: confirm with nmcli con show before bringing a connection down on a box you're remoted into — it's an easy way to lock yourself out.

Opening a port through firewalld networking

Use when: a service needs a port opened, permanently

firewall-cmd --add-port=8080/tcp --permanent
firewall-cmd --reload

Gotcha: forgetting --reload is the most common reason a "fixed" firewall rule doesn't actually take effect. Without --permanent, the rule vanishes on the next reload/reboot too.

DNS troubleshooting flow networking

Use when: a hostname won't resolve but you're not sure if it's DNS, hosts file, or network

ping -c 4 8.8.8.8
ping -c 4 example.com
cat /etc/resolv.conf
dig example.com
dig @8.8.8.8 example.com
cat /etc/hosts

Note: if ping-by-IP works but ping-by-name fails, the problem is DNS, not the network — that one comparison saves a lot of wrong-direction troubleshooting.

Finding what's listening on a port networking

Use when: a service should be listening but a client can't connect

ss -tulpn | grep :PORT
lsof -i :PORT

Note: confirms the service is actually bound to the port before spending time on firewall rules or network paths that were never the problem.

Capturing traffic with tcpdump networking

Use when: a connection is failing and you need to see the actual packets

tcpdump -nn -i INTERFACE host HOST_IP and port PORT

tcpdump -nn -s 0 -i INTERFACE host HOST_IP and port PORT -w /tmp/capture.pcap

tcpdump -nn -s 0 -i INTERFACE -G 60 -W 5 -w /tmp/capture-%Y%m%d-%H%M%S.pcap

Reading it: repeated SYN with no SYN-ACK back means nothing's answering. A returned RST means something's actively rejecting the connection — two different problems that look the same from the client side.

Services & System Health

Managing services with systemd services

Use when: a service needs checking, restarting, or its logs reviewed

systemctl status SERVICE
journalctl -u SERVICE -n 100
systemctl restart SERVICE
systemctl status SERVICE

Note: prefer reload over restart when a service supports it — it reapplies config without a hard stop/start, which matters more than it sounds on anything user-facing.

Investigating logs with journalctl services

Use when: something broke and you don't yet know what

journalctl -xe
journalctl -p err -b
journalctl -u SERVICE --since "1 hour ago"

Note: -xe is almost always the right first move — it adds explanations to cryptic entries, not just raw log lines.

Zombie processes — what actually needs fixing services

Use when: ps shows processes marked Z / defunct

ps -eo stat,pid,ppid,cmd | grep -w Z
ps -fp PARENT_PID

Gotcha: a zombie is already dead — you fix the parent, not the zombie. One or two is usually nothing; a steadily growing count means the parent isn't reaping its children, which is an application bug, not something memory tuning fixes.

First-check command set for "something's wrong" services

Use when: you don't know what's broken yet

hostnamectl
uptime
df -h
free -h
systemctl --failed
ip a
journalctl -xe

Note: covers identity, load, disk, memory, failed units, and network in one pass — narrows down which of the "big five" is actually the problem before going deeper into any one of them.

Package management basics services

Use when: checking what's installed, or which package owns a file

dnf info PACKAGE_NAME
rpm -qa | grep PACKAGE_NAME
rpm -qf /path/to/file

Note: rpm -qf is underused — genuinely handy when you find an unfamiliar binary or config file and need to know what put it there.

Scripting & Automation

Safe Bash script starting template scripting

Use when: starting any new script, before adding real logic

#!/bin/bash
set -euo pipefail

echo "Starting script..."
# commands here
echo "Done."

Note: set -e exits on any failed command, -u errors on undefined variables, -o pipefail catches failures inside a pipe — without these three, a script can silently continue past a failure and do real damage downstream.

Backup script template with retention scripting

Use when: scripting a simple tar-based backup with automatic cleanup

#!/bin/bash
set -euo pipefail

DATE=$(date +"%Y-%m-%d_%H-%M-%S")
BACKUP_DIR="/path/to/backups"
SOURCE_DIR="/path/to/source"
RETENTION_DAYS=14

mkdir -p "$BACKUP_DIR"
tar -czf "$BACKUP_DIR/backup-$DATE.tar.gz" -C "$SOURCE_DIR" .
find "$BACKUP_DIR" -type f -name "backup-*.tar.gz" -mtime +"$RETENTION_DAYS" -delete

Note: the retention cleanup line is the part people forget to add until disk usage becomes a problem — build it in from the start, not after the fact.

Cron basics scripting

Use when: scheduling a recurring script

crontab -e
crontab -l

0 2 * * * /path/to/script.sh >> /path/to/script.log 2>&1

# 0 2 * * *    = every day at 02:00
# */5 * * * *  = every 5 minutes
# 0 8 * * 1    = every Monday at 08:00

Note: always redirect output (>> log 2>&1) — a cron job that fails silently with no log is one of the most annoying things to debug later.

Docker Compose day-to-day commands scripting

Use when: managing containerized services defined in a compose file

docker compose up -d
docker compose down
docker compose logs -f
docker compose pull && docker compose up -d
docker compose restart SERVICE_NAME

Note: pull then up -d is the safe update pattern — it fetches new images first and only recreates containers once they're actually available.

rsync for copies and backups scripting

Use when: copying files locally or to a remote host, especially repeatedly

rsync -avh --progress SOURCE/ DESTINATION/
rsync -avh -e ssh SOURCE/ USERNAME@SERVER:/DESTINATION/
rsync -avh --dry-run SOURCE/ DESTINATION/

Gotcha: a trailing slash on the source means "copy the contents," no trailing slash means "copy the folder itself" — easy to get backwards and end up with an extra nested directory. Always --dry-run first on anything you didn't write yourself.

Maintenance & Security

SELinux — the first three commands maintenance

Use when: something is denied for no obvious permission reason

getenforce
grep denied /var/log/audit/audit.log | tail
restorecon -Rv /path/to/fix

Gotcha: never leave a system in setenforce 0 (permissive) to "fix" a problem — that disables the protection instead of fixing the actual context. Find the denial, then restorecon or semanage fcontext the correct label in.

Log rotation with logrotate maintenance

Use when: a service's logs are growing unbounded and there's no built-in rotation

cat /etc/logrotate.d/SERVICE_NAME
logrotate -d /etc/logrotate.d/SERVICE_NAME
logrotate -f /etc/logrotate.conf

Note: most packaged services already ship a logrotate config — check before writing one from scratch. This is usually the actual fix for "disk filling up with logs," not manual deletion.

Time sync with chrony maintenance

Use when: clock drift is suspected — auth failures, cluster weirdness, cert errors

chronyc tracking
chronyc sources -v
timedatectl

Note: clock drift is an underrated cause of weird failures — Kerberos/SSO auth and cluster heartbeats are especially sensitive to it, and the symptoms rarely look time-related at first glance.

Patching safely with dnf maintenance

Use when: applying updates, especially on anything production

dnf check-update
dnf update --setopt=install_weak_deps=False PACKAGE_NAME
needs-restarting -r

Gotcha: a blanket dnf update on production without checking what's included first is how unrelated things break. Patch narrowly when possible, and always check needs-restarting afterward — a patched-but-not-rebooted kernel is still running the old, vulnerable one.

Checking disk health before it fails maintenance

Use when: proactively checking a physical disk, or investigating unexplained I/O errors

smartctl -a /dev/sda
smartctl -H /dev/sda
dmesg -T | grep -Ei "ata|scsi|i/o error"

Note: SMART isn't infallible, but a failing "reallocated sector count" trending upward is one of the most reliable early-warning signs of a dying disk — worth checking before it becomes an outage.

Terminal Workflow

tmux for sessions that survive disconnects terminal

Use when: running something long, or working over an unreliable connection

tmux new -s work
# Ctrl+b, then d
tmux attach -t work
tmux ls

Note: the habit worth building is starting anything long-running (a migration, a big rsync, a patch job) inside tmux by default — a dropped SSH connection no longer means starting over.

vim — just enough to survive terminal

Use when: editing a config file on a server with no other editor available

i
Esc
:wq
:q!
/searchterm

Gotcha: :q! exists for a reason — if you're not sure what state the file is in, that's the safe exit, not closing the terminal window and hoping.

Enterprise Clustering (Veritas)

Reading Veritas cluster health cluster

Use when: checking overall cluster and service group status

hastatus -sum
hagrp -display SERVICE_GROUP

Note: check whether a group is frozen (automatic actions blocked) before assuming a fault needs manual intervention.

Expanding Veritas-managed storage cluster

Use when: growing storage that's under Veritas, not plain LVM

vxdg list
vxprint -g DISK_GROUP -ht
vxassist -g DISK_GROUP growby VOLUME_NAME SIZE
# then grow the filesystem: xfs_growfs or resize2fs, matching the fs type

Gotcha: this is deliberately not a copy-paste recipe. Running plain OS LVM commands against Veritas-managed disks by mistake is one of the most common ways this goes wrong.

VVR replication status & RLINK in DCM mode cluster

Use when: checking replication health, or investigating a DCM mode alert

vradmin -g DISK_GROUP repstatus RVG_NAME
# healthy output shows:
#   Data status: consistent, up-to-date
#   Replication status: replicating (connected)

# if vradmin can't connect:
service vras-vradmind status

Note: a failed VRAS daemon alongside a healthy vvr_stats is a known, restartable state — not a full outage.

— curated from my own working notes; sanitized of hostnames, IPs, and anything environment-specific —

contact

LocationPrague, CZ — moving to Denmark, 2027