VPS DeploymentBeginner 12 min Lesson 7 of 30

SSH Keys on the Server

Install your key, disable password authentication, and add a separate deployment key that can be revoked independently.

VPS Deployment · Lesson 7 of 30
0/30 done(0%)

What is it? #

With a non-root user in place, the next step is making keys the only way in.

Password authentication on a public server is under constant automated attack. Disabling it does not make attacks less frequent; it makes them all fail immediately.

Alongside your personal key, a deployment key for automation is worth setting up separately, so it can be rotated or revoked without touching anyone's personal access.

The pattern is the same as the Linux SSH keys lesson, applied to a real server with the lockout precautions that matter.

Think of it like this #

Replacing a combination lock with a key lock and then removing the keypad entirely.

Anyone can still try the door. Without a keypad there is nothing to guess.

Simple example #

Your key is installed for the deploy user, a separate CI key is added with restricted permissions, password authentication and root login are disabled, and you verify all of it before closing your session.

Code #

BASH
# From your laptop: install your key on the server
ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]
ssh [email protected]          # must work without a password prompt

# A separate key for automation (generate on the CI machine, not the server)
ssh-keygen -t ed25519 -C "ci-deploy" -f ~/.ssh/ci_deploy -N ""
# Add the public key to the server's authorized_keys as a second line
TEXT
# /home/deploy/.ssh/authorized_keys — one key per line, with restrictions
ssh-ed25519 AAAAC3Nza...ravi ravi@laptop

restrict,pty,from="198.51.100.0/24" ssh-ed25519 AAAAC3Nza...ci ci-deploy
#   restrict  : disables forwarding and other features by default
#   pty       : still allow an interactive terminal
#   from=     : this key only works from the CI network
BASH
# Harden sshd — but keep your current session open
sudo tee /etc/ssh/sshd_config.d/10-hardening.conf > /dev/null <<'CONF'
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
AllowUsers deploy
CONF

sudo sshd -t                        # validate the configuration
sudo systemctl reload sshd

# Verify from a NEW terminal before closing the old one
ssh [email protected] "echo ok"
ssh [email protected]               # must now be refused
BASH
# Confirm passwords really are refused
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no \
    [email protected]
# Expected: Permission denied (publickey).
TEXT
Key management over time

one key per person       so access can be removed individually
one key per system       CI, backup jobs, monitoring — each revocable alone
restrictions             from= and command= limit what a key can do
rotation                 replace keys when people leave or a laptop is lost
no shared keys           a shared key cannot be revoked without disrupting everyone

How it works #

ssh-copy-id appends your public key to the remote authorized_keys and sets the correct permissions. Doing it manually works too, but the permissions are the part people get wrong.

Each line in authorized_keys is an independent credential. Removing a line revokes exactly that access, which is why one key per person and per system matters.

The restrict option disables agent forwarding, port forwarding and X11 by default, then pty re-enables only the terminal. For a CI key that runs commands, that is the right surface.

from= limits a key to a source network. Even if the private key leaked, it would be unusable outside that range — a strong control for automation keys with predictable source addresses.

Putting the hardening in a file under sshd_config.d keeps it separate from the distribution's default file, so package upgrades do not overwrite or conflict with it.

sshd -t validates before reload, and testing from a new terminal while the old one stays open is the standard precaution. A syntax error plus a reload on a remote machine with no console is a genuinely bad afternoon.

The explicit password test confirms the change took effect rather than assuming it did.

Real-world use #

Servers with password authentication see thousands of login attempts daily. With keys only, those attempts fail at the protocol level and cost nothing.

Deployment keys with from= and command= restrictions are standard in CI setups. A key that can only run one specific command from one network is a small target.

Key rotation is an operational habit rather than a one-off task. When someone leaves, their line comes out of every authorized_keys — which is much easier when those files are managed by configuration rather than edited by hand.

Some organisations move to SSH certificates, where a short-lived certificate is signed by a trusted authority. Access then expires automatically instead of requiring file edits across every server.

Never store a private key on the server itself. Keys belong on the machines that initiate connections; a private key on a server is one compromise away from access to everything it can reach.

Common mistakes #

  • Disabling password authentication before verifying key login from a new session.
  • Sharing one key between people and automation, so it cannot be rotated.
  • Storing a private key on the server.
  • Editing the distribution sshd_config directly and losing changes on upgrade.
  • Never removing keys belonging to people who have left.

Practice #

Install your key for the deploy user, add a second restricted key for automation with a from= restriction, then disable password and root login. Verify from a new session, and confirm explicitly that a password attempt is refused.

Quick quiz

  1. 1. What does disabling PasswordAuthentication achieve?

  2. 2. Why use a separate key for CI?

  3. 3. What does `from="198.51.100.0/24"` do in authorized_keys?

  4. 4. Why put hardening in sshd_config.d rather than the main file?

  5. 5. Should a private key ever be stored on the server?

Summary

  • Install keys, then disable password and root login.
  • One key per person and per system, each independently revocable.
  • Use restrict, pty and from= to limit automation keys.
  • Validate with sshd -t and verify from a new session before closing the old one.
  • Private keys never belong on the server.