Set Up Two-Factor Authentication (2FA) for SSH

Set Up Two-Factor Authentication (2FA) for SSH

June 2026 · 7 min read

Password alone is not sufficient to protect your SSH connection. If your password is leaked or compromised through a brute force attack, attackers can gain immediate access to your VPS. Adding 2FA (Two-Factor Authentication) with TOTP (Time-based One-Time Password) ensures that even if a password is compromised, access is impossible without a second authentication device.

Important: Keep an SSH session open throughout the configuration process. If something goes wrong, you can troubleshoot without getting locked out.

Install Google Authenticator PAM

sudo apt update
sudo apt install libpam-google-authenticator -y

# Set up TOTP for the current user
google-authenticator

Answer the prompts as follows:

Save the QR code (scan it with the Google Authenticator app) and all 5 backup codes in a secure location.

Configure PAM for SSH

sudo nano /etc/pam.d/sshd
# Add this line after @include common-auth
auth required pam_google_authenticator.so
sudo nano /etc/ssh/sshd_config
# Edit or add these lines
ChallengeResponseAuthentication yes
# Or in newer SSH versions:
KbdInteractiveAuthentication yes

UsePAM yes

# If you want both SSH key and 2FA:
AuthenticationMethods publickey,keyboard-interactive
# Restart SSH daemon
sudo systemctl restart ssh

# Test in a new terminal (keep the old session open)
ssh user@YOUR_VPS_IP

Allow SSH Key to Bypass 2FA (Optional)

If you want SSH key authentication to skip the 2FA step (more convenient, but less secure):

sudo nano /etc/pam.d/sshd

# Change the line you added to:
auth required pam_google_authenticator.so nullok
sudo nano /etc/ssh/sshd_config

# Set AuthenticationMethods to support both modes
AuthenticationMethods publickey publickey,keyboard-interactive
Tip: If you use automation scripts or CI/CD pipelines that need SSH key access without 2FA, create a separate user for automation and add a Match User deploybot block in sshd_config to skip 2FA only for that user.

Verify 2FA is Working Correctly

# Check sshd config syntax
sudo sshd -t

# Check SSH service status
systemctl status ssh

# Test login (should prompt for both password and OTP code)
ssh -v user@YOUR_VPS_IP

# Verify PAM module is loaded
grep google-authenticator /var/log/auth.log | tail -10
Tip: If login succeeds without prompting for OTP, the configuration is incorrect. Double-check /etc/pam.d/sshd and /etc/ssh/sshd_config.

Common Issues & Troubleshooting

SSH Does Not Prompt for Verification Code

ChallengeResponseAuthentication is still set to no, or PAM is not loading the google-authenticator module:

# Check sshd_config
grep -i "ChallengeResponse\|KbdInteractive\|UsePAM" /etc/ssh/sshd_config

# Check PAM
grep -n "google-authenticator" /etc/pam.d/sshd

# Read SSH logs after login attempt
sudo journalctl -u ssh -n 30

Locked Out Despite Entering Correct Code

The VPS time differs from your phone's time by more than 30 seconds. Synchronize NTP first:

# Check server time
date
timedatectl

# Sync NTP
sudo timedatectl set-ntp true
sudo systemctl restart systemd-timesyncd

google-authenticator File Missing or Phone Reinstalled

The ~/.google_authenticator file stores the secret key. If it's lost, you must regenerate it:

# Regenerate (scan QR code in the app again)
google-authenticator

# If completely locked out, access via VPS console (KVM)
# Then temporarily disable 2FA for recovery

All Backup Codes Used Up

Generate new backup codes by regenerating google-authenticator, but you must scan the QR code in the app again:

# Edit the file directly to add backup codes (lines starting with 8 digits)
nano ~/.google_authenticator
# Or regenerate everything
google-authenticator -f -t -d -r 3 -R 30 -w 3

Frequently Asked Questions

What's the difference between 2FA and SSH key? Which should I use?

SSH keys protect against brute force very well because they are extremely long, but if your private key is compromised, an attacker gains instant access. 2FA adds another layer of protection that requires a physical device. Ideally, use both together: SSH key + 2FA.

What's the difference between TOTP and HOTP?

TOTP (Time-based OTP) generates a new code every 30 seconds using time as input. HOTP (HMAC-based OTP) uses a counter that increments by 1 with each use. TOTP is more popular because codes expire automatically.

Will I be locked out if my phone is lost?

Yes — if you don't have backup codes, losing your phone means lockout. Solutions: 1) Store backup codes outside your device, 2) Set up 2FA on two devices, 3) Save your secret key (.google_authenticator) in a password manager.