Skip to content
Search RunEntLinux

Searches general documentation on RunEntLinux. Each distribution has its own documentation search.

    Browse this documentation

    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.

    • Operating system installed with a minimal profile
    • Root access or an account with sudo privileges
    • Network connectivity with access to dnf repositories

    Use a meaningful naming convention such as purpose-env-number, e.g., web-prod-01.

    Terminal window
    # Set hostname
    hostnamectl set-hostname web-prod-01
    # Verify
    hostnamectl

    Also update /etc/hosts for local resolution:

    Terminal window
    echo "127.0.0.1 web-prod-01" >> /etc/hosts

    Set a timezone that matches your operational region:

    Terminal window
    # Check current timezone
    timedatectl
    # Set timezone (example: US Eastern)
    timedatectl set-timezone America/New_York
    # Verify
    date

    Step 3: Configure NTP Time Synchronization

    Section titled “Step 3: Configure NTP Time Synchronization”

    EL 9 uses chrony as the default NTP client:

    Terminal window
    # Ensure chrony is installed
    dnf install -y chrony
    # Edit configuration (optional: replace with internal or preferred NTP sources)
    vi /etc/chrony.conf

    Example NTP server configuration:

    # Public NTP pools
    server 0.pool.ntp.org iburst
    server 1.pool.ntp.org iburst
    server time.cloudflare.com iburst

    Start and enable the service:

    Terminal window
    systemctl enable --now chronyd
    # Verify synchronization
    chronyc tracking
    chronyc sources -v

    Always update the system before going live:

    Terminal window
    dnf update -y
    # Check if a reboot is required (e.g., after kernel updates)
    needs-restarting -r

    If a reboot is needed, defer it until all baseline steps are complete.

    Never use root directly in production. Create a dedicated admin account:

    Terminal window
    # Create user
    useradd -m -s /bin/bash admin
    # Set password
    passwd admin
    # Add to wheel group for sudo privileges
    usermod -aG wheel admin

    Verify sudo configuration:

    Terminal window
    # Confirm wheel group has sudo access
    grep '%wheel' /etc/sudoers
    # Expected output: %wheel ALL=(ALL) ALL

    SSH is one of the primary attack surfaces on any server.

    On your local client, generate a key pair (if you don’t have one):

    Terminal window
    ssh-keygen -t ed25519 -C "admin@web-prod-01"

    Copy the public key to the server:

    Terminal window
    ssh-copy-id admin@SERVER_IP

    Edit /etc/ssh/sshd_config.d/99-hardening.conf (EL 9 supports drop-in configuration files):

    Terminal window
    cat > /etc/ssh/sshd_config.d/99-hardening.conf << 'EOF'
    # Disable root login
    PermitRootLogin no
    # Disable password authentication (ensure key auth works first)
    PasswordAuthentication no
    # Disallow empty passwords
    PermitEmptyPasswords no
    # Limit authentication attempts
    MaxAuthTries 3
    # Limit concurrent unauthenticated connections
    MaxStartups 10:30:60
    # Set login timeout
    LoginGraceTime 30
    # Only allow specific users
    AllowUsers admin
    EOF

    Restart SSH:

    Terminal window
    systemctl restart sshd

    EL 9 uses firewalld by default:

    Terminal window
    # Ensure firewalld is running
    systemctl enable --now firewalld
    # View current rules
    firewall-cmd --list-all
    # Ensure SSH is allowed (enabled by default)
    firewall-cmd --permanent --zone=public --add-service=ssh
    # Remove unnecessary services
    firewall-cmd --permanent --zone=public --remove-service=cockpit
    firewall-cmd --permanent --zone=public --remove-service=dhcpv6-client
    # Reload
    firewall-cmd --reload
    # Verify final rules
    firewall-cmd --list-all

    Open additional ports as needed later:

    Terminal window
    # Example: allow HTTP/HTTPS
    firewall-cmd --permanent --add-service=http
    firewall-cmd --permanent --add-service=https
    firewall-cmd --reload

    SELinux is a critical security layer on EL systems. Do not disable it.

    Terminal window
    # Check status
    getenforce
    # Expected output: Enforcing
    sestatus

    If the status is Disabled or Permissive, enable it:

    Terminal window
    # Edit configuration
    sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
    # If switching from Disabled, trigger filesystem relabel on next boot
    touch /.autorelabel

    Install SELinux management tools:

    Terminal window
    dnf install -y policycoreutils-python-utils setools-console

    Install commonly used administration tools:

    Terminal window
    dnf install -y \
    vim \
    tmux \
    htop \
    iotop \
    lsof \
    strace \
    tcpdump \
    net-tools \
    bind-utils \
    wget \
    curl \
    tar \
    unzip \
    bash-completion \
    man-pages \
    yum-utils

    Optional advanced diagnostic tools:

    Terminal window
    dnf install -y \
    sysstat \
    perf \
    bpftool \
    nmap-ncat

    Using node_exporter (Prometheus ecosystem) as an example:

    Terminal window
    # Create a system user
    useradd --no-create-home --shell /sbin/nologin node_exporter
    # Download and install (replace with the latest version)
    cd /tmp
    curl -LO https://github.com/prometheus/node_exporter/releases/download/v1.12.1/node_exporter-1.12.1.linux-amd64.tar.gz
    tar xzf node_exporter-1.12.1.linux-amd64.tar.gz
    cp node_exporter-1.12.1.linux-amd64/node_exporter /usr/local/bin/
    # Create systemd service
    cat > /etc/systemd/system/node_exporter.service << 'EOF'
    [Unit]
    Description=Prometheus Node Exporter
    After=network-online.target
    Wants=network-online.target
    [Service]
    Type=simple
    User=node_exporter
    ExecStart=/usr/local/bin/node_exporter
    Restart=on-failure
    RestartSec=5
    [Install]
    WantedBy=multi-user.target
    EOF
    systemctl daemon-reload
    systemctl enable --now node_exporter

    Open the monitoring port only for the monitoring server:

    Terminal window
    firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.100/32" port protocol="tcp" port="9100" accept'
    firewall-cmd --reload

    Using borgbackup as an example:

    Terminal window
    dnf install -y epel-release
    dnf install -y borgbackup
    # Initialize backup repository (local or remote)
    borg init --encryption=repokey /backup/borg-repo
    # Create a basic backup script
    cat > /usr/local/bin/backup.sh << 'SCRIPT'
    #!/bin/bash
    REPO="/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 monthly
    borg prune --keep-daily=7 --keep-weekly=4 --keep-monthly=6 "$REPO"
    SCRIPT
    chmod +x /usr/local/bin/backup.sh

    Schedule automatic execution:

    Terminal window
    # Run backup daily at 2:00 AM
    cat > /etc/cron.d/backup << 'EOF'
    0 2 * * * root /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
    EOF

    Ensure logrotate is installed and functioning:

    Terminal window
    # Usually pre-installed
    dnf install -y logrotate
    # Review default configuration
    cat /etc/logrotate.conf

    Add rotation rules for custom application logs:

    Terminal window
    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
    }
    EOF

    Test the rotation configuration:

    Terminal window
    logrotate -d /etc/logrotate.d/app-logs

    After all configurations are complete, perform a full reboot test:

    Terminal window
    # Record current state before reboot
    uptime
    systemctl list-units --failed
    # Reboot
    reboot

    After reboot, verify each item:

    Terminal window
    # 1. Hostname
    hostname
    # 2. Timezone and time sync
    timedatectl
    chronyc tracking
    # 3. SELinux
    getenforce
    # 4. Firewall
    firewall-cmd --list-all
    # 5. SSH service
    systemctl status sshd
    # 6. Monitoring agent
    systemctl status node_exporter
    # 7. No failed services
    systemctl list-units --failed
    # 8. Disk and memory
    df -h
    free -h
    #Check ItemCommand / VerificationExpected Result
    1HostnamehostnameMeaningful name
    2TimezonetimedatectlCorrect timezone
    3NTPchronyc trackingSynchronized
    4System updatesdnf check-updateNo available updates
    5Admin userid adminExists, in wheel group
    6SSH hardeningsshd -T | grep permitrootloginno
    7Firewallfirewall-cmd --list-allOnly necessary ports open
    8SELinuxgetenforceEnforcing
    9Essential toolswhich vim htop tmuxAll installed
    10Monitoringsystemctl status node_exporteractive (running)
    11Backupls /backup/borg-repoRepository initialized
    12Log rotationlogrotate -d /etc/logrotate.confNo errors
    13Reboot testsystemctl list-units --failed0 failed

    After completing the baseline, continue based on the server’s role: