SecurityAugust 4, 20265 min read

How to Add Two-Factor Authentication to SSH

Add a time-based one-time code on top of your SSH key for defence in depth. Set up Google Authenticator PAM without locking yourself out.

NBy Nxeon

For high-value servers, an SSH key alone may not be enough โ€” if the key leaks, it's game over. Two-factor authentication (2FA) adds a rotating six-digit code from your phone, so an attacker needs both your key and your device. This guide sets up TOTP-based 2FA using the Google Authenticator PAM module.

How SSH 2FA works

You'll combine two factors: something you have (your SSH key) and something you generate (a time-based one-time password, or TOTP). The server runs a PAM module that checks the code from an authenticator app like Google Authenticator, Authy, or Aegis.

Step 1: install the PAM module

On Ubuntu/Debian:

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

Step 2: run the setup wizard as your user

Run the tool as the user who will log in โ€” not root. It generates a secret and QR code:

google-authenticator

Answer the prompts:

  • Time-based tokens: yes
  • Scan the QR code into your authenticator app
  • Save the emergency scratch codes somewhere safe โ€” they're your backup if you lose your phone
  • Update the .google_authenticator file: yes
  • Disallow multiple uses: yes
  • Rate limiting: yes

{{SCREENSHOT}}

Step 3: tell PAM to require the code

Edit /etc/pam.d/sshd. Add this line at the top:

auth required pam_google_authenticator.so

To require a code only after key auth (recommended), you'll also adjust sshd_config below. If you want to keep password + code working for accounts without 2FA set up, add nullok to the line: auth required pam_google_authenticator.so nullok.

Step 4: configure sshd to demand both factors

Edit /etc/ssh/sshd_config:

KbdInteractiveAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
UsePAM yes

AuthenticationMethods publickey,keyboard-interactive means a user must present a valid key first, then a valid TOTP code. This is the strongest common setup.

Step 5: validate and reload carefully

Keep your current session open. Validate then reload:

sudo sshd -t && sudo systemctl reload ssh

Open a new terminal and log in. You should authenticate with your key, then be prompted for a verification code. Only after this works should you close your original session.

Don't lock out automation

Automated deploys and CI can't type a TOTP code. Exempt them by IP or user. For example, skip 2FA for connections from your CI's IP by wrapping the PAM line with pam_access, or keep a dedicated key-only user restricted by firewall. Plan this before you roll 2FA out fleet-wide.

Layer it with the rest

2FA sits on top of the fundamentals. Make sure you've already done SSH key auth, disabled root login, and set up fail2ban and a firewall.

Hardware keys: an even stronger second factor

TOTP codes are excellent, but a hardware security key (a YubiKey or any FIDO2/U2F device) is stronger still, because the secret never leaves the physical device and there's nothing to phish. Modern OpenSSH supports this natively through ed25519-sk keys:

ssh-keygen -t ed25519-sk -C "yubikey"

You'll be asked to touch the key to confirm. The resulting key requires the physical device present to authenticate, so a stolen private key file alone is useless. For servers you truly care about, a hardware key as the "something you have" factor is the gold standard, and it removes the friction of typing a code on every login.

Planning for scale

Setting up 2FA on one server is simple; rolling it across a fleet needs a plan. A few things to decide up front:

  • Which accounts need it. Human logins, yes. Service and deploy accounts usually can't type a code, so exempt them by user or restrict them tightly by firewall and key instead.
  • Backup access. Store the emergency scratch codes somewhere central and secure, and make sure at least one administrator can reach the provider's console to recover a locked-out box.
  • Onboarding. New team members run google-authenticator once as their user; document it so it isn't a mystery.

Treat 2FA as one layer among several. It dramatically raises the cost of a stolen key, but it works best on top of key-only auth, no root login, a firewall, and fail2ban โ€” defence in depth, not a single magic switch. Reviewed together, those layers make a compromise require several independent failures at once.

FAQ

What happens if I lose my phone?

Use one of the emergency scratch codes you saved during setup, or log in via your host's web console and remove the ~/.google_authenticator file. Always store the scratch codes offline.

Does 2FA slow down every login?

It adds one six-digit code per new session. With an SSH agent and connection multiplexing, the friction is minimal for day-to-day work.

Can I require 2FA only for some users?

Yes. With nullok in the PAM config, users without a configured secret skip the code, while users who ran google-authenticator must provide one.

Is TOTP better than SMS codes?

Yes. TOTP apps work offline and aren't vulnerable to SIM-swapping or intercepted texts. Avoid SMS-based 2FA where possible.

Rollout checklist

Enabling 2FA safely comes down to a handful of careful steps:

  • Install libpam-google-authenticator and run google-authenticator as your user (not root).
  • Save the emergency scratch codes offline โ€” they're your way back in if you lose your phone.
  • Add auth required pam_google_authenticator.so to /etc/pam.d/sshd.
  • Set AuthenticationMethods publickey,keyboard-interactive in sshd_config to require key *and* code.
  • Validate with sudo sshd -t, reload, and confirm the two-step login in a fresh session before closing your working one.
  • Exempt automation and CI accounts that can't type a code, by user or firewall.

The recurring theme is the same as every SSH change: keep a working session open, test the new path fully, and know your console fallback exists. Do that, and adding a second factor carries no risk of locking yourself out while dramatically raising the bar for anyone who steals a key.

Two-factor SSH turns a stolen key into a dead end. Build it on a VPS where you control the whole stack โ€” see Nxeon VPS hosting and our security overview.

#2fa#ssh#totp#security#vps#seobatch

Deploy your first server in under a minute

Creating an account is free and takes no card details. You pay when you deploy โ€” choose a billing term and pay from your wallet or by card at checkout.