← Back to DevBytes

Securing CentOS Servers: A Practical Checklist

Introduction to Securing CentOS Servers

CentOS (Community Enterprise Operating System) has long been a favorite among system administrators for building production servers. Whether you are running CentOS 7, CentOS 8, or one of its successors like AlmaLinux and Rocky Linux, the underlying RHEL-based architecture means the security principles remain largely the same. However, a fresh CentOS installation is not secure by default — it is configured for usability, not for production hardening. This tutorial walks you through a practical, actionable checklist to lock down a CentOS server from the moment you gain SSH access.

What Is Server Hardening?

Server hardening is the process of reducing a system's attack surface by removing unnecessary software, disabling unused services, enforcing strict access controls, applying patches, and configuring defensive tools such as firewalls and intrusion detection systems. The goal is not to make the server impenetrable — no system is — but to make it significantly harder and less attractive for attackers to compromise.

Why It Matters

Every minute, thousands of automated bots scan the internet for vulnerable servers. Default SSH ports, weak passwords, outdated packages, and open ports are low-hanging fruit that attackers exploit within hours of a server going online. A single compromised server can become part of a botnet, leak sensitive customer data, or serve as a pivot point into your broader infrastructure. Hardening your CentOS server is therefore not optional — it is the baseline of responsible operations.

1. Initial System Updates and Package Management

The very first action after provisioning a CentOS server should be updating all installed packages to their latest stable versions. This patches known CVEs and ensures you are running software with the latest security fixes.

# Update all packages
sudo yum update -y

# On CentOS 8 / RHEL 8+ based systems
sudo dnf update -y

# Enable automatic security updates (CentOS 8+)
sudo dnf install -y dnf-automatic
sudo systemctl enable --now dnf-automatic.timer

After updating, remove unnecessary packages that may introduce vulnerabilities:

# Remove unused packages and clean cache
sudo yum autoremove -y
sudo yum clean all

# List installed packages for audit
rpm -qa | sort > installed_packages.txt

Best Practices for Package Management

2. Securing SSH Access

SSH is the primary entry point to your server, and it is also the most attacked service. Hardening SSH is one of the highest-impact changes you can make.

2.1 Disable Root Login and Password Authentication

Edit the SSH daemon configuration file at /etc/ssh/sshd_config:

# Disable direct root login
PermitRootLogin no

# Disable password authentication
PasswordAuthentication no

# Disable empty passwords
PermitEmptyPasswords no

# Limit authentication attempts
MaxAuthTries 3

# Disable X11 forwarding if not needed
X11Forwarding no

# Set a login grace period
LoginGraceTime 30

# Allow only specific users
AllowUsers deployuser

Before restarting SSH, ensure you have set up SSH key-based authentication:

# On your local machine, generate a key pair
ssh-keygen -t ed25519 -C "admin@yourdomain.com"

# Copy the public key to the server
ssh-copy-id deployuser@your-server-ip

# Restart SSH after verifying key login works
sudo systemctl restart sshd

2.2 Change the Default SSH Port

Changing the SSH port from 22 to a non-standard port reduces automated brute-force noise significantly. Edit /etc/ssh/sshd_config:

Port 2222

Update the firewall before restarting SSH:

sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload
sudo systemctl restart sshd

2.3 Use Fail2Ban to Block Brute-Force Attacks

Fail2Ban monitors log files and bans IPs that show malicious signs. Install it via EPEL:

sudo yum install -y epel-release
sudo yum install -y fail2ban

# Create a local configuration
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo vi /etc/fail2ban/jail.local

Add a jail for SSH:

[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/secure
maxretry = 3
bantime = 3600
findtime = 600
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

3. User Management and Privilege Escalation

Never run services or perform daily tasks as the root user. Create dedicated accounts with limited privileges and grant sudo access only where necessary.

# Create a new user with sudo privileges
sudo adduser deployuser
sudo passwd deployuser

# Add to the wheel group (sudoers)
sudo usermod -aG wheel deployuser

# Lock the root password (optional but recommended)
sudo passwd -l root

3.1 Restrict Sudo Access

Edit the sudoers file safely using visudo:

sudo visudo

Configure granular permissions:

# Require password for sudo
Defaults timestamp_timeout=5

# Allow deployuser to restart nginx only
deployuser ALL=(ALL) /bin/systemctl restart nginx

# Log all sudo commands
Defaults logfile="/var/log/sudo.log"
Defaults log_input, log_output

3.2 Enforce Strong Password Policies

Configure password quality with PAM by editing /etc/security/pwquality.conf:

minlen = 12
minclass = 4
maxrepeat = 3
dcredit = -1
ucredit = -1
ocredit = -1
lcredit = -1

Set password aging policies in /etc/login.defs:

PASS_MAX_DAYS 90
PASS_MIN_DAYS 7
PASS_MIN_LEN 12
PASS_WARN_AGE 7

4. Configuring the Firewall

CentOS uses firewalld as the default firewall management tool. A properly configured firewall is your first line of network defense.

# Verify firewalld is running
sudo systemctl status firewalld

# Enable and start firewalld
sudo systemctl enable --now firewalld

# List current rules
sudo firewall-cmd --list-all

4.1 Define Zones and Services

# Set default zone to public
sudo firewall-cmd --set-default-zone=public

# Allow only essential services
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https

# Remove unwanted services
sudo firewall-cmd --permanent --remove-service=dhcpv6-client

# Reload to apply changes
sudo firewall-cmd --reload

4.2 Rate-Limit SSH Connections

Protect against brute-force attacks by limiting connection rates:

sudo firewall-cmd --permanent --add-rich-rule='rule service name="ssh" limit value="3/m" accept'
sudo firewall-cmd --reload

Best Practices for Firewall Configuration

5. SELinux Configuration

SELinux (Security-Enhanced Linux) is a mandatory access control system built into CentOS. Many administrators disable it because it can be difficult to troubleshoot, but disabling SELinux removes a critical layer of protection.

# Check SELinux status
sudo sestatus

# Check current mode
getenforce

# Set to enforcing mode permanently
sudo vi /etc/selinux/config

Set the configuration:

SELINUX=enforcing
SELINUXTYPE=targeted
# Apply changes (requires reboot)
sudo reboot

# Temporarily set mode without reboot
sudo setenforce 1

5.1 Troubleshooting SELinux Denials

# Install troubleshooting tools
sudo yum install -y setroubleshoot setools

# View SELinux denials
sudo sealert -a /var/log/audit/audit.log

# List SELinux contexts of files
ls -Z /var/www/html

# Restore default contexts
sudo restorecon -Rv /var/www/html

If a service requires a specific policy, use audit2allow to generate a custom module rather than disabling SELinux entirely:

sudo grep httpd /var/log/audit/audit.log | audit2allow -M myhttpdpolicy
sudo semodule -i myhttpdpolicy.pp

6. Securing Network Parameters with Sysctl

The Linux kernel exposes many network parameters that can be tuned to mitigate common attacks such as SYN floods, IP spoofing, and man-in-the-middle attacks.

Create a custom sysctl configuration file:

sudo vi /etc/sysctl.d/99-security.conf

Add the following hardening parameters:

# Ignore ICMP echo requests (ping)
net.ipv4.icmp_echo_ignore_all = 1

# Enable SYN cookies
net.ipv4.tcp_syncookies = 1

# Disable IP forwarding
net.ipv4.ip_forward = 0

# Disable source packet routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0

# Enable reverse path filtering
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Log martian packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

# Disable IPv6 if not used
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
# Apply the new settings
sudo sysctl --system

# Verify changes
sudo sysctl -a | grep syncookies

7. Disabling Unused Services

Every running service is a potential attack vector. Audit your system and disable anything that is not required for your workload.

# List all enabled services
sudo systemctl list-unit-files --type=service --state=enabled

# Disable common unnecessary services
sudo systemctl disable --now avahi-daemon
sudo systemctl disable --now cups
sudo systemctl disable --now bluetooth
sudo systemctl disable --now nfs-server
sudo systemctl disable --now rpcbind

# List all listening ports
sudo ss -tulpn

Review the output of ss -tulpn carefully. If you see a service listening on a port you do not recognize, investigate it immediately and disable it if it is not needed.

8. File System and Kernel Hardening

8.1 Secure /tmp and /var/tmp

The /tmp directory is world-writable and a common target for attackers to store scripts. Mount it with noexec, nosuid, and nodev options:

# Create a tmpfs mount for /tmp
sudo vi /etc/fstab

Add the following line:

tmpfs /tmp tmpfs defaults,noexec,nosuid,nodev 0 0
tmpfs /var/tmp tmpfs defaults,noexec,nosuid,nodev 0 0
sudo mount -o remount /tmp
sudo mount -o remount /var/tmp

8.2 Set Secure Permissions on Critical Files

# Restrict access to cron directories
sudo chmod 700 /etc/cron.d
sudo chmod 700 /etc/cron.daily
sudo chmod 700 /etc/cron.hourly
sudo chmod 700 /etc/cron.weekly
sudo chmod 700 /etc/cron.monthly

# Restrict SSH configuration
sudo chmod 600 /etc/ssh/sshd_config

# Restrict access to host files
sudo chattr +i /etc/passwd
sudo chattr +i /etc/shadow
sudo chattr +i /etc/group
sudo chattr +i /etc/gshadow

Note: Setting the immutable flag with chattr +i prevents even root from modifying these files without first removing the flag. This can break user management tools, so test carefully in your environment. To remove the flag, use chattr -i.

9. Intrusion Detection with AIDE

AIDE (Advanced Intrusion Detection Environment) creates a database of file checksums and permissions, then alerts you when files change unexpectedly. This helps detect unauthorized modifications.

sudo yum install -y aide

# Initialize the AIDE database
sudo aide --init

# Move the database to the production location
sudo mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz

# Run a manual check
sudo aide --check

Schedule regular AIDE checks via cron:

sudo crontab -e
0 3 * * * /usr/sbin/aide --check | mail -s "AIDE Report for $(hostname)" admin@yourdomain.com

10. Logging and Auditing

Centralized and tamper-resistant logging is essential for incident response. CentOS uses journald and rsyslog for logging, and auditd for security auditing.

10.1 Configure Auditd

sudo yum install -y audit
sudo systemctl enable --now auditd

Edit /etc/audit/auditd.conf to configure log retention and behavior:

max_log_file = 100
max_log_file_action = ROTATE
space_left = 50
space_left_action = EMAIL
admin_space_left = 20
admin_space_left_action = HALT

Add audit rules to monitor critical files:

sudo vi /etc/audit/rules.d/audit.rules
# Monitor changes to /etc/passwd
-w /etc/passwd -p wa -k identity

# Monitor changes to /etc/shadow
-w /etc/shadow -p wa -k identity

# Monitor sudoers changes
-w /etc/sudoers -p wa -k scope

# Monitor SSH configuration
-w /etc/ssh/sshd_config -p wa -k ssh_config

# Monitor login events
-w /var/log/lastlog -p wa -k logins
sudo systemctl restart auditd
sudo auditctl -l

10.2 Forward Logs to a Remote Server

Configure rsyslog to forward logs to a central logging server:

sudo vi /etc/rsyslog.conf
*.* @@logserver.yourdomain.com:514
sudo systemctl restart rsyslog

11. Time Synchronization

Accurate system time is critical for log correlation, certificate validation, and cron job execution. Configure chrony for time synchronization:

sudo yum install -y chrony
sudo systemctl enable --now chronyd

# Verify synchronization
chronyc sources
chronyc tracking

12. Additional Hardening Measures

12.1 Install and Configure ClamAV

For servers that handle file uploads or email, an antivirus scanner adds another layer of defense:

sudo yum install -y clamav clamav-update

# Update virus database
sudo freshclam

# Run a scan
sudo clamscan -r /home

# Schedule daily scans
echo "0 2 * * * /usr/bin/clamscan -r /home --quiet -l /var/log/clamav/daily.log" | sudo crontab -

12.2 Enable Process Accounting

sudo yum install -y psacct
sudo systemctl enable --now psacct

# View command history of users
sudo lastcomm

12.3 Secure the Bootloader

Set a GRUB password to prevent unauthorized boot parameter changes:

sudo grub2-setpassword

13. Creating a Hardening Script

To make this checklist repeatable across multiple servers, encapsulate the key steps into a bash script. Below is a starting point that you can extend:

#!/bin/bash
# centos-hardening.sh - Basic CentOS server hardening script

set -e

echo "=== Updating system packages ==="
yum update -y
yum autoremove -y

echo "=== Configuring SSH ==="
sed -i 's/^#PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^#MaxAuthTries.*/MaxAuthTries 3/' /etc/ssh/sshd_config
systemctl restart sshd

echo "=== Configuring firewall ==="
systemctl enable --now firewalld
firewall-cmd --permanent --add-service=ssh
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

echo "=== Applying sysctl hardening ==="
cat > /etc/sysctl.d/99-security.conf << 'EOF'
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.icmp_echo_ignore_all = 1
EOF
sysctl --system

echo "=== Enabling SELinux ==="
sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config

echo "=== Installing and enabling fail2ban ==="
yum install -y epel-release
yum install -y fail2ban
systemctl enable --now fail2ban

echo "=== Hardening complete. Reboot required for SELinux changes. ==="

Make the script executable and run it:

chmod +x centos-hardening.sh
sudo ./centos-hardening.sh

Best Practices Summary

Conclusion

Securing a CentOS server is not a one-time task but an ongoing discipline. The checklist above covers the foundational hardening steps — from system updates and SSH lockdown to firewall configuration, SELinux enforcement, kernel tuning, intrusion detection, and auditing. By systematically applying each control and continuously monitoring your systems, you dramatically reduce the risk of compromise and build a server environment that can withstand the relentless automated attacks that define today's internet. Remember that security is a process, not a destination: revisit this checklist regularly, stay informed about new vulnerabilities, and adapt your defenses as your infrastructure evolves.

— Ad —

Google AdSense will appear here after approval

← Back to all articles