All Systems GO!
VPS & Dedicated

SSH Key Setup for WordPress VPS

Disclosure: This post contains affiliate links; we may earn a commission at no extra cost to you.

SSH Key Setup for a WordPress VPS

SSH keys let you administer a WordPress VPS without sending an account password on every login. A properly protected Ed25519 key is resistant to guessing attacks and can be revoked independently. It does not make the server invulnerable: stolen private keys, permissive sudo rules, vulnerable WordPress plugins, and exposed hosting accounts remain serious risks.

This walkthrough assumes an Ubuntu or Debian VPS and a local computer with OpenSSH. Commands are shown for PowerShell, macOS, and Linux where they differ. Keep your current provider console or SSH session open until a second session proves key login works.

Choose a VPS with recovery access

DigitalOcean Droplets, Hetzner Cloud, Vultr Cloud Compute, Linode/Akamai Cloud, and AWS Lightsail all support SSH keys and browser or serial recovery consoles. Compare current regional pricing, backups, bandwidth, support, and managed services. A cheap unmanaged VPS requires you to patch the OS, configure firewall and backups, monitor resources, and recover failures yourself.

[AFFILIATE CTA: DigitalOcean]

DigitalOcean is the easiest general recommendation for a first WordPress VPS because its SSH-key onboarding, documentation, snapshots, monitoring, and recovery console are approachable. It costs more than some budget providers at similar raw specifications, automated backups add cost, and it is still unmanaged unless you buy a separate management layer.

1. Generate an Ed25519 key

On PowerShell, Windows Terminal, macOS Terminal, or Linux, run:

ssh-keygen -t ed25519 -a 100 -C "wordpress-prod-admin"

Accept the proposed location or choose a descriptive file such as ~/.ssh/wp_prod_ed25519. Use a strong passphrase. The private key file has no extension by default; the public key ends in .pub. Never upload, email, or paste the private key.

Ed25519 is compact, fast, and the preferred default on modern OpenSSH. If a legacy or compliance environment requires RSA, use at least 3072 bits:

ssh-keygen -t rsa -b 4096 -o -a 100 -C "wordpress-prod-admin"

The -a 100 option increases key-derivation work protecting the private-key file. A passphrase buys time if a laptop or backup is stolen. It does not help if malware captures the key after the user unlocks it.

Display only the public key:

Get-Content $env:USERPROFILE\.ssh\wp_prod_ed25519.pub
# macOS/Linux:
cat ~/.ssh/wp_prod_ed25519.pub

The line begins with ssh-ed25519. Copy the entire single line. Hosting control panels commonly allow this public key during server creation, which is safer than enabling a password first.

2. Create a non-root administrator

If the image initially permits root login, connect using the provider-approved method, then create an individual account:

adduser deploy
usermod -aG sudo deploy
install -d -m 700 -o deploy -g deploy /home/deploy/.ssh

Use a named account for each administrator instead of sharing deploy on a team. Individual accounts make audit logs and revocation meaningful. A deployment service can have a separate account with narrower permissions and no interactive sudo.

Add the public key without changing its one-line format:

nano /home/deploy/.ssh/authorized_keys
chown deploy:deploy /home/deploy/.ssh/authorized_keys
chmod 600 /home/deploy/.ssh/authorized_keys

Paste the public key, save, and exit. The directory must normally be mode 700 and authorized_keys mode 600. OpenSSH may reject files writable by other users.

When password login is temporarily available, macOS/Linux users can use:

ssh-copy-id -i ~/.ssh/wp_prod_ed25519.pub deploy@server.example.com

Windows OpenSSH can pipe a public key through an SSH command, but manual provider injection or careful editing avoids quoting mistakes. Confirm the destination before sending any content.

3. Test a separate session

From a new terminal, run:

ssh -i ~/.ssh/wp_prod_ed25519 deploy@203.0.113.10

On first connection, SSH displays a host-key fingerprint. Compare it with the fingerprint shown by the provider console or generated directly on the server. Blindly answering “yes” can accept a machine-in-the-middle. IP address 203.0.113.10 is documentation-only; substitute the real address.

Test sudo:

sudo -v
sudo whoami

The final output should be root. Keep the original session open. If key authentication fails, use verbose output:

ssh -vvv -i ~/.ssh/wp_prod_ed25519 deploy@server.example.com

Common causes are the wrong username, wrong key, incorrect permissions, a wrapped public-key line, a cloud firewall blocking TCP 22, or sshd reading a different authorized-keys path.

4. Configure the local SSH client

Add an entry to ~/.ssh/config:

Host wp-production
    HostName 203.0.113.10
    User deploy
    IdentityFile ~/.ssh/wp_prod_ed25519
    IdentitiesOnly yes

Then connect with ssh wp-production. On Windows, OpenSSH expands a suitable home-relative path in its configuration; verify with ssh -G wp-production. Restrict the config file so other local users cannot modify it.

An SSH agent caches an unlocked key. On Linux/macOS:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/wp_prod_ed25519

Windows includes an ssh-agent service, but enabling persistent key storage changes the security tradeoff. A hardware-backed FIDO2 security key can be stronger. Modern OpenSSH can create resident or non-resident ed25519-sk keys with compatible YubiKey or other FIDO authenticators; test provider console access before depending on one device.

5. Harden the SSH server

Only after successful key and sudo tests, inspect the effective configuration:

sudo sshd -T | grep -E 'passwordauthentication|permitrootlogin|pubkeyauthentication'

Create a drop-in where supported, such as /etc/ssh/sshd_config.d/99-hardening.conf:

PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no

Some cloud images or authentication modules need keyboard-interactive login. Do not disable a method until every legitimate administrator has tested a key and provider recovery works. Validate syntax and reload without killing sessions:

sudo sshd -t
sudo systemctl reload ssh

On some distributions the unit is sshd. Open a third session and test again. A successful configuration test prevents many lockouts, but a cloud firewall or user-file error can still block access.

Changing the SSH port reduces noisy automated logs but is not material authentication security. If you change it, update the cloud firewall, UFW, monitoring, and local config before reloading. Key-only authentication and restricted source networks are more valuable.

6. Restrict network access

Use the provider firewall and the server firewall. With UFW, allow SSH before enabling it:

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

If administrators have stable office or VPN addresses, restrict port 22 to those sources. A mesh VPN such as Tailscale can keep SSH off the public internet; understand its identity provider and recovery dependencies before making it the only route.

Fail2ban can temporarily block repeated failures, but it is secondary once passwords are disabled. Install unattended security updates carefully, monitor reboot requirements, and subscribe to distribution security notices.

7. Separate WordPress deployment permissions

Do not make all WordPress files owned by the web server with mode 777. A common approach gives a deployment user and web-server group controlled access, with directories at 755 or 750 and files at 644 or 640 depending on the stack. The exact ownership depends on PHP-FPM pools, deployment design, and which directories WordPress must write.

At minimum, uploads and cache directories may need web-process write access. WordPress core and plugin files can be read-only to the web process when updates occur through a deployment pipeline. Disable the built-in theme/plugin editor with DISALLOW_FILE_EDIT. If automatic updates are required, design permissions narrowly rather than granting global writes.

Use SFTP over SSH instead of plain FTP. Give contractors separate time-limited keys and accounts. In authorized_keys, keys can be restricted by source address or forced command, although mistakes can lock out automation. Never put a private deployment key inside the web root or a public repository.

Rotation, revocation, and backups

Maintain an inventory showing key fingerprint, owner, purpose, creation date, and servers authorized. Show a fingerprint with:

ssh-keygen -lf ~/.ssh/wp_prod_ed25519.pub

To revoke access, remove that exact public-key line from every relevant authorized_keys file and terminate active sessions if necessary. Rotating a key means adding and testing the new public key before removing the old one.

Back up private keys only in encrypted storage, such as a reputable password manager that supports secure files or an encrypted offline archive. Do not rely on the laptop’s only copy. Also do not clone one personal private key across an entire team.

SSH access is just one recovery layer. Enable provider snapshots or independent backups, test WordPress database restoration, and preserve a provider-console route. If the server is compromised, assume keys and secrets accessible to that host may be exposed; rebuild from a clean image and rotate credentials rather than merely deleting suspicious files.