WordPress Security Checklist for Solo Bloggers (What I Actually Did)

I run this blog on a $6/month VPS from Vultr. No managed hosting. No security team. Just me, a terminal, and a healthy dose of paranoia.

When I first set up this WordPress site, I realized something uncomfortable: I’m responsible for everything. If someone hacks my server, that’s on me. If my blog gets turned into a spam relay, that’s on me. If I lose all my posts because I didn’t back up… you get the idea.

So I went through the process of actually securing my WordPress installation. Not the “enterprise-grade 47-step security audit” kind — the “solo blogger who needs to sleep at night” kind.

Here’s my actual checklist. Everything I did, why I did it, and a couple things I honestly skipped.

1. SSH Key Authentication (Disable Password Login)

This was step zero. When you spin up a VPS, the default is password-based SSH login. That means anyone on the internet can try to brute-force your server password. And they will — within minutes of your server going live.

What I did:

  • Generated an SSH key pair on my local machine (ssh-keygen -t ed25519)
  • Copied the public key to my server (ssh-copy-id root@my-server-ip)
  • Disabled password authentication in /etc/ssh/sshd_config (PasswordAuthentication no)
  • Restarted SSH (systemctl restart sshd)

This single step eliminates the most common attack vector for VPS servers. If you do nothing else on this list, do this one.

2. Firewall with UFW

UFW (Uncomplicated Firewall) is Ubuntu’s built-in firewall tool, and it lives up to its name. By default, your VPS has every port wide open. That’s… not great.

What I did:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

That’s it. Only SSH (port 22), HTTP (80), and HTTPS (443) are open. Everything else is blocked. Five commands, maybe two minutes of work, and your attack surface just shrank dramatically.

3. Fail2Ban for Brute Force Protection

Even with SSH keys, bots will still hammer your server trying to log in. Fail2Ban watches your log files and automatically bans IP addresses that fail too many login attempts.

What I did:

  • Installed Fail2Ban (apt install fail2ban)
  • Enabled the SSH jail (enabled by default on most Ubuntu installs)
  • Set it to ban IPs after 3 failed attempts for 1 hour

I checked the logs after a week and Fail2Ban had already banned over 200 IPs. These are all automated bots just scanning the internet for weak servers. Glad I’m not one of them.

4. Change the WordPress Login URL

Every WordPress site in the world has its login page at /wp-admin or /wp-login.php. Bots know this. They’ll hit those URLs constantly trying default credentials.

What I did: Installed the WPS Hide Login plugin and changed my login URL to something custom. It’s a free plugin, takes 30 seconds to set up, and it immediately cuts down on automated login attempts.

Is this “security through obscurity”? Yes. Is it still worth doing? Also yes. It won’t stop a targeted attack, but it eliminates 99% of automated bot traffic to your login page.

5. Strong Passwords + Unique Admin Username

This one’s boring but essential. My WordPress admin account doesn’t use “admin” as the username (never do this), and my password is a randomly generated 24-character string stored in a password manager.

What I did:

  • Created a non-obvious admin username during WordPress installation
  • Generated a strong password with my password manager
  • Made sure my database password is also unique and strong
  • Different passwords for SSH, WordPress admin, and MySQL — no reuse

I know, I know. Everyone says this. But “everyone says this” because people still use admin/password123 and then wonder why they got hacked.

6. Automatic WordPress Updates

WordPress has had automatic minor updates enabled by default for a while, but I also enabled automatic updates for plugins and themes. As a solo blogger, I can’t be checking for security patches every day.

What I did:

  • Confirmed WordPress core auto-updates are enabled
  • Enabled auto-updates for all plugins in the WordPress dashboard
  • Enabled auto-updates for my theme

The risk: An auto-update could break something. But for a solo blogger, the risk of running outdated software with known vulnerabilities is way higher than the risk of an update breaking your site. I’ll take the trade-off.

7. Backup Strategy

This isn’t technically “security,” but it’s your safety net when everything else fails. If your site gets compromised, you need to be able to restore it.

What I did:

  • Installed the UpdraftPlus plugin (free version)
  • Set up weekly full backups
  • Backups are stored remotely (not just on the same server — that defeats the purpose)
  • Tested restoring from a backup once to make sure it actually works

That last point is important. A backup you’ve never tested restoring is not really a backup. It’s just a file that might work. Maybe. Hopefully.

8. Disable XML-RPC

XML-RPC is a WordPress feature that allows external applications to communicate with your site. It’s also a common attack vector for brute force and DDoS amplification attacks. Unless you’re using the WordPress mobile app or Jetpack, you probably don’t need it.

What I did: Added this to my .htaccess file:

# Block XML-RPC
<Files xmlrpc.php>
    Order Deny,Allow
    Deny from all
</Files>

Done. One less thing for bots to poke at.

9. Limit Login Attempts

Even with the login URL changed, I added an extra layer. The Limit Login Attempts Reloaded plugin does exactly what the name says — it locks out IP addresses after a certain number of failed login attempts.

What I did:

  • Installed the plugin
  • Set it to 3 attempts before lockout
  • 20-minute lockout on first offense, increasing with repeated attempts

Between this, Fail2Ban, and the hidden login URL, brute-forcing my WordPress login is basically a dead end.

10. Security Headers

Security headers tell browsers how to behave when loading your site. They can prevent clickjacking, XSS attacks, and other common web vulnerabilities.

What I did: Added these headers to my Nginx configuration:

add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

These are basic but effective. You can check your headers at securityheaders.com — it’ll give you a letter grade and tell you what’s missing.

What I Skipped (And Why)

I’m being honest here. There are some commonly recommended security steps I haven’t done:

  • Web Application Firewall (WAF): Services like Cloudflare or Sucuri add a WAF in front of your site. I’m considering Cloudflare’s free tier, but I haven’t set it up yet. My traffic is low enough that it’s not urgent.
  • Two-Factor Authentication: I should set this up for my WordPress admin. I know. I’ll get to it. (This is the security equivalent of “I’ll start going to the gym next week.”)
  • File permission hardening: WordPress has recommended file permissions, and mine are probably fine by default, but I haven’t manually audited them.
  • Security audit plugins: Wordfence, iThemes Security, etc. I decided against adding a heavy security plugin because they can slow down a small VPS. The server-level protections I’ve set up cover the basics.

Is my setup perfect? No. Is it good enough for a solo blog on a $6 VPS? I think so. Security is about risk management, not perfection.

The Quick Checklist

If you’re setting up a WordPress blog on a VPS, here’s the priority order I’d recommend:

  1. SSH key authentication — do this immediately
  2. UFW firewall — takes 2 minutes
  3. Strong passwords — non-negotiable
  4. Fail2Ban — install and forget
  5. Automatic updates — enable everything
  6. Backups — set up UpdraftPlus or similar
  7. Change login URL — quick win
  8. Disable XML-RPC — one-time setup
  9. Limit login attempts — plugin install
  10. Security headers — add to your server config

The first five items take maybe 30 minutes total and cover 90% of what you need. Everything after that is extra protection that’s nice to have.

How This Post Was Made

I told Claude (in Korean, as usual) what I wanted: a security checklist post based on what I’ve actually done on this server. I listed out the steps — SSH keys, UFW, Fail2Ban, the plugins I use, what I skipped — and asked Claude to turn it into a readable post.

Claude wrote the full article, formatted it with WordPress blocks, and published it directly to my site using WP-CLI over SSH. Scheduled for 7am, as always. I reviewed it from my end, and here it is.

The security steps in this post are real — they’re running on the same server that’s serving you this page right now. That’s the nice thing about writing from experience: you can’t fake it when the proof is the site itself working (and not being hacked).


This post was written with Claude AI. I provided the direction, topic, and key points in Korean — Claude turned it into the article you just read. The security configurations described are actually running on this server.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top