Overview
Two-factor authentication (2FA) adds an essential security layer to SSH access by requiring both your password (or SSH key) and a time-based one-time password (TOTP) generated by an authenticator app. This guide walks through configuring the Google Authenticator PAM module on Linux servers.
| Difficulty | Intermediate |
| Time Required | 15-20 minutes |
| Supported OS | Ubuntu 20.04/22.04/24.04, Debian 11/12, CentOS/RHEL 8/9, AlmaLinux 8/9 |
| Requirements | Root/sudo access, TOTP authenticator app |
Prerequisites
Before you begin, ensure you have the following:
- Root or sudo access to your server
- A TOTP-compatible authenticator app installed on your mobile device (Google Authenticator, Authy, Microsoft Authenticator, or 1Password)
- An active SSH session (keep this open throughout the configuration process)
- A backup access method (console access via your hosting provider) in case of configuration errors
Important
Keep your current SSH session open until you have verified the new configuration works. Misconfigured 2FA can lock you out of your server.
Installation
Step 1: Install Google Authenticator PAM Module
Install the Google Authenticator PAM module using your distribution's package manager.
Ubuntu/Debian
sudo apt update
sudo apt install libpam-google-authenticator -yCentOS/RHEL/AlmaLinux
sudo dnf install epel-release -y
sudo dnf install google-authenticator -yConfigure TOTP
Step 2: Configure TOTP for Your User Account
Run the Google Authenticator setup as the user who will be using 2FA (do not use sudo for this step):
google-authenticatorYou will be prompted with several configuration questions. Here are the recommended responses:
| Question | Answer | Purpose |
|---|---|---|
| Do you want authentication tokens to be time-based? | y | Uses TOTP standard |
| Do you want me to update your ~/.google_authenticator file? | y | Saves configuration |
| Do you want to disallow multiple uses of the same token? | y | Prevents replay attacks |
| Do you want to increase the time skew window? | n | Default window is secure |
| Do you want to enable rate-limiting? | y | Prevents brute force |
The setup will display a QR code and a secret key. Scan the QR code with your authenticator app and securely store the emergency backup codes.
Configure PAM
Step 3: Configure PAM for SSH
Edit the PAM configuration file for SSH:
sudo nano /etc/pam.d/sshdAdd the following line at the end of the file:
auth required pam_google_authenticator.so nullokThe nullok option allows users who haven't configured 2FA to still log in with just their password. Remove nullok once all users have set up their authenticators to enforce 2FA for everyone.
Configure SSH Daemon
Step 4: Configure SSH Daemon
Edit the SSH daemon configuration:
sudo nano /etc/ssh/sshd_configLocate and modify the following directives (or add them if they don't exist):
ChallengeResponseAuthentication yes
UsePAM yesFor Password + TOTP Authentication
To require both password and TOTP verification:
AuthenticationMethods keyboard-interactiveFor SSH Key + TOTP Authentication
To require both an SSH key and TOTP verification:
AuthenticationMethods publickey,keyboard-interactiveFor SSH key + TOTP, also comment out the following line in /etc/pam.d/sshd:
# @include common-authStep 5: Restart SSH Service
Apply the configuration changes by restarting the SSH daemon:
sudo systemctl restart sshdYour existing SSH session will remain active. Test the new configuration in a separate terminal window before closing your current session.
Test the Configuration
Step 6: Test the Configuration
Open a new terminal window (keep your current session open) and test the login:
ssh username@your-server-ipYou should be prompted for your password (if using password authentication) followed by the verification code from your authenticator app.
Backup and Recovery
Emergency Backup Codes
During the initial setup, you received five emergency scratch codes. These are one-time use codes that work when you don't have access to your authenticator app.
- 1.Store these codes in a secure location (password manager, encrypted file, or printed in a safe)
- 2.Each code can only be used once
- 3.Generate new codes by re-running
google-authenticatorif you run out
Regenerating Codes
To generate a new set of backup codes without changing your secret key:
google-authenticator -s ~/.google_authenticatorTroubleshooting
Verification Code Not Accepted
- Time synchronization: Ensure your server's time is accurate. Run
timedatectlto check andsudo timedatectl set-ntp trueto enable NTP sync. - Time zone mismatch: Verify both your phone and server are using correct time zones.
- Code expiration: TOTP codes are valid for 30 seconds. Wait for a new code if near expiration.
Locked Out of Server
- • Use emergency backup codes if available
- • Access the server via console through your hosting provider's control panel
- • Boot into recovery mode and remove the PAM configuration line from
/etc/pam.d/sshd
View Debug Logs
Check authentication logs for detailed error information:
Ubuntu/Debian
sudo tail -f /var/log/auth.logCentOS/RHEL/AlmaLinux
sudo tail -f /var/log/secureSecurity Best Practices
Remove nullok after setup
Once all users have configured 2FA, remove the
nullokoption from the PAM configuration to enforce 2FA for all accounts.Use SSH keys with 2FA
Combining SSH key authentication with TOTP provides the strongest security.
Disable root login
Set
PermitRootLogin noin/etc/ssh/sshd_configand use sudo for administrative tasks.Secure backup codes
Store emergency codes in a password manager or encrypted storage, not in plaintext.
Regular audits
Periodically review
/var/log/auth.logfor failed authentication attempts.Use Fail2Ban
Deploy Fail2Ban to automatically block IPs with repeated failed login attempts.
Conclusion
Two-factor authentication significantly enhances your server's security by requiring attackers to compromise both your credentials and your physical authenticator device. Combined with strong passwords, SSH key authentication, and regular security updates, 2FA forms an essential layer of your defense-in-depth security strategy.
