Disabling Direct Root SSH Login Across Multiple Servers
Part of my #DevOpsFromZero series — documenting real KodeCloud tasks with the commands, the reasoning, the mistakes, and the principles behind every decision.
The Task
Disable direct SSH root login on all app servers within the Stratos Datacenter.
Three servers. One security change. Higher stakes than anything so far.
Why Does This Matter?
Disabling root SSH login reduces the risk of a complete server takeover.
The root account is like a hotel manager's master access card: it can open every room, office, storage area, and security room. Allowing root to log in directly is like letting someone request that master card at the front desk. If an attacker gets it, they immediately have access to everything.
By disabling direct root SSH login, you force anyone who needs elevated privileges to:
Log in as a named user first
Escalate via
sudoonly when needed
This creates an audit trail — you know who did what and when. Direct root login leaves none of that.
Understanding SSH Configuration
Before touching any server, it's worth understanding where SSH gets its configuration from — because there are two distinct sides to SSH:
| Component | Binary | Config File | Purpose |
|---|---|---|---|
| Client | ssh |
/etc/ssh/ssh_config |
How you connect to other servers |
| Daemon | sshd |
/etc/ssh/sshd_config |
How your server accepts incoming connections |
This task is about the daemon — you're changing how the server accepts connections. That means sshd_config is the file you need.
The Infrastructure
Three app servers in the Nautilus project environment:
| Server | Hostname | SSH User |
|---|---|---|
| App Server 1 | stapp01 |
tony |
| App Server 2 | stapp02 |
steve |
| App Server 3 | stapp03 |
banner |
Step-by-Step: What I Did
The process is identical on all three servers. Here it is, using stapp01 as the example.
1. Connect to the Server
ssh tony@stapp01
2. Check the Current State
Before making any change, check what's already in the file:
sudo grep PermitRootLogin /etc/ssh/sshd_config
On stapp01, this returned:
#PermitRootLogin no
# the setting of "PermitRootLogin without-password".
PermitRootLogin yes
Two things stand out here:
There's a commented-out line (
#PermitRootLogin no) — this is ignored by the daemonThere's an active line (
PermitRootLogin yes) — this is what the daemon is actually reading
Root login is currently enabled. That's what needs to change.
3. Edit sshd_config
sudo nano /etc/ssh/sshd_config
Find the active PermitRootLogin line and change it to:
PermitRootLogin no
Save and exit (Ctrl+X, Y, Enter).
4. Verify the Change
sudo grep PermitRootLogin /etc/ssh/sshd_config
Expected output:
#PermitRootLogin prohibit-password
# the setting of "PermitRootLogin without-password".
PermitRootLogin no
The active line now says no. The commented lines above are irrelevant — only the uncommented line is read by the daemon.
5. Reload the SSH Daemon
sudo systemctl reload sshd
⚠️ This step is not optional. See the mistakes section below.
6. Exit and Repeat
exit
Repeat steps 1–5 for stapp02 (as steve) and stapp03 (as banner).
restart vs reload — Which One and Why?
Both apply config changes, but they behave differently:
| Command | What It Does | Risk |
|---|---|---|
systemctl restart sshd |
Stops and starts the service completely | Drops all active SSH sessions |
systemctl reload sshd |
Re-reads config without stopping the service | Safe — existing sessions stay alive |
In production, it is safe to always prefer reload for SSH. Restarting drops active connections — including potentially your own.
The Mistakes
1. Forgetting to Reload After Saving
I edited sshd_config on stapp01, verified the file looked correct, exited, and moved on. The validation check failed — root login was still enabled.
The file was correct. The running daemon was not. It was still operating on the old configuration because I never told it to reload.
💡 A configuration change is not real until the running service has loaded it.
This applies everywhere — nginx, Kubernetes, systemd services, application configs. Editing a file and saving it does nothing to a running process until that process re-reads it.
2. Confusing ssh_config and sshd_config
SSH has both a client config and a daemon config, living side by side in /etc/ssh/. Early on it's easy to reach for ssh_config when you mean sshd_config. The distinction matters:
ssh_config→ how you connect outsshd_config→ how your server lets others connect in
When in doubt: if you're hardening a server, you want sshd_config.
Key Concepts Recap
| Concept | What It Means |
|---|---|
PermitRootLogin no |
Directive in sshd_config that blocks direct root SSH access |
sshd_config |
Server-side SSH daemon configuration file |
ssh_config |
Client-side SSH configuration file |
systemctl reload sshd |
Re-reads config without dropping active connections |
Commented line (#) |
Ignored by the daemon — only active lines are read |
| Audit trail | Named user logins via sudo create traceable records; root login does not |
Closing Thought
Day 1: Not every mistake requires deletion — modify deliberately. Day 2: No error doesn't mean correct behaviour — always verify. Day 3: A configuration change is not real until the running service has loaded it.
#DevOpsFromZero #100DaysOfDevOps #Linux #SSH #Security #DevOps #KodeCloud #Beginner

