How to Log into Any Router from CLI and Automate Config Backups
As developers, we often interact with various systems through the command line. Networks are no exception. While most consumer-grade routers offer a shiny web UI, real power users – and especially those looking to automate – gravitate towards the Command Line Interface (CLI). This guide will walk you through accessing network routers from your Linux/macOS terminal and, critically, how to automate those critical configuration backups.
Forget clicking around; let’s get pragmatic.
Why CLI for Router Management?
- Automation: Automate repetitive tasks, configurations, and backups. Essential for DevOps and SREs.
- Consistency: Ensure identical configurations across multiple devices.
- Speed: Often faster to type a command than navigate multiple web UI menus.
- Troubleshooting: Access to detailed logs and diagnostic tools not always exposed in the web UI.
- Disaster Recovery: A backup of your router’s configuration is paramount for quick recovery.
Let’s dive into the various methods of accessing a router.
1. Understanding Router Access Protocols
Routers speak a few different languages for CLI access. Knowing which to use, and when, is key.
a. SSH (Secure Shell) - The Preferred Standard
SSH is the gold standard for secure remote access. It encrypts all communication, protecting your credentials and configuration data from eavesdropping. Most modern, professional-grade routers (Cisco, Juniper, MikroTik, Ubiquiti, etc.) support SSH.
b. Telnet - The Insecure Legacy
Telnet is an older protocol that transmits all data, including usernames and passwords, in plain text. This makes it highly vulnerable to eavesdropping. Avoid Telnet if SSH is available. It’s typically only found on very old or poorly configured devices. We’ll cover it only out of completeness and necessity when no other option exists.
c. Serial Console - The Lifeline
When things go really wrong (e.g., misconfigured IP, locked out, factory reset), the serial console is your direct, out-of-band access. It requires a physical cable connection (typically a USB-to-serial adapter and a console cable) to a dedicated serial port on the router. This is your “break glass in case of emergency” access.
d. Web UI (Graphical User Interface) - Not CLI
While most consumer routers rely primarily on a Web UI (accessed via http://192.168.1.1
or similar), this guide focuses on CLI methods. Web UIs are fine for basic setup but are generally not conducive to automation or advanced troubleshooting.
Checking for Open Ports with nmap
Before attempting to connect, you can check which ports are open on your router’s IP address using nmap
. The default SSH port is 22, and Telnet is 23.
# Replace 192.168.1.1 with your router's IP address
nmap 192.168.1.1 -p 22,23
Starting Nmap 7.93 ( https://nmap.org ) at 2023-10-27 10:30 PDT
Nmap scan report for _gateway (192.168.1.1)
Host is up (0.0028s latency).
PORT STATE SERVICE
22/tcp open ssh
23/tcp closed telnet
Nmap done: 1 IP address (1 host up) scanned in 0.04 seconds
In this output, port 22 (SSH) is open, and port 23 (Telnet) is closed. Excellent! We should use SSH.
2. Logging In via SSH (The Preferred Way)
To use SSH, you’ll need:
- Your router’s IP address (e.g.,
192.168.1.1
). - A username configured on the router (e.g.,
admin
,root
,cisco
). - The password for that user, or an SSH key.
a. Basic SSH Login (Password-based)
This is the simplest way, but less secure for automation as it typically requires entering a password manually or using sshpass
(which we’ll cover later, with caveats).
# Syntax: ssh <username>@<router_ip>
ssh admin@192.168.1.1
The authenticity of host '192.168.1.1 (192.168.1.1)' can't be established.
ED25519 key fingerprint is SHA256:aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.1.1' (ED25519) to the list of known hosts.
admin@192.168.1.1's password:
RouterOS 7.10.2 (stable)
admin@Router>
Once logged in, the prompt will change, indicating you are now on the router’s CLI. Commands are vendor-specific (e.g., show running-config
on Cisco, print
on MikroTik, status
on UniFi devices).
b. SSH Key-based Authentication (Highly Recommended)
For security and automation, SSH keys are superior. You generate a pair of keys: a private key (kept secret on your local machine) and a public key (uploaded to the router). When connecting, your client uses the private key to prove its identity, and the router verifies it with the public key. No password needs to be sent over the network.
Step 1: Generate an SSH Key Pair
If you don’t have one, generate a strong ED25519 key.
ssh-keygen -t ed25519 -C "your_email@example.com"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/youruser/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/youruser/.ssh/id_ed25519
Your public key has been saved in /home/youruser/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:AbCdEfGhIjKlMnOpQrStUvWxFgHiJkL your_email@example.com
The key's randomart image is:
+--[ED25519 256]--+
| .o*o.. |
| . o=*=. |
| . . =++. |
| . + = E. |
|. . o + . |
|.o o + o |
|==+ o . |
|*o = o |
|o.+. |
+----[SHA256]-----+
- Note: It’s good practice to set a passphrase for your private key, especially if your local machine might be compromised. For automation, you might leave it empty, but be aware of the security implications.
- Your public key will be in
~/.ssh/id_ed25519.pub
.
Step 2: Copy Public Key to Router
This step is router-specific. You’ll usually log in to the router (via its web UI or initial password-based SSH) and paste your id_ed25519.pub
content into the user’s SSH key configuration.
- Cisco IOS/IOS XE:
username <username> privilege 15 secret <password> username <username> sshpubkey-data <paste_your_public_key_here>
- MikroTik RouterOS:
/user ssh-keys add user=<username> public-key="<paste_your_public_key_here>"
- Ubiquiti EdgeRouter/UniFi OS: Usually involves copying the key to
~/.ssh/authorized_keys
for a specific user.
Step 3: Configure SSH Client (Optional but Recommended)
Edit ~/.ssh/config
to simplify connections.
# Open or create the SSH config file
nano ~/.ssh/config
Add an entry like this:
Host myrouter
Hostname 192.168.1.1
User admin
IdentityFile ~/.ssh/id_ed25519
Port 22 # Optional, 22 is default
Now, you can connect using the alias:
ssh myrouter
RouterOS 7.10.2 (stable)
admin@Router>
This is much cleaner and secure.
3. Dealing with Telnet (When You Have No Choice)
As stated, Telnet is insecure. Use it only if:
- It’s the only available method.
- You are on a highly trusted, isolated network.
- You understand the risks.
The command is simple:
telnet 192.168.1.1
Trying 192.168.1.1...
Connected to 192.168.1.1.
Escape character is '^]'.
MikroTik RouterOS 7.10.2
Login: admin
Password:
RouterOS 7.10.2 (stable)
admin@Router>
Once connected, it behaves much like an SSH session, but without encryption.
4. Serial Console Access (The Lifeline)
This method requires physical access and specific hardware:
- USB-to-Serial Adapter: If your computer doesn’t have a built-in serial port (most don’t), you’ll need one. Prolific (PL2303) and FTDI (FT232) chipsets are common.
- Console Cable: Typically an RJ45-to-DB9 (or USB-C to RJ45 for newer routers) cable that connects the router’s console port to your serial adapter.
a. Identifying the Serial Port
On Linux, serial devices usually appear as /dev/ttyUSB0
, /dev/ttyS0
, etc. After plugging in your USB-to-serial adapter, you can check dmesg
:
dmesg | grep tty
[ 10.123456] usb 1-1: pl2303 converter now attached to ttyUSB0
This confirms /dev/ttyUSB0
is our port.
b. Connecting with screen
screen
is a powerful terminal multiplexer that can also be used for serial connections. You’ll need to know the router’s console speed (baud rate), data bits, parity, and stop bits (usually 9600 8N1: 9600 baud, 8 data bits, No parity, 1 stop bit).
# Syntax: screen /dev/ttyUSB0 <baud_rate>
screen /dev/ttyUSB0 9600
(Screen clears, you might see boot messages or a login prompt from the router)
Press Enter to activate the console...
User: admin
Password:
admin@Router>
To exit screen
, press Ctrl+A
then k
, then y
to confirm.
c. Other Tools
minicom
: Another popular serial client for Linux. More configuration options thanscreen
.putty
: Excellent multi-protocol client for Windows, also available on Linux. Has a dedicated Serial section.
5. Automating Configuration Backups
This is where CLI truly shines. Regular configuration backups are essential for disaster recovery, auditing, and change management.
a. Simple SSH + Scripting (Bash)
For basic backups, a simple shell script combined with SSH keys can be highly effective. This assumes the router’s CLI can output the running configuration to standard output.
#!/bin/bash
ROUTER_IP="192.168.1.1"
ROUTER_USER="admin"
BACKUP_DIR="/opt/router_configs"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
CONFIG_FILE="${BACKUP_DIR}/router_config_${TIMESTAMP}.txt"
LOG_FILE="${BACKUP_DIR}/backup.log"
# Ensure backup directory exists
mkdir -p "$BACKUP_DIR"
echo "[$(date)] Starting backup for $ROUTER_IP..." >> "$LOG_FILE"
# Cisco-like command: show running-config
# MikroTik-like command: export compact
# Ubiquiti EdgeRouter: show configuration commands
# Replace 'show running-config' with the appropriate command for your router
ssh -o BatchMode=yes -o StrictHostKeyChecking=no "$ROUTER_USER@$ROUTER_IP" "show running-config" > "$CONFIG_FILE" 2>> "$LOG_FILE"
if [ $? -eq 0 ]; then
echo "[$(date)] Backup successful: $CONFIG_FILE" >> "$LOG_FILE"
echo "Backup successful: $CONFIG_FILE"
else
echo "[$(date)] Backup failed for $ROUTER_IP" >> "$LOG_FILE"
echo "Backup failed. Check $LOG_FILE for details."
fi
# Optional: Keep only the last 7 backups
find "$BACKUP_DIR" -type f -name "router_config_*.txt" -mtime +7 -delete
Explanation:
ssh -o BatchMode=yes
: Prevents SSH from asking for a password, essential for automation. Requires SSH key authentication.-o StrictHostKeyChecking=no
: Use with caution! This bypasses the host key check. Only use if you’ve already manually connected and accepted the host key, or in controlled environments. Better to setStrictHostKeyChecking=yes
and ensure the router’s host key is in~/.ssh/known_hosts
."show running-config"
: The command executed on the router. Change this to your router’s specific command!>
: Redirects the router’s output toCONFIG_FILE
.2>>
: Appends standard error toLOG_FILE
.
Example Usage:
# Save the script as backup_router.sh
chmod +x backup_router.sh
./backup_router.sh
Backup successful: /opt/router_configs/router_config_20231027_104500.txt
Sample Log File (/opt/router_configs/backup.log
):
[Fri Oct 27 10:45:00 PDT 2023] Starting backup for 192.168.1.1...
[Fri Oct 27 10:45:01 PDT 2023] Backup successful: /opt/router_configs/router_config_20231027_104500.txt
b. Automating with cron
You can schedule the above script to run daily or weekly using cron
.
crontab -e
Add the following line to run the script every day at 3:00 AM:
0 3 * * * /path/to/your/backup_router.sh > /dev/null 2>&1
Replace /path/to/your/backup_router.sh
with the actual path to your script.
c. Python with paramiko
(Robust, Cross-Platform)
For more complex interactions, error handling, or when dealing with multiple devices, Python with paramiko
(an SSHv2 protocol implementation) or netmiko
(built on paramiko
, specifically for network devices) is excellent.
First, install paramiko
:
pip install paramiko
Python Script Example (backup_paramiko.py
):
import paramiko
import os
import datetime
ROUTER_IP = "192.168.1.1"
ROUTER_USER = "admin"
# Ensure your SSH private key is correctly specified
PRIVATE_KEY_PATH = os.path.expanduser("~/.ssh/id_ed25519")
BACKUP_DIR = "/opt/router_configs"
# Command to get the running config. Adjust for your router type.
# Cisco: "show running-config"
# MikroTik: "/export compact"
# Juniper: "show configuration | display set"
CONFIG_COMMAND = "show running-config"
def backup_router_config():
if not os.path.exists(BACKUP_DIR):
os.makedirs(BACKUP_DIR)
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
config_file = os.path.join(BACKUP_DIR, f"router_config_{timestamp}.txt")
try:
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # AVOID IN PRODUCTION, use WarningPolicy or known_hosts
# Load the private key
private_key = paramiko.RSAKey.from_private_key_file(PRIVATE_KEY_PATH) # Or paramiko.Ed25519Key, paramiko.ECDSAKey
print(f"Connecting to {ROUTER_IP}...")
ssh_client.connect(hostname=ROUTER_IP, username=ROUTER_USER, pkey=private_key)
print("Connected. Executing command...")
stdin, stdout, stderr = ssh_client.exec_command(CONFIG_COMMAND)
output = stdout.read().decode('utf-8')
errors = stderr.read().decode('utf-8')
if errors:
print(f"Error executing command: {errors}")
return False
with open(config_file, "w") as f:
f.write(output)
print(f"Backup successful: {config_file}")
return True
except paramiko.AuthenticationException:
print("Authentication failed, please check your credentials/key.")
return False
except paramiko.SSHException as e:
print(f"SSH error: {e}")
return False
except Exception as e:
print(f"An unexpected error occurred: {e}")
return False
finally:
if 'ssh_client' in locals() and ssh_client:
ssh_client.close()
if __name__ == "__main__":
backup_router_config()
Note on paramiko.AutoAddPolicy()
: This line will automatically add the router’s host key to your ~/.ssh/known_hosts
file if it’s not already there. While convenient for initial setup, in a production environment, you should use paramiko.WarningPolicy()
(which warns if the key is unknown) or, ideally, pre-populate your known_hosts
file and use ssh_client.load_system_host_keys()
.
Example Usage:
python backup_paramiko.py
Connecting to 192.168.1.1...
Connected. Executing command...
Backup successful: /opt/router_configs/router_config_20231027_105500.txt
d. Python with netmiko
(Network Automation Library)
netmiko
is built on paramiko
but provides a simplified API specifically for interacting with various network device vendors. It handles prompt detection, pagination, and various vendor quirks automatically. This is generally the best choice for network automation in Python.
First, install netmiko
:
pip install netmiko
Python Script Example (backup_netmiko.py
):
from netmiko import ConnectHandler
import os
import datetime
# Device type specifies the vendor and OS (e.g., 'cisco_ios', 'mikrotik_routeros', 'juniper_junos')
# Find the correct device type in Netmiko documentation for your router.
ROUTER_DEVICE_TYPE = "cisco_ios" # or "mikrotik_routeros", "ubiquiti_edgerouter", etc.
ROUTER_IP = "192.168.1.1"
ROUTER_USER = "admin"
PRIVATE_KEY_PATH = os.path.expanduser("~/.ssh/id_ed25519")
BACKUP_DIR = "/opt/router_configs"
# Command to get the running config. Netmiko often has built-in methods too.
# For Cisco, "show running-config" is common. For MikroTik, "/export compact".
CONFIG_COMMAND = "show running-config"
def backup_router_config_netmiko():
if not os.path.exists(BACKUP_DIR):
os.makedirs(BACKUP_DIR)
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
config_file = os.path.join(BACKUP_DIR, f"router_config_{timestamp}.txt")
device = {
"device_type": ROUTER_DEVICE_TYPE,
"host": ROUTER_IP,
"username": ROUTER_USER,
"use_keys": True,
"key_file": PRIVATE_KEY_PATH,
# "password": "your_password_if_not_using_keys", # Use password if not using keys
"global_delay_factor": 2, # Increase for slow devices/connections
}
try:
print(f"Connecting to {ROUTER_IP} ({ROUTER_DEVICE_TYPE})...")
with ConnectHandler(**device) as net_connect:
print("Connected. Executing command...")
output = net_connect.send_command(CONFIG_COMMAND, delay_factor=5) # Add delay_factor for slow devices
# Netmiko can also directly get specific configs
# output = net_connect.send_command("show startup-config") # Example for startup config
# output = net_connect.send_command("show version") # Example for version info
# Or use built-in methods if supported by device type:
# output = net_connect.send_config_from_file(config_file='commands.txt') # For applying configs
# net_connect.save_config() # If you want to save running-config to startup-config
with open(config_file, "w") as f:
f.write(output)
print(f"Backup successful: {config_file}")
return True
except Exception as e:
print(f"An error occurred: {e}")
return False
if __name__ == "__main__":
backup_router_config_netmiko()
Example Usage:
python backup_netmiko.py
Connecting to 192.168.1.1 (cisco_ios)...
Connected. Executing command...
Backup successful: /opt/router_configs/router_config_20231027_110000.txt
netmiko
abstracts away a lot of the complexities of interacting with different network operating systems, making it highly suitable for multi-vendor environments.
6. Version Control for Configurations (Git)
Once you’re regularly backing up configs, version controlling them with Git is the next logical step. This allows you to track changes, see who changed what, and revert to previous versions if needed.
Basic Git Workflow for Router Configs:
# Initialize a Git repository in your backup directory
cd /opt/router_configs
git init
Initialized empty Git repository in /opt/router_configs/.git/
# First commit (optional: add a .gitignore for logs or temporary files)
echo "backup.log" > .gitignore
git add .gitignore
git commit -m "Add .gitignore"
[master (root-commit) 8c4f2b1] Add .gitignore
1 file changed, 1 insertion(+)
create mode 100644 .gitignore
Now, after each successful backup script run, add these lines to your backup script (e.g., backup_router.sh
or within Python):
# After a successful config file creation:
cd "$BACKUP_DIR"
git add "$CONFIG_FILE"
git commit -m "Automated backup for $(basename "$CONFIG_FILE")"
# Optional: Push to a remote Git repository (e.g., GitHub, GitLab, private server)
# git push origin master
Example of the Bash script (updated section):
# ... (previous script content) ...
if [ $? -eq 0 ]; then
echo "[$(date)] Backup successful: $CONFIG_FILE" >> "$LOG_FILE"
echo "Backup successful: $CONFIG_FILE"
# Git Integration
cd "$BACKUP_DIR"
git add "$CONFIG_FILE"
git commit -m "Automated backup for $ROUTER_IP - ${TIMESTAMP}" >> "$LOG_FILE" 2>&1
echo "[$(date)] Config committed to Git." >> "$LOG_FILE"
else
# ... (error handling) ...
fi
# ... (rest of the script) ...
Checking Git History:
cd /opt/router_configs
git log --oneline
2a1b3c4 (HEAD -> master) Automated backup for 192.168.1.1 - 20231027_110000
9d8e7f6 Automated backup for 192.168.1.1 - 20231027_105500
8c4f2b1 Add .gitignore
You can now easily see what changed between backups:
git diff HEAD~1 HEAD
diff --git a/router_config_20231027_105500.txt b/router_config_20231027_110000.txt
index a1b2c3d..e4f5g6h 100644
--- a/router_config_20231027_105500.txt
+++ b/router_config_20231027_110000.txt
@@ -10,4 +10,5 @@
interface Ethernet0/1
ip address 192.168.10.1 255.255.255.0
!
-route 0.0.0.0 0.0.0.0 192.168.1.254
+route 0.0.0.0 0.0.0.0 192.168.1.254 name DefaultRoute
+! A new comment added to config
This makes managing router configurations just like managing code – a powerful paradigm shift for network operations.
Conclusion
Mastering CLI access to your network devices is a fundamental skill for any developer or operations professional. It unlocks capabilities far beyond what a typical web UI offers, especially when it comes to automation.
By leveraging SSH (with keys!), scripting with Bash or Python (paramiko
, netmiko
), and integrating with version control like Git, you can transform your network management from a manual chore into a robust, automated, and auditable process. Start small, understand your router’s specific commands, and scale up from there. Happy networking!