Restricting SSH logins by source IP address reduces exposure on servers that should accept remote administration only from a fixed office range, a VPN pool, or a bastion host. Narrowing the login path helps keep broad internet authentication attempts away from systems that do not need them.

The OpenSSH server applies IP-based login restrictions through AllowUsers and DenyUsers patterns written as USER@HOST. The HOST portion can be a single address or a CIDR range such as 198.51.100.0/24, and current Debian and Ubuntu packages load /etc/ssh/sshd_config.d/*.conf at the start of /etc/ssh/sshd_config, so a dedicated drop-in file can override older settings cleanly.

A wrong access rule can lock out new remote sessions immediately, so keep the current shell open until a separate login test succeeds from both an allowed and a blocked source. Prefer explicit administrator accounts over wide * patterns, validate the configuration with sshd -t before any reload, and move to Match Address blocks when different networks need different authentication behavior instead of one shared allow or deny list.

Steps to allow or deny SSH access by IP address:

  1. Open a terminal on the SSH server with an account that can use sudo, and keep that session open until a second login test succeeds.
    $ whoami
    user

    Do not close the current administrative session until both the allowed and blocked connection tests behave as expected.

  2. Record the client IP address that must keep working after the policy change.
    $ echo "$SSH_CONNECTION"
    198.51.100.44 60320 203.0.113.10 22

    The first value in $SSH_CONNECTION is the client IP address seen by sshd. Use that exact address or the corresponding VPN or office CIDR when building the allow rule.

  3. Check whether the server already loads SSH configuration snippets from /etc/ssh/sshd_config.d/.
    $ sudo grep -n '^Include' /etc/ssh/sshd_config
    12:Include /etc/ssh/sshd_config.d/*.conf

    If the host uses that include line, keep the IP policy in a dedicated file such as /etc/ssh/sshd_config.d/60-ip-access.conf. If no include is present, place the same directives near the end of /etc/ssh/sshd_config instead.

  4. Open the file that will hold the IP-based access rules.
    $ sudo vi /etc/ssh/sshd_config.d/60-ip-access.conf
  5. Add the allow and deny entries that should control remote SSH access by source address.
    # Allow approved administrator accounts from the office VPN
    AllowUsers admin@198.51.100.0/24 backupuser@198.51.100.0/24
     
    # Block one source explicitly even if another rule would otherwise allow it
    DenyUsers admin@203.0.113.45

    OpenSSH processes DenyUsers before AllowUsers, so a matching deny rule wins even when the same account also appears in an allow rule.

    Use exact administrator accounts first. Replace the user name with * only when the address restriction should apply to every SSH-capable account, for example *@198.51.100.0/24.

  6. Test the SSH daemon configuration before reloading the service.
    $ sudo sshd -t

    No output means the full configuration parsed successfully.

  7. Inspect the resolved AllowUsers and DenyUsers entries after drop-ins and defaults are merged.
    $ sudo sshd -T | grep -E '^(allow|deny)users'
    allowusers admin@198.51.100.0/24
    allowusers backupuser@198.51.100.0/24
    denyusers admin@203.0.113.45

    sshd -T shows the runtime configuration that will be applied to new connections. Multiple values from one directive appear as separate lines.

  8. Reload the SSH service so the new source-address policy applies to new sessions.
    $ sudo systemctl reload ssh

    Use sudo systemctl reload sshd on systems where the service unit is named sshd instead of ssh. If the unit does not support reload, fall back to a restart only after the syntax test succeeds.

  9. Confirm that the SSH service is still active after the reload.
    $ sudo systemctl is-active ssh
    active

    If the command does not return active, inspect the journal before attempting another login change or closing the original session.

  10. From a source address that should be allowed, open a new SSH session and confirm that the login succeeds.
    $ ssh admin@host.example.net 'whoami'
    admin
  11. From a source address that should be blocked, open a separate new SSH session and confirm that the server refuses the login.
    $ ssh admin@host.example.net 'whoami'
    admin@host.example.net: Permission denied (publickey).

    Use a second network path, a VPN exit, or a bastion whose source IP matches the deny rule or falls outside the allow list. The exact client error text can vary with the enabled authentication methods, but the new login should be rejected. Existing sessions usually stay connected until they disconnect, so always verify with a new login attempt.