<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ricardo Loureiro</title>
    <description>The latest articles on DEV Community by Ricardo Loureiro (@sysbalance).</description>
    <link>https://dev.to/sysbalance</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3981209%2F19abbf37-a30a-4139-b330-fb54c4a0c0c8.jpg</url>
      <title>DEV Community: Ricardo Loureiro</title>
      <link>https://dev.to/sysbalance</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sysbalance"/>
    <language>en</language>
    <item>
      <title>I Audited a Production WHM/cPanel Server. Here's What I Found (and How to Check Yours)</title>
      <dc:creator>Ricardo Loureiro</dc:creator>
      <pubDate>Fri, 12 Jun 2026 12:02:37 +0000</pubDate>
      <link>https://dev.to/sysbalance/i-audited-a-production-whmcpanel-server-heres-what-i-found-and-how-to-check-yours-3h5m</link>
      <guid>https://dev.to/sysbalance/i-audited-a-production-whmcpanel-server-heres-what-i-found-and-how-to-check-yours-3h5m</guid>
      <description>&lt;p&gt;Last month I ran a security audit on a production WHM/cPanel server. It belonged to a web agency hosting a couple dozen client sites — WordPress, WooCommerce, the usual stack.&lt;/p&gt;

&lt;p&gt;The server had been running for years without anyone really &lt;em&gt;looking&lt;/em&gt; at it. Sites were up, clients were happy, nobody touched anything. Sound familiar?&lt;/p&gt;

&lt;p&gt;Here's what I found:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenSSH vulnerable to a critical CVE** (remote code execution class — the   kind you patch the day it's announced, not years later)&lt;/li&gt;
&lt;li&gt;SSH open to the world on port 22, root login enabled, password authentication on&lt;/li&gt;
&lt;li&gt;No brute-force protection beyond cPHulk's defaults&lt;/li&gt;
&lt;li&gt;PHP versions EOL'd long ago, still serving production sites&lt;/li&gt;
&lt;li&gt;"Backups configured" — but never test-restored. Two were silently failing&lt;/li&gt;
&lt;li&gt;No firewall rules beyond the defaults. Every service exposed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is exotic. This is what &lt;em&gt;most&lt;/em&gt; long-running cPanel servers look like when nobody owns them. So here's the audit checklist I use — run it on your own server this week. It takes about an hour.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Are you running vulnerable services?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The single highest-impact check. Start with SSH, since it's the front door:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-V&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare against the &lt;a href="https://www.openssh.com/releasenotes.html" rel="noopener noreferrer"&gt;OpenSSH release notes&lt;/a&gt; and check the version against known CVEs. If you're on a years-old version, assume it's vulnerable.&lt;/p&gt;

&lt;p&gt;On AlmaLinux/CloudLinux/RHEL-family (which is what cPanel runs on), check what security updates are pending:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yum updateinfo list security all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that list is long, that's your priority for the week. Don't cherry-pick — patch.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Harden SSH (15 minutes, massive payoff)
&lt;/h2&gt;

&lt;p&gt;Edit &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Move off the default port (reduces noise, not a security measure by itself)&lt;/span&gt;
Port 2222

&lt;span class="c"&gt;# No root over SSH. Ever. Use a sudo user.&lt;/span&gt;
PermitRootLogin no

&lt;span class="c"&gt;# Keys only. Passwords get brute-forced.&lt;/span&gt;
PasswordAuthentication no
PubkeyAuthentication &lt;span class="nb"&gt;yes&lt;/span&gt;

&lt;span class="c"&gt;# Limit who can even try&lt;/span&gt;
AllowUsers youradminuser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then restart: &lt;code&gt;systemctl restart sshd&lt;/code&gt; — &lt;strong&gt;but test the new connection in a second terminal before closing your current session.&lt;/strong&gt; Locking yourself out of a production server is a rite of passage you can skip.&lt;/p&gt;

&lt;p&gt;Better yet: restrict SSH access to your IP at the firewall level, so the rest of the internet can't even reach the port.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Install and actually configure a firewall
&lt;/h2&gt;

&lt;p&gt;cPanel servers should be running &lt;strong&gt;CSF/LFD&lt;/strong&gt; (ConfigServer Security &amp;amp; Firewall). It's free and integrates directly into WHM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /usr/src
wget https://download.configserver.com/csf.tgz
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzf&lt;/span&gt; csf.tgz
&lt;span class="nb"&gt;cd &lt;/span&gt;csf &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sh install.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The defaults are decent, but the minimum to configure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;TESTING = "0"&lt;/code&gt; once you've confirmed you're not locked out&lt;/li&gt;
&lt;li&gt;Close every port you don't use. A typical cPanel server needs far fewer open ports than the default&lt;/li&gt;
&lt;li&gt;Enable LFD login failure detection for SSH, FTP, mail, and cPanel itself&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;LF_PERMBLOCK = "1"&lt;/code&gt; for repeat offenders&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Audit your PHP versions
&lt;/h2&gt;

&lt;p&gt;Run this in WHM → MultiPHP Manager, or from the shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;whmapi1 php_get_installed_versions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anything EOL (&lt;a href="https://www.php.net/supported-versions.php" rel="noopener noreferrer"&gt;check php.net/supported-versions&lt;/a&gt;) is unpatched attack surface — and on a shared server, one compromised site is a problem for &lt;em&gt;every&lt;/em&gt; site. Move accounts off EOL versions. If a client's site "needs" PHP 7.4 in 2026, that's a conversation about updating the site, not a reason to keep the server vulnerable.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Test a backup restore. Today.
&lt;/h2&gt;

&lt;p&gt;A backup you've never restored is a hope, not a backup.&lt;/p&gt;

&lt;p&gt;Whatever you use — cPanel's native backups, JetBackup, rsync scripts — do this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pick one account&lt;/li&gt;
&lt;li&gt;Restore it to a test location (JetBackup can restore to an alternate account)&lt;/li&gt;
&lt;li&gt;Verify: files there? Database imports? Emails intact?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The agency server I audited had backups "running" for months. Two accounts were silently failing on a database dump error. Nobody knew, because nobody had ever restored one.&lt;/p&gt;

&lt;p&gt;While you're at it, check the 3-2-1 basics: are backups stored &lt;strong&gt;off the server&lt;/strong&gt;? A backup on the same disk as production protects you from nothing that matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Check who can do what
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Who has shell access?&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s1"&gt;'/sbin/nologin\|/bin/false'&lt;/span&gt; /etc/passwd

&lt;span class="c"&gt;# Who's in the wheel/sudo group?&lt;/span&gt;
&lt;span class="nb"&gt;grep &lt;/span&gt;wheel /etc/group

&lt;span class="c"&gt;# Any resellers with root-level WHM privileges they don't need?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In WHM → Edit Reseller Nameservers and Privileges, audit reseller ACLs. "All features" granted years ago for convenience is privilege escalation waiting to happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. The quiet ones people skip
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Symlink protection&lt;/strong&gt; — enable it in WHM (EasyApache → Apache symlink protection) so one compromised account can't read other accounts' files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ModSecurity&lt;/strong&gt; — should be on, with the OWASP CRS or Comodo ruleset&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cPHulk&lt;/strong&gt; — enabled, with country-level blocking if your users are geographically predictable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disable unused services&lt;/strong&gt; — &lt;code&gt;systemctl list-units --type=service --state=running&lt;/code&gt; and ask yourself why each one is there&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/tmp&lt;/code&gt; mounted with &lt;code&gt;noexec,nosuid&lt;/code&gt;&lt;/strong&gt; — classic and still effective&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The real takeaway
&lt;/h2&gt;

&lt;p&gt;None of these steps are hard. The problem is never the difficulty — it's that &lt;strong&gt;nobody owns the server&lt;/strong&gt;. Sites get built, deployed, and forgotten. The server hums along until the day it doesn't, and that day is expensive: downtime, blacklisted IPs, compromised client data, weekend recovery marathons.&lt;/p&gt;

&lt;p&gt;If you're a developer or agency running your own WHM/cPanel box: block one hour, run this checklist, and write down what you find. Worst case, you confirm you're in good shape. Best case, you find the thing before someone else does.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I've spent 15+ years managing Linux and WHM/cPanel infrastructure, and these days I help web agencies keep their client-hosting servers secure and online through &lt;a href="https://sysbalance.com" rel="noopener noreferrer"&gt;SysBalance&lt;/a&gt;. Questions about anything in this checklist? Drop them in the comments — happy to go deeper on any of these.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>security</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
