How to Enable SSH on Cisco Routers and Switches

Enabling SSH on a Cisco router or switch takes a hostname, domain name, RSA keys (3072-bit minimum on current IOS XE), a local user, and vty line login. Full config plus real verification output.

How to Enable SSH on Cisco Routers and Switches - PingLabz Fundamentals article title card

SSH is how you manage Cisco gear remotely without sending credentials in cleartext. Enabling it takes five pieces of configuration: a hostname, a domain name, an RSA key pair, a local user, and vty lines locked to SSH. This guide walks through all five on IOS XE, with every output line captured from a live device (IOS XE 17.18 in our CML lab), then covers verification, restricting access with an ACL, and the errors you will actually hit.

One thing most guides still get wrong: modern IOS XE requires a 3072-bit RSA key minimum to enable the SSH server. The old "2048 bits is fine" advice no longer applies. More on that below.

Prerequisites

  • Console access to a Cisco router or switch running IOS or IOS XE
  • Privileged EXEC (enable) access
  • An IP address on the device that your management station can reach

Check the Starting State

Before configuring anything, show ip ssh tells you exactly what is missing. On a fresh device:

R1# show ip ssh
SSH Disabled - version 2.0
%Please create an RSA key of atleast 3072 bits or an EC key of
atleast 384 bits to enable SSH server functionality
Authentication methods:publickey,keyboard-interactive,password
! (algorithm list trimmed)
Authentication timeout: 120 secs; Authentication retries: 3
IOS Keys in SECSH format(ssh-rsa, base64 encoded): NONE

That message (typo and all - it really prints "atleast") is IOS XE telling you the modern key-size floor: 3072-bit RSA or 384-bit EC. A 2048-bit key that worked on older code will not enable the SSH server on current IOS XE.

Step-by-Step Configuration

1. Set the Hostname and Domain Name

The RSA key pair is named after hostname.domain, so both must exist before you generate keys:

Router> enable
Router# configure terminal
Router(config)# hostname R1
R1(config)# ip domain name pinglabz.lab

2. Generate the RSA Key Pair

Generate a 3072-bit pair (the minimum on current IOS XE; 4096 also works if you can spare the CPU during generation):

R1(config)# crypto key generate rsa modulus 3072
%This command is deprecated.  Use the command in exec mode instead
The name for the keys will be: R1.pinglabz.lab

% The key modulus size is 3072 bits
% Generating 3072 bit RSA keys, keys will be non-exportable...
[OK] (elapsed time was 2 seconds)

Two things worth noticing in that real output. First, the keys generate fine either way, but IOS XE now flags the config-mode form as deprecated - on 17.x you can run crypto key generate rsa modulus 3072 straight from privileged EXEC instead. Second, there is no "How many bits in the modulus [512]" prompt when you specify modulus on the command line, which is why scripts and automation always use this form.

3. Create a Local User Account

R1(config)# username admin privilege 15 secret Pinglabz123

Use secret, not password - secret stores a salted hash, while password stores the string in a reversible format.

4. Configure the VTY Lines

R1(config)# line vty 0 4
R1(config-line)# transport input ssh
R1(config-line)# login local
R1(config-line)# exit

transport input ssh kills Telnet on those lines at the same time (if anything still connects to this device over Telnet, it stops working the moment you apply this - which is usually the point).

5. Force SSH Version 2

R1(config)# ip ssh version 2

SSHv1 has known protocol weaknesses. Current IOS XE negotiates version 2 anyway, but pinning it makes the config explicit and keeps auditors happy.

Verify the Configuration

Run show ip ssh again:

R1# show ip ssh
SSH Enabled - version 2.0
Authentication methods:publickey,keyboard-interactive,password
! (algorithm list trimmed)
Authentication timeout: 120 secs; Authentication retries: 3
Minimum expected Diffie Hellman key size : 2048 bits
IOS Keys in SECSH format(ssh-rsa, base64 encoded): R1.pinglabz.lab
Modulus Size : 3072 bits

SSH Enabled - version 2.0 plus a named key pair is what you want to see. Then save:

R1# write memory
Building configuration...
[OK]

Connect from a Client

Linux, macOS, and modern Windows (PowerShell on Windows 10/11) all ship OpenSSH, so the client side is one command everywhere:

$ ssh admin@10.78.10.1

Enter the password from step 3 and you land at the R1# prompt. OpenSSH can also run a single command remotely, which is handy for scripted checks. Here is a real session from a Linux host in our lab, asking the router who is connected:

$ ssh admin@10.78.10.1 show users
    Line       User       Host(s)              Idle       Location
   0 con 0                idle                 00:00:10
*  2 vty 0     admin      idle                 00:00:00 10.78.10.50

The asterisk marks our own SSH session on vty 0, coming from 10.78.10.50. On the router side, show ssh shows the same session with its negotiated ciphers:

R1# show ssh
Connection Version Mode  Encryption   Hmac                          State            Username
0          2.0     IN    chacha20-pol hmac-sha2-256-etm@openssh.com Session started  admin
0          2.0     OUT   chacha20-pol hmac-sha2-256-etm@openssh.com Session started  admin

If PuTTY is your tool of choice on Windows, it works the same way: host = the device IP, port 22, connection type SSH.

Restrict Who Can SSH In

An open SSH port on every interface is an invitation. Lock the vty lines to your management subnets with a standard ACL:

R1(config)# access-list 10 remark SSH-MGMT-ONLY
R1(config)# access-list 10 permit 10.78.0.0 0.0.0.255
R1(config)# line vty 0 4
R1(config-line)# access-class 10 in

Anything outside the permitted range is rejected before authentication even starts. From a host in a subnet the ACL does not permit:

$ ssh admin@10.78.10.1
ssh: connect to host 10.78.10.1 port 22: Connection refused

That instant "Connection refused" (rather than a password prompt) is the signature of an access-class block. Add the missing subnet to the ACL and the same host connects normally.

Hardening Checklist

Once SSH works, tighten it:

R1(config)# ip ssh time-out 60
R1(config)# ip ssh authentication-retries 2
R1(config)# login block-for 120 attempts 3 within 60
  • ip ssh time-out caps how long an unauthenticated connection can sit in negotiation (default 120 seconds).
  • ip ssh authentication-retries cuts the password guesses per connection from 3 to 2.
  • login block-for locks the login process for 120 seconds after 3 failed attempts within a minute - cheap brute-force protection.

The finished vty section should look like this (show run | section line vty):

line vty 0 4
 access-class 10 in
 login local
 transport input ssh

Troubleshooting

SSH refuses to enable

show ip ssh says "SSH Disabled" and asks for a key: you have no RSA key pair, or it is smaller than 3072 bits on current IOS XE. Generate a new one (step 2). If crypto key generate rsa complains about the key name, set the domain name first - no ip domain name, no keys.

Connection refused

Either an access-class ACL on the vty lines is rejecting your source address (see above), or SSH never enabled - check show ip ssh first.

Password rejected or immediately disconnected

Confirm login local is on the vty lines and the username exists with secret. If the vty lines still have a line password and plain login, the router expects the line password rather than your user account.

Old client or server cannot negotiate

Very old IOS speaks only legacy key-exchange and ssh-rsa signatures that modern OpenSSH disables by default. You will see algorithm-mismatch errors on connect. Client-side workarounds exist (-oKexAlgorithms=+diffie-hellman-group14-sha1 and friends), but the right fix is upgrading the IOS side.

Key Takeaways

  • Five steps enable SSH: hostname, ip domain name, RSA keys, a local user with secret, and transport input ssh + login local on the vty lines.
  • Current IOS XE requires a 3072-bit RSA key minimum - show ip ssh tells you this on a fresh box, and older 2048-bit guidance is out of date.
  • crypto key generate rsa modulus 3072 runs without interactive prompts, and on 17.x lives in exec mode (the config-mode form still works but is deprecated).
  • Verify with show ip ssh (server state) and show ssh (live sessions).
  • Restrict sources with access-class on the vty lines - a blocked client sees "Connection refused" before any password prompt.

More Cisco admin how-tos: Essential Cisco Commands Cheat Sheet and How to Configure HTTP Method on a Cisco Switch.

Read next