When one SSH server handles normal users, backup accounts, automation jobs, and trusted network ranges, one global sshd policy can be too broad. OpenSSH Match blocks let the daemon change selected server settings only for sessions that match a user, group, source address, local address, local port, host name, or server version.
The OpenSSH daemon reads /etc/ssh/sshd_config and any included files before it accepts new sessions. A Match block continues until the next Match line or the end of the file, and if the same keyword is set by more than one satisfied Match block, sshd uses the first matching instance of that keyword. Keep unconditional server settings before the first Match block so they do not become conditional by accident.
Back up the server file, add one focused condition, test syntax with sshd -t, and inspect the effective policy with sshd -T -C before reloading the service. Keep an existing SSH session or console path open until a new login works, especially when changing authentication, forwarding, shell, chroot, or SFTP rules.
Keep a second SSH session or console path open until the changed configuration reloads and the intended login path still works.
$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.match-blocks
$ sudoedit /etc/ssh/sshd_config
Use the local editor required by your environment, but edit the active file that sshd reads.
PasswordAuthentication no PubkeyAuthentication yes
If an active directive already appears earlier in the file or in an included snippet, change that existing directive instead of adding a duplicate below it. For most sshd_config keywords, the first active value wins.
Match User backupuser Address 192.0.2.0/24
PasswordAuthentication yes
DisableForwarding yes
PermitTTY no
Replace backupuser and 192.0.2.0/24 with the account and source network that should receive the exception. All criteria on the Match line must match for the block to apply.
A Match line is not closed with braces. Start another Match block for another condition, or move ordinary global directives above the first Match line.
$ sudo sshd -t
No output means the configuration parsed successfully.
Related: How to test SSH server configuration
$ sudo sshd -T -C user=backupuser,addr=192.0.2.40 port 22 addressfamily any listenaddress [::]:22 listenaddress 0.0.0.0:22 ##### snipped ##### pubkeyauthentication yes passwordauthentication yes ##### snipped ##### permittty no disableforwarding yes ##### snipped #####
sshd -T -C evaluates Match rules without opening a network connection. Add only the fields your rules use, such as user=, addr=, host=, laddr=, lport=, or rdomain=.
Related: How to view SSH server configuration
$ sudo sshd -T -C user=backupuser,addr=203.0.113.10 port 22 addressfamily any listenaddress [::]:22 listenaddress 0.0.0.0:22 ##### snipped ##### pubkeyauthentication yes passwordauthentication no ##### snipped ##### permittty yes disableforwarding no ##### snipped #####
The non-matching output should keep the global policy, which confirms the exception is limited to the intended source range.
$ sudo systemctl reload ssh
Use sudo systemctl reload sshd on distributions that name the unit sshd. Use a restart instead of a reload only when the local service guide or package requires it.
$ sudo systemctl is-active ssh active
$ ssh backupuser@host.example.net 'echo SSH Match policy loaded' backupuser@host.example.net's password: SSH Match policy loaded
Run this smoke test from a client inside the source network used in the Address condition.