New Server Baseline Checklist
Every new server requires a standardized set of configurations before it is ready for production. Missing any step can introduce security vulnerabilities or operational headaches down the road. This article provides a battle-tested baseline checklist applicable to CentOS Stream 9 & 10, AlmaLinux 9 & 10, and Rocky Linux 9 & 10.
Prerequisites
Section titled “Prerequisites”- Operating system installed with a minimal profile
- Root access or an account with sudo privileges
- Network connectivity with access to dnf repositories
Step 1: Set the Hostname
Section titled “Step 1: Set the Hostname”Use a meaningful naming convention such as purpose-env-number, e.g., web-prod-01.
# Set hostnamehostnamectl set-hostname web-prod-01
# VerifyhostnamectlAlso update /etc/hosts for local resolution:
echo "127.0.0.1 web-prod-01" >> /etc/hostsStep 2: Configure Timezone
Section titled “Step 2: Configure Timezone”Set a timezone that matches your operational region:
# Check current timezonetimedatectl
# Set timezone (example: US Eastern)timedatectl set-timezone America/New_York
# VerifydateStep 3: Configure NTP Time Synchronization
Section titled “Step 3: Configure NTP Time Synchronization”EL 9 uses chrony as the default NTP client:
# Ensure chrony is installeddnf install -y chrony
# Edit configuration (optional: replace with internal or preferred NTP sources)vi /etc/chrony.confExample NTP server configuration:
# Public NTP poolsserver 0.pool.ntp.org iburstserver 1.pool.ntp.org iburstserver time.cloudflare.com iburstStart and enable the service:
systemctl enable --now chronyd
# Verify synchronizationchronyc trackingchronyc sources -vStep 4: Full System Update
Section titled “Step 4: Full System Update”Always update the system before going live:
dnf update -y
# Check if a reboot is required (e.g., after kernel updates)needs-restarting -rIf a reboot is needed, defer it until all baseline steps are complete.
Step 5: Create an Admin User
Section titled “Step 5: Create an Admin User”Never use root directly in production. Create a dedicated admin account:
# Create useruseradd -m -s /bin/bash admin
# Set passwordpasswd admin
# Add to wheel group for sudo privilegesusermod -aG wheel adminVerify sudo configuration:
# Confirm wheel group has sudo accessgrep '%wheel' /etc/sudoers# Expected output: %wheel ALL=(ALL) ALLStep 6: SSH Hardening
Section titled “Step 6: SSH Hardening”SSH is one of the primary attack surfaces on any server.
6.1 Deploy Key-Based Authentication
Section titled “6.1 Deploy Key-Based Authentication”On your local client, generate a key pair (if you don’t have one):
ssh-keygen -t ed25519 -C "admin@web-prod-01"Copy the public key to the server:
ssh-copy-id admin@SERVER_IP6.2 Harden the SSH Configuration
Section titled “6.2 Harden the SSH Configuration”Edit /etc/ssh/sshd_config.d/99-hardening.conf (EL 9 supports drop-in configuration files):
cat > /etc/ssh/sshd_config.d/99-hardening.conf << 'EOF'# Disable root loginPermitRootLogin no
# Disable password authentication (ensure key auth works first)PasswordAuthentication no
# Disallow empty passwordsPermitEmptyPasswords no
# Limit authentication attemptsMaxAuthTries 3
# Limit concurrent unauthenticated connectionsMaxStartups 10:30:60
# Set login timeoutLoginGraceTime 30
# Only allow specific usersAllowUsers adminEOFRestart SSH:
systemctl restart sshdStep 7: Firewall Baseline
Section titled “Step 7: Firewall Baseline”EL 9 uses firewalld by default:
# Ensure firewalld is runningsystemctl enable --now firewalld
# View current rulesfirewall-cmd --list-all
# Ensure SSH is allowed (enabled by default)firewall-cmd --permanent --zone=public --add-service=ssh
# Remove unnecessary servicesfirewall-cmd --permanent --zone=public --remove-service=cockpitfirewall-cmd --permanent --zone=public --remove-service=dhcpv6-client
# Reloadfirewall-cmd --reload
# Verify final rulesfirewall-cmd --list-allOpen additional ports as needed later:
# Example: allow HTTP/HTTPSfirewall-cmd --permanent --add-service=httpfirewall-cmd --permanent --add-service=httpsfirewall-cmd --reloadStep 8: Verify SELinux Status
Section titled “Step 8: Verify SELinux Status”SELinux is a critical security layer on EL systems. Do not disable it.
# Check statusgetenforce# Expected output: Enforcing
sestatusIf the status is Disabled or Permissive, enable it:
# Edit configurationsed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
# If switching from Disabled, trigger filesystem relabel on next boottouch /.autorelabelInstall SELinux management tools:
dnf install -y policycoreutils-python-utils setools-consoleStep 9: Install Essential Tools
Section titled “Step 9: Install Essential Tools”Install commonly used administration tools:
dnf install -y \ vim \ tmux \ htop \ iotop \ lsof \ strace \ tcpdump \ net-tools \ bind-utils \ wget \ curl \ tar \ unzip \ bash-completion \ man-pages \ yum-utilsOptional advanced diagnostic tools:
dnf install -y \ sysstat \ perf \ bpftool \ nmap-ncatStep 10: Set Up Monitoring Agent
Section titled “Step 10: Set Up Monitoring Agent”Using node_exporter (Prometheus ecosystem) as an example:
# Create a system useruseradd --no-create-home --shell /sbin/nologin node_exporter
# Download and install (replace with the latest version)cd /tmpcurl -LO https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gztar xzf node_exporter-1.8.2.linux-amd64.tar.gzcp node_exporter-1.8.2.linux-amd64/node_exporter /usr/local/bin/
# Create systemd servicecat > /etc/systemd/system/node_exporter.service << 'EOF'[Unit]Description=Prometheus Node ExporterAfter=network-online.targetWants=network-online.target
[Service]Type=simpleUser=node_exporterExecStart=/usr/local/bin/node_exporterRestart=on-failureRestartSec=5
[Install]WantedBy=multi-user.targetEOF
systemctl daemon-reloadsystemctl enable --now node_exporterOpen the monitoring port only for the monitoring server:
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.100/32" port protocol="tcp" port="9100" accept'firewall-cmd --reloadStep 11: Set Up Backup Agent
Section titled “Step 11: Set Up Backup Agent”Using borgbackup as an example:
dnf install -y epel-releasednf install -y borgbackup
# Initialize backup repository (local or remote)borg init --encryption=repokey /backup/borg-repo
# Create a basic backup scriptcat > /usr/local/bin/backup.sh << 'SCRIPT'#!/bin/bashREPO="/backup/borg-repo"TIMESTAMP=$(date +%Y-%m-%d_%H%M)
borg create --stats --compression zstd \ "${REPO}::${TIMESTAMP}" \ /etc \ /home \ /var/log \ --exclude '*.cache'
# Retention policy: 7 daily + 4 weekly + 6 monthlyborg prune --keep-daily=7 --keep-weekly=4 --keep-monthly=6 "$REPO"SCRIPT
chmod +x /usr/local/bin/backup.shSchedule automatic execution:
# Run backup daily at 2:00 AMcat > /etc/cron.d/backup << 'EOF'0 2 * * * root /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1EOFStep 12: Configure Log Rotation
Section titled “Step 12: Configure Log Rotation”Ensure logrotate is installed and functioning:
# Usually pre-installeddnf install -y logrotate
# Review default configurationcat /etc/logrotate.confAdd rotation rules for custom application logs:
cat > /etc/logrotate.d/app-logs << 'EOF'/var/log/app/*.log { daily missingok rotate 30 compress delaycompress notifempty create 0640 root root sharedscripts postrotate /bin/systemctl reload rsyslog > /dev/null 2>&1 || true endscript}EOFTest the rotation configuration:
logrotate -d /etc/logrotate.d/app-logsStep 13: Reboot and Verify
Section titled “Step 13: Reboot and Verify”After all configurations are complete, perform a full reboot test:
# Record current state before rebootuptimesystemctl list-units --failed
# RebootrebootAfter reboot, verify each item:
# 1. Hostnamehostname
# 2. Timezone and time synctimedatectlchronyc tracking
# 3. SELinuxgetenforce
# 4. Firewallfirewall-cmd --list-all
# 5. SSH servicesystemctl status sshd
# 6. Monitoring agentsystemctl status node_exporter
# 7. No failed servicessystemctl list-units --failed
# 8. Disk and memorydf -hfree -hQuick Reference Checklist
Section titled “Quick Reference Checklist”| # | Check Item | Command / Verification | Expected Result |
|---|---|---|---|
| 1 | Hostname | hostname | Meaningful name |
| 2 | Timezone | timedatectl | Correct timezone |
| 3 | NTP | chronyc tracking | Synchronized |
| 4 | System updates | dnf check-update | No available updates |
| 5 | Admin user | id admin | Exists, in wheel group |
| 6 | SSH hardening | sshd -T | grep permitrootlogin | no |
| 7 | Firewall | firewall-cmd --list-all | Only necessary ports open |
| 8 | SELinux | getenforce | Enforcing |
| 9 | Essential tools | which vim htop tmux | All installed |
| 10 | Monitoring | systemctl status node_exporter | active (running) |
| 11 | Backup | ls /backup/borg-repo | Repository initialized |
| 12 | Log rotation | logrotate -d /etc/logrotate.conf | No errors |
| 13 | Reboot test | systemctl list-units --failed | 0 failed |
Next Steps
Section titled “Next Steps”After completing the baseline, continue based on the server’s role:
- Web server - See Nginx Application Deployment Guide
- Database server - See PostgreSQL or Redis guides
- Backup verification - See Backup & Recovery Drill
- SSL certificates - See SSL Certificate Management