<?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: Tyler Russo</title>
    <description>The latest articles on DEV Community by Tyler Russo (@tyler_russo_f3ae739f97551).</description>
    <link>https://dev.to/tyler_russo_f3ae739f97551</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4161582%2Fbb21cbc9-4e57-4aba-a34f-5c44d935a9dc.png</url>
      <title>DEV Community: Tyler Russo</title>
      <link>https://dev.to/tyler_russo_f3ae739f97551</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tyler_russo_f3ae739f97551"/>
    <language>en</language>
    <item>
      <title>Why Your WordPress Site Is Slow (It's Probably Not Your Host)</title>
      <dc:creator>Tyler Russo</dc:creator>
      <pubDate>Mon, 05 Oct 2026 23:12:54 +0000</pubDate>
      <link>https://dev.to/tyler_russo_f3ae739f97551/why-your-wordpress-site-is-slow-its-probably-not-your-host-hjp</link>
      <guid>https://dev.to/tyler_russo_f3ae739f97551/why-your-wordpress-site-is-slow-its-probably-not-your-host-hjp</guid>
      <description>&lt;p&gt;Everyone blames the host. "I need to upgrade my plan." Nine times out of ten, the host is fine — the site is just carrying dead weight. Here's how I find it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with a real measurement
&lt;/h2&gt;

&lt;p&gt;Don't guess. Run your URL through PageSpeed Insights and write down three numbers: LCP (Largest Contentful Paint), INP (Interaction to Next Paint), and TTFB (Time to First Byte). These are your before numbers. Everything below is about moving them.&lt;/p&gt;

&lt;p&gt;If TTFB is over 600ms on a cached page, &lt;em&gt;then&lt;/em&gt; you can blame the host. Under that, keep reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  The usual suspects, in order
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. No page caching.&lt;/strong&gt; This is the big one. Every uncached WordPress request boots PHP, hits MySQL, renders the theme — hundreds of milliseconds you don't need to spend. A caching plugin serving static HTML cuts that to near zero. This alone fixes most "slow WordPress" complaints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Unoptimized images.&lt;/strong&gt; I still find 4MB PNGs as hero images. Convert to WebP, resize to the actual display size, and lazy-load everything below the fold. A single oversized image can blow your entire LCP budget.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Plugin bloat.&lt;/strong&gt; Deactivate everything, then reactivate one at a time while watching TTFB. Page builders, slider plugins, and "all-in-one" packs are the usual offenders. If a plugin adds 200ms and you barely use it, it's gone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. No database cleanup.&lt;/strong&gt; Years of post revisions, expired transients, and orphaned metadata slow down every query. Back up first, then clean house.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Old PHP.&lt;/strong&gt; PHP 7.4 to 8.x is a free 20-30% performance gain. Most hosts let you switch in the control panel. Check plugin compatibility first, then flip it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The order matters
&lt;/h2&gt;

&lt;p&gt;Do caching first — it masks a multitude of sins and gives you the biggest immediate win. Then images, then plugins, then database, then PHP. Each step builds on the last, and you re-measure after each one so you know what actually moved the needle.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "fast enough" looks like
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;LCP under 2.5 seconds&lt;/li&gt;
&lt;li&gt;INP under 200ms&lt;/li&gt;
&lt;li&gt;TTFB under 600ms (under 200ms cached)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hit those and you're in Google's good graces for Core Web Vitals, which is a ranking factor.&lt;/p&gt;




&lt;p&gt;The full process — 40 checkpoints covering caching, database cleanup, image optimization, CDN setup, and PHP tuning, in the exact order to do them — is in my &lt;a href="https://www.skypressdigital.com/wordpress-speed-checklist" rel="noopener noreferrer"&gt;WordPress Speed Checklist&lt;/a&gt;. Every step includes the before-and-after measurement so you can prove it worked.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>performance</category>
      <category>webdev</category>
      <category>php</category>
    </item>
    <item>
      <title>The Pre-Migration Server Audit: What to Document Before You Touch Anything</title>
      <dc:creator>Tyler Russo</dc:creator>
      <pubDate>Mon, 05 Oct 2026 15:43:04 +0000</pubDate>
      <link>https://dev.to/tyler_russo_f3ae739f97551/the-pre-migration-server-audit-what-to-document-before-you-touch-anything-3p18</link>
      <guid>https://dev.to/tyler_russo_f3ae739f97551/the-pre-migration-server-audit-what-to-document-before-you-touch-anything-3p18</guid>
      <description>&lt;p&gt;Migrating a VPS goes sideways in the same places every time — and it's never the part you expect. It's the queue worker left on the old box. The certbot renewal in root's crontab. The rsync that died on permissions.&lt;/p&gt;

&lt;p&gt;Before you move anything, audit the old server. Here's the checklist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running services
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl list-units &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;service &lt;span class="nt"&gt;--state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;running
ss &lt;span class="nt"&gt;-tlnp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Write down everything. That random Python process on port 8000? That's serving something. Find out what before you migrate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cron jobs (all four places)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crontab &lt;span class="nt"&gt;-l&lt;/span&gt;                    &lt;span class="c"&gt;# your user&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;crontab &lt;span class="nt"&gt;-l&lt;/span&gt;               &lt;span class="c"&gt;# root&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; /etc/cron.d/ /etc/cron.daily/ /etc/cron.hourly/
systemctl list-timers         &lt;span class="c"&gt;# systemd timers (the new cron)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Miss one and something silently stops working a week after migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disk and databases
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;df&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt;
&lt;span class="nb"&gt;du&lt;/span&gt; &lt;span class="nt"&gt;-sh&lt;/span&gt; /var/www/&lt;span class="k"&gt;*&lt;/span&gt; /home/&lt;span class="k"&gt;*&lt;/span&gt;
mysql &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"SHOW DATABASES;"&lt;/span&gt;    &lt;span class="c"&gt;# or psql -l for Postgres&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Know what you're moving before you start moving it.&lt;/p&gt;

&lt;h2&gt;
  
  
  SSL certificates
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;certbot certificates
&lt;span class="nb"&gt;ls&lt;/span&gt; /etc/letsencrypt/live/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note expiry dates and renewal method. If certbot auto-renewal is configured, that config needs to move too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Config files
&lt;/h2&gt;

&lt;p&gt;Document every customized config: nginx/apache vhosts, PHP settings, systemd units, environment files. &lt;code&gt;diff&lt;/code&gt; against defaults if you're not sure what you changed.&lt;/p&gt;




&lt;p&gt;This audit is Zone 1 of my &lt;a href="https://www.skypressdigital.com/vps-migration-checklist" rel="noopener noreferrer"&gt;VPS Migration Checklist &amp;amp; Runbook&lt;/a&gt; — 38 checkpoints across 8 zones, from this audit through cutover and the 24-hour watch afterward. The full runbook covers rsync flags, database moves, the hosts-file testing trick, and the rollback plan you write before you need it.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>linux</category>
      <category>tutorial</category>
      <category>vps</category>
    </item>
    <item>
      <title>How to Test a WordPress Backup Restore (Before You Need It)</title>
      <dc:creator>Tyler Russo</dc:creator>
      <pubDate>Mon, 05 Oct 2026 15:00:22 +0000</pubDate>
      <link>https://dev.to/tyler_russo_f3ae739f97551/how-to-test-a-wordpress-backup-restore-before-you-need-it-16ji</link>
      <guid>https://dev.to/tyler_russo_f3ae739f97551/how-to-test-a-wordpress-backup-restore-before-you-need-it-16ji</guid>
      <description>&lt;p&gt;Untested backups aren't backups. They're hopes. Here's how to prove yours actually work — the full restore drill I run.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you need
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A scratch server or local environment (doesn't need to be powerful)&lt;/li&gt;
&lt;li&gt;Your latest backup files (database dump + files archive)&lt;/li&gt;
&lt;li&gt;About an hour&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Set up the scratch environment
&lt;/h2&gt;

&lt;p&gt;Spin up a fresh Ubuntu box or Docker container. Install the same PHP version your production site runs — version mismatches cause the weirdest restore failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Restore the database
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mysql &lt;span class="nt"&gt;-u&lt;/span&gt; root &lt;span class="nt"&gt;-p&lt;/span&gt; new_database &amp;lt; backup.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then verify: count the tables, check that &lt;code&gt;wp_options&lt;/code&gt; has your site URL. If the dump is corrupted or incomplete, you want to know now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Restore the files
&lt;/h2&gt;

&lt;p&gt;Extract your files archive to the web root. Check that &lt;code&gt;wp-config.php&lt;/code&gt; is there (some backup tools exclude it — that's a nasty surprise at 2am).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Point and test
&lt;/h2&gt;

&lt;p&gt;Update &lt;code&gt;wp-config.php&lt;/code&gt; with the new database credentials. Add this to your local &lt;code&gt;/etc/hosts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;127.0.0.1 yoursite.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now browse the site. Click around. Log into wp-admin. Upload a test image. If everything works, your backup is real.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Document what you learned
&lt;/h2&gt;

&lt;p&gt;Write down every step you took, every gotcha you hit. That's your disaster runbook. Next time you're restoring at midnight with the site down, you'll thank past-you.&lt;/p&gt;

&lt;h2&gt;
  
  
  How often?
&lt;/h2&gt;

&lt;p&gt;Quarterly at minimum. After every major change (host migration, PHP upgrade, big plugin update).&lt;/p&gt;




&lt;p&gt;The full backup process — 40 checkpoints across 7 zones covering inventory, automation, encrypted offsite copies, and monitoring — is in my &lt;a href="https://www.skypressdigital.com/wordpress-backup-disaster-recovery" rel="noopener noreferrer"&gt;WordPress Backup &amp;amp; Disaster Recovery Checklist&lt;/a&gt;. The restore drill above is Zone 5.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>backup</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Hardening SSH on Ubuntu 24.04: The 6 Things That Actually Matter</title>
      <dc:creator>Tyler Russo</dc:creator>
      <pubDate>Mon, 05 Oct 2026 14:59:13 +0000</pubDate>
      <link>https://dev.to/tyler_russo_f3ae739f97551/hardening-ssh-on-ubuntu-2404-the-6-things-that-actually-matter-4abe</link>
      <guid>https://dev.to/tyler_russo_f3ae739f97551/hardening-ssh-on-ubuntu-2404-the-6-things-that-actually-matter-4abe</guid>
      <description>&lt;p&gt;Most SSH hardening guides give you 30 config options and no sense of priority. Here's what actually matters, in the order I'd do them on a fresh Ubuntu 24.04 server.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Key-only auth (but test first)
&lt;/h2&gt;

&lt;p&gt;Generate your key, copy it over, SSH in with the key to confirm it works — &lt;em&gt;then&lt;/em&gt; disable passwords. The number of people who lock themselves out by doing this backwards is staggering.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;PasswordAuthentication&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt;
&lt;span class="n"&gt;ChallengeResponseAuthentication&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. The cloud-image gotcha
&lt;/h2&gt;

&lt;p&gt;On Ubuntu cloud images (AWS, DigitalOcean, etc.), there's a file at &lt;code&gt;/etc/ssh/sshd_config.d/60-cloudimg-settings.conf&lt;/code&gt; that overrides whatever you put in &lt;code&gt;sshd_config&lt;/code&gt;. Drop-in files are read alphabetically, first value wins — so &lt;code&gt;60-cloudimg-settings.conf&lt;/code&gt; beats your settings.&lt;/p&gt;

&lt;p&gt;The fix: put your hardening in &lt;code&gt;/etc/ssh/sshd_config.d/10-hardening.conf&lt;/code&gt;. 10 beats 60. I wrote about this in detail &lt;a href="https://dev.to/tyler_russo_f3ae739f97551/your-ssh-hardening-guide-has-a-bug-on-cloud-servers-60-beats-99-2fcf"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Disable root login
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;PermitRootLogin&lt;/span&gt; &lt;span class="no"&gt;no&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have sudo. You don't need direct root SSH.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Change the port (yes, really)
&lt;/h2&gt;

&lt;p&gt;Security through obscurity isn't security — but moving off port 22 eliminates 99% of automated brute-force noise, which makes your logs readable and fail2ban's job easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. fail2ban with sane defaults
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;fail2ban
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default SSH jail is fine for most people. Check it's running: &lt;code&gt;sudo fail2ban-client status sshd&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Automatic security updates
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;unattended-upgrades
&lt;span class="nb"&gt;sudo &lt;/span&gt;dpkg-reconfigure &lt;span class="nt"&gt;-plow&lt;/span&gt; unattended-upgrades
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;This is the 30-minute emergency version. The full process — 46 checkpoints covering users, firewall, kernel tweaks, file permissions, log monitoring, and more — is in my &lt;a href="https://www.skypressdigital.com/linux-server-hardening-checklist" rel="noopener noreferrer"&gt;Linux Server Hardening Checklist&lt;/a&gt;. Every command tested on real Ubuntu 22.04 and 24.04 servers.&lt;/p&gt;

&lt;p&gt;Or grab the &lt;a href="https://tylerrusso.gumroad.com/l/free-server-lockdown-checklist" rel="noopener noreferrer"&gt;free 7-step emergency lockdown checklist&lt;/a&gt; if you just need the essentials right now.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>security</category>
      <category>ssh</category>
      <category>ubuntu</category>
    </item>
    <item>
      <title>Your SSH hardening guide has a bug: on cloud servers, 60 beats 99</title>
      <dc:creator>Tyler Russo</dc:creator>
      <pubDate>Sun, 04 Oct 2026 12:37:21 +0000</pubDate>
      <link>https://dev.to/tyler_russo_f3ae739f97551/your-ssh-hardening-guide-has-a-bug-on-cloud-servers-60-beats-99-2fcf</link>
      <guid>https://dev.to/tyler_russo_f3ae739f97551/your-ssh-hardening-guide-has-a-bug-on-cloud-servers-60-beats-99-2fcf</guid>
      <description>&lt;p&gt;I sell a server hardening checklist, so last week I did something most checklist authors never do: I re-ran every single command against a real Ubuntu 24.04 box instead of trusting the docs.&lt;/p&gt;

&lt;p&gt;Two of the commands were wrong. Not "suboptimal" — wrong. One of them fails &lt;em&gt;silently&lt;/em&gt;, which is worse. Here's the interesting one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;Most SSH hardening guides tell you the same thing: don't edit &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; directly. Drop your settings into &lt;code&gt;/etc/ssh/sshd_config.d/&lt;/code&gt;, conventionally in a file named something like &lt;code&gt;99-hardening.conf&lt;/code&gt;. High number, loads last, wins. Clean, package-manager-safe advice.&lt;/p&gt;

&lt;p&gt;It's wrong on cloud images.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually happens
&lt;/h2&gt;

&lt;p&gt;Ubuntu cloud images (AWS, DigitalOcean, Hetzner, all of them) ship a file at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="k"&gt;etc&lt;/span&gt;/ssh/sshd_config.d/60-cloudimg-settings.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's the part the guides skip: sshd reads the drop-in directory with a glob, in &lt;strong&gt;alphabetical order&lt;/strong&gt; — and for most keywords, sshd uses &lt;strong&gt;first-value-wins&lt;/strong&gt; semantics. The first setting it encounters is the one that sticks.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;60&lt;/code&gt; sorts before &lt;code&gt;99&lt;/code&gt;. So your carefully written &lt;code&gt;99-hardening.conf&lt;/code&gt; &lt;strong&gt;loses to the cloud image's file for every keyword they both set&lt;/strong&gt; — and it loses silently. No error, no warning. Your hardening setting just... doesn't apply.&lt;/p&gt;

&lt;p&gt;I proved it the honest way: wrote a test value into &lt;code&gt;99-hardening.conf&lt;/code&gt; on a real 24.04 box and ran:&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;sudo &lt;/span&gt;sshd &lt;span class="nt"&gt;-T&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &amp;lt;keyword&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The effective config showed the cloud image's value, not mine. My file might as well not have existed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix (30 seconds)
&lt;/h2&gt;

&lt;p&gt;Name your file so it sorts &lt;em&gt;before&lt;/em&gt; the cloud image's file:&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;sudo mv&lt;/span&gt; /etc/ssh/sshd_config.d/99-hardening.conf &lt;span class="se"&gt;\&lt;/span&gt;
        /etc/ssh/sshd_config.d/10-hardening.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then verify — don't trust, verify:&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;sudo &lt;/span&gt;sshd &lt;span class="nt"&gt;-T&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &amp;lt;keyword&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;sshd -T&lt;/code&gt; prints the &lt;em&gt;effective&lt;/em&gt; configuration after all includes are resolved. If your value shows up there, it won. If it doesn't, something earlier in the sort order is beating you, and now you know how to find it.&lt;/p&gt;

&lt;p&gt;This also means the generic advice "put it in the main &lt;code&gt;sshd_config&lt;/code&gt;" is doubly broken: the main file &lt;code&gt;Include&lt;/code&gt;s the drop-in directory at the &lt;em&gt;top&lt;/em&gt;, so drop-ins beat the main file too. The drop-in directory is the right place — you just have to win the sort order.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus bug: &lt;code&gt;systemctl restart sshd&lt;/code&gt; fails on Ubuntu
&lt;/h2&gt;

&lt;p&gt;While I was at it: half the guides say &lt;code&gt;systemctl restart sshd&lt;/code&gt; after editing. On Ubuntu there is no &lt;code&gt;sshd.service&lt;/code&gt; — the unit is &lt;code&gt;ssh&lt;/code&gt;. The command fails, and if you're following a guide at 2 AM you get to debug that instead of sleeping:&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;sudo &lt;/span&gt;systemctl restart ssh   &lt;span class="c"&gt;# not sshd, on Ubuntu/Debian&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(RHEL-family distros do use &lt;code&gt;sshd&lt;/code&gt;. Know your box.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual lesson
&lt;/h2&gt;

&lt;p&gt;Doc-based audits miss ordering and naming subtleties. The only audit I trust anymore is running the real binary and reading what it says: &lt;code&gt;sshd -T&lt;/code&gt; for SSH, &lt;code&gt;nginx -t&lt;/code&gt; for nginx, and so on. If your hardening checklist wasn't verified against a live system, it's a wish list.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I turned the full verified checklist into a 46-checkpoint playbook (every command tested like this one), but the 7-step starter version is free — &lt;a href="https://tylerrusso.gumroad.com/l/free-server-lockdown-checklist" rel="noopener noreferrer"&gt;Emergency Server Lockdown Checklist&lt;/a&gt;. Lock down a VPS tonight with copy-paste commands.&lt;/em&gt;&lt;/p&gt;

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