Prerequisites
- SSH key authentication already configured (to prevent lockout)
- Google Authenticator or Authy installed on your smartphone
- Keep a separate test SSH session open while you proceed
1. Install the PAM module
Bash
# Ubuntu / Debian
sudo apt update && sudo apt install -y libpam-google-authenticator
# CentOS / RHEL
sudo yum install -y epel-release
sudo yum install -y google-authenticator2. Per-user OTP initialization
Each user must run this themselves.
Bash
google-authenticatorAnswer the prompts as follows:
- Time-based tokens? → y (TOTP recommended)
- Scan the QR code → scan with your smartphone app
- Emergency scratch codes → store them in a safe place
- Update the file? → y
- Allow multiple uses (within 30 seconds)? → n (prevent reuse)
- Allow time skew (±1 minute)? → y
- Rate limiting? → y (limit to 3 attempts per 30 seconds)
3. PAM configuration
Bash
sudo nano /etc/pam.d/sshdAdd at the top of the file:
CODE
# 2FA — OTP required (also required for key-authenticated users)
auth required pam_google_authenticator.so
# Or skip OTP when key authentication succeeds (optional)
# auth [success=done default=ignore] pam_google_authenticator.so nullok4. Configure sshd_config
Bash
sudo nano /etc/ssh/sshd_configCODE
# Enable keyboard-interactive authentication
ChallengeResponseAuthentication yes
# Or (OpenSSH 8.7+)
KbdInteractiveAuthentication yes
# Password + OTP combination
UsePAM yes
# Authentication methods: require both publickey and keyboard-interactive
AuthenticationMethods publickey,keyboard-interactive
# To use password + OTP only:
# AuthenticationMethods keyboard-interactiveBash
# Validate the configuration
sudo sshd -t
# Restart
sudo systemctl restart sshd5. Test the connection
Do not close your current session — test from a new terminal.
Bash
ssh user@server
# Verification code: (enter the 6-digit code from the app)Emergency access — logging in without OTP
If you lose your smartphone, enter one of the emergency scratch codes saved during setup in the OTP prompt. Each code can be used only once.
Bash
# Check emergency codes in ~/.google_authenticator (requires direct server access)
cat ~/.google_authenticatorExempt specific users from 2FA
CODE
# /etc/pam.d/sshd
auth [success=1 default=ignore] pam_succeed_if.so user in ci-runner:deploy
auth required pam_google_authenticator.soEditorial note
AI tools may assist drafting. Check the evidence in each guide for whether commands were run and which environment was used. Confirm the current docs for your version before applying instructions, and email us about errors. email us
Topic-related official docs (auto-linked · not per-claim sources)Linux man pages ↗OWASP documentation ↗
Questions & answers
Ask a question about this guide. We'll review and reply.