1. Inventory the real attack surface
List public ports, listening services, DNS names, administration endpoints, WordPress users, plugins, themes, scheduled jobs, database bindings, mail paths, analytics, storage, and external integrations. Confirm which component owns TLS termination and which logs contain security events.
Remove default content, unused themes and plugins, obsolete staging routes, and services with no operating owner. WordPress guidance treats fewer writable components and fewer dependencies as a security advantage, not merely a performance preference.
2. Patch the operating system and WordPress deliberately
Use a supported operating system, enable unattended security updates where appropriate, monitor advisories, and inspect pending packages. Keep WordPress core, active plugins, and the active theme current. Verify official core checksums with WP-CLI after significant changes.
When application code is read-only to the web service, updates should run through a privileged, backup-first procedure. This is safer than leaving production code writable indefinitely, but only if the procedure has an owner and cadence.
3. Harden SSH without losing recovery access
Disable root login, password authentication, keyboard-interactive authentication, X11 forwarding, agent forwarding, TCP forwarding, tunnelling, and gateway ports unless a documented need exists. Reduce authentication attempts and login grace time. Keep public-key access and validate the effective configuration before reload.
Never close the current administrative session immediately after an SSH change. Open a second session and run a harmless command first. Keep console or provider-level recovery available for major access changes.
4. Default-deny network access
At the host firewall, deny unsolicited inbound traffic and allow only the ports required for administration and the public web service. Keep the database bound to loopback unless a deliberate private-network architecture requires otherwise.
Apply the same principle at the cloud firewall. Host and cloud controls are complementary: one protects against a broad provider rule; the other protects when a local service unexpectedly begins listening.
5. Remove runtime write access to application code
The PHP/web-service account normally needs to read WordPress core, plugins, and themes, but it should not be able to rewrite them during an ordinary request. Use restrictive ownership and conventional 755 directory and 644 file modes, with a tighter read-only configuration file.
Keep only explicit runtime locations writable, such as uploads and a required cache or upgrade workspace. Deny script execution inside uploads. For the deeper rationale, read why WordPress filesystem permissions matter more than another plugin.
6. Protect the application boundary
Force HTTPS for administration, disable the built-in file editor, block XML-RPC if unused, prevent unauthenticated user enumeration, and apply secure response headers. Use a Content Security Policy that is strict enough to add value but compatible with the editor and required scripts.
Use generic authentication errors, strong unique credentials, least-privilege roles, and MFA for administrators. Keep service users scoped to their actual tasks and make credentials revocable.
7. Detect abuse and preserve evidence
Use server logs and a tool such as Fail2ban to identify repeated SSH and application authentication failures. Tune thresholds to the actual log format and validate filters before enabling them. Do not log passwords, application credentials, sensitive form values, or full AI prompts by default.
Alert on availability failures, certificate expiry, repeated authentication abuse, unexpected file changes, update failures, and backup failures. Monitoring should identify an action owner, not only produce a dashboard.
8. Make recovery part of the control
Back up both database and files to an off-host location with restricted credentials. Test a restore. Before each material change, capture the affected configuration, permissions, database, and application release. Document a rollback command that can be executed under pressure.
The most important security question is not whether an incident is imaginable. It is whether the service can be contained, understood, restored, and improved without relying on memory.
Primary references
Start with WordPress hardening guidance, WordPress file-permission guidance, the Debian Securing Manual, the OWASP HTTP Headers Cheat Sheet, and NIST SP 800-123. Controls must be adapted to the actual stack and tested with a rollback path.


