preloader
post-thumb

Last Update: April 6, 2026


BYauthor-thumberic

|Loading...

Keywords

The Goal

We have an old Cisco 1941/K9 sitting on the shelf as a backup router. The main router — another Cisco 1941 — is handling NAT, DHCP, and internet access for a home office LAN on 192.168.8.0/24. The ISP provides both IPv4 (DHCP) and IPv6 (native, with a /48 delegation).

It's important to note that the Cisco 1941 is now quite outdated hardware and is no longer supported by Cisco. If your budget allows, you should definitely look into upgrading to a newer model. However, for a home office environment, if managed properly, these devices are absolute warhorses. They remain relatively safe, highly stable, and can still perform significantly better than most consumer-grade routers currently on the market.

The plan:

  1. Access the backup router's console via a serial cable from an Alpine Linux machine (alpine)
  2. Pull the running config from the main router
  3. Add IPv6 (SLAAC + DHCPv6 for LAN clients)
  4. Push the full config to the backup router over serial
  5. Verify internet works through the backup router before doing the physical swap

The Setup

ISP (IPv4 DHCP + IPv6 /48)
        |
   [Backup Cisco 1941]  ← Gi0/1 (WAN)
   192.168.8.1          ← Gi0/0 (LAN)
        |
   [alpine - Alpine Linux]  ← eth1 (192.168.8.2, connected to backup router)
   192.168.8.99         ← eth0 (connected to main router)
        |
   [Main Cisco 1941]
   192.168.8.1

alpine also has a DB9 serial cable going to the backup router's console port (/dev/ttyS0).

Step 1: Console Access via Serial

Modern SSH clients don't support SSHv1, so until we configure SSHv2, serial console is our only way in. Alpine Linux has screen which works perfectly for this.

bash
# Start a detached screen session on the console port
sudo screen -dmS cisco /dev/ttyS0 9600

# Attach to it
sudo screen -r cisco

The Cisco console defaults are 9600 baud, 8N1 — no need to change anything.

Sending a Break Signal for ROMmon

Getting to rommon> requires sending a break signal within 60 seconds of power-on. The trick is to automate this so timing isn't an issue — fire the break loop, then power-cycle the router:

bash
# Send break every second for 60 seconds
for i in $(seq 1 60); do
  sudo screen -S cisco -X break
  sleep 1
done

Power-cycle the router as soon as the loop starts. When it works, you'll see:

rommon 1 >

Step 2: Pulling the Main Router's Config

The main router is running SSHv1 (Cisco IOS default). Modern OpenSSH 8.0+ dropped SSHv1 entirely, so a standard ssh command will fail:

Protocol major versions differ: 2 vs. 1

The fix: run an old Ubuntu 14.04 container which ships with OpenSSH 6.6 — the last version to support SSHv1.

bash
docker run --rm -it --network host ubuntu:14.04 bash

Inside the container:

bash
apt-get update && apt-get install -y openssh-client sshpass
sshpass -p 'yourpassword' ssh -1 -o StrictHostKeyChecking=no \
  [email protected] 'show running-config'

Save the output — this is your baseline config to replicate on the backup router.

Step 3: Building the Config with IPv6

The main router config becomes the template. The key additions for IPv6:

Enable IPv6 Routing

ipv6 unicast-routing
ipv6 cef

DHCPv6 Pool for LAN Clients

ipv6 dhcp pool LAN-V6
 dns-server 2001:4860:4860::8888
 dns-server 2001:4860:4860::8844
 domain-name yourdomain.com

WAN Interface (Gi0/1)

interface GigabitEthernet0/1
 ip address dhcp
 ip nat outside
 ip virtual-reassembly in
 ipv6 address dhcp
 ipv6 address autoconfig default
 ipv6 enable
 ipv6 dhcp client pd ISP_PREFIX
 no shutdown
  • ipv6 address dhcp — requests a WAN IPv6 address from the ISP via stateful DHCPv6
  • ipv6 address autoconfig default — accepts SLAAC prefix and installs a default route via RA
  • ipv6 dhcp client pd ISP_PREFIX — requests a delegated prefix (IA-PD); the ISP assigns a /48 (e.g. 2403:580c:d9d4::/48) which is bound to the label ISP_PREFIX

If DHCPv6-PD stays in SOLICIT indefinitely, prefix delegation is not enabled on your account. Contact the ISP — ask them to enable "IPv6 Prefix Delegation (IA-PD)" for your service. They will assign you a static prefix (e.g. a /48). Once enabled it negotiates in seconds.

Without PD, the ISP may assign the WAN address from the same /64 as your LAN prefix, causing an "overlapping" conflict in IOS when you try to configure both interfaces. The workaround is to drop ipv6 address dhcp from the WAN, use only ipv6 enable, and assign the /64 statically to the LAN — but LAN clients won't have IPv6 internet routing until PD is sorted.

LAN Interface (Gi0/0)

interface GigabitEthernet0/0
 ip address 192.168.8.1 255.255.255.0
 ip nat inside
 ip virtual-reassembly in
 ipv6 address ISP_PREFIX ::1/64
 ipv6 enable
 ipv6 nd other-config-flag
 ipv6 dhcp server LAN-V6
 no shutdown
  • ipv6 address ISP_PREFIX ::1/64 — assigns the first /64 from the delegated /48 to the LAN interface. With 2403:580c:d9d4::/48 delegated, this gives the router 2403:580c:d9d4::1/64 and advertises 2403:580c:d9d4::/64 to LAN clients via SLAAC. The remaining /64s (2403:580c:d9d4:1::/64, 2403:580c:d9d4:2::/64, ...) are available for future VLANs or subnets.
  • ipv6 nd other-config-flag — tells clients to use SLAAC for their address but get DNS/domain via DHCPv6 (stateless DHCPv6)
  • ipv6 dhcp server LAN-V6 — serves the DNS info from our pool above

Static IPv6 Default Route

With only ipv6 enable or autoconfig on the WAN interface, you need a static default route so the router knows to send IPv6 traffic via the ISP:

ipv6 route ::/0 GigabitEthernet0/1 FE80::2A2:FF:FEB2:C2

Replace FE80::2A2:FF:FEB2:C2 with your ISP gateway's link-local address — visible via show ipv6 neighbors GigabitEthernet0/1 once the interface is up. If ipv6 address autoconfig default is configured, IOS will install a default route via RA automatically, so the static route is a belt-and-suspenders fallback.

Enable SSH Version 2

While we're at it, fix the SSHv1 problem for the future:

ip domain name yourdomain.com
crypto key generate rsa modulus 1024
ip ssh version 2

Step 4: Pushing Config via Serial

screen's paste buffer drops characters at serial speeds. The most reliable approach is writing directly to the TTY device:

bash
#!/bin/sh
TTY=/dev/ttyS0
stty -F $TTY 9600 cs8 -cstopb -parenb clocal -echo raw

send_line() {
    printf '%s\r\n' "$1" > $TTY
    sleep 0.8
}

# Authenticate
printf '\r\n' > $TTY; sleep 1
send_line "hello"           # console password
send_line "enable"
send_line "cisco2"          # enable password
send_line "configure terminal"

# Send config line by line
while IFS= read -r line; do
    printf '%s\r\n' "$line" > $TTY
    sleep 0.6
done < /home/dev/cisco/delta.cfg

send_line "end"
send_line "write memory"

Key points:

  • Use stty raw to disable line buffering on the serial device
  • 0.6–0.8 seconds per line is safe at 9600 baud
  • Include exit commands between sub-modes (e.g. after interface, line) to avoid the router getting confused about context
  • Read the config back with show running-config to verify

Reading Output Back from the Serial Port

To capture what the router is saying, read from the TTY in the background while sending commands:

bash
sudo cat /dev/ttyS0 > /tmp/router_output.txt &
CAT_PID=$!

# ... send commands ...

kill $CAT_PID
cat /tmp/router_output.txt

Step 5: Verifying the Config

Once applied, check interfaces and IPv6:

show ip interface brief
show ipv6 interface brief
show ip nat statistics
show ip ssh

Expected output after correct configuration:

GigabitEthernet0/0    192.168.8.1     YES manual up   up
GigabitEthernet0/1    192.168.1.x     YES DHCP   up   up

And on the LAN client connected to alpine's eth1:

eth1: inet6 2403:580c:ffff:35db:xxxx:xxxx:xxxx:xxxx/64

SLAAC is working when clients automatically pick up a 2403:580c:ffff:35db::/64 address.

Step 6: Fixing Dual-NIC Asymmetric Routing on alpine

With alpine having two NICs on the same subnet (192.168.8.0/24) — one to the main router, one to the backup — Linux routing gets confused. Both are on 192.168.8.0/24, so the kernel uses whichever it prefers (usually eth0) for both.

This means pings sent out eth1 get their replies routed back via eth0 — the backup router never sees the return traffic.

The fix is policy routing — a separate routing table for traffic sourced from eth1:

bash
# Create a routing table for eth1
echo '200 eth1table' >> /etc/iproute2/rt_tables

# Populate it
ip route add 192.168.8.0/24 dev eth1 src 192.168.8.2 table 200
ip route add default via 192.168.8.1 dev eth1 table 200

# Rule: if source is eth1's IP, use table 200
ip rule add from 192.168.8.2 table 200

Verify:

bash
ping -I eth1 -c 3 8.8.8.8
# Should succeed with ~20ms latency

To make it persistent, add to /etc/network/interfaces:

auto eth1
iface eth1 inet dhcp
    post-up ip route add 192.168.8.0/24 dev eth1 src 192.168.8.2 table 200
    post-up ip route add default via 192.168.8.1 dev eth1 table 200
    post-up ip rule add from 192.168.8.2 table 200
    pre-down ip rule del from 192.168.8.2 table 200

Step 7: SSH Shortcut on alpine

Add to ~/.ssh/config on alpine so you can reach the backup router with a simple alias:

Host backup-router
    HostName 192.168.8.1
    User admin
    BindAddress 192.168.8.2
    KexAlgorithms +diffie-hellman-group14-sha1
    HostKeyAlgorithms +ssh-rsa
    Ciphers +aes128-cbc

Then just:

bash
ssh backup-router

The BindAddress 192.168.8.2 forces SSH to source from eth1, which the policy routing table picks up and routes correctly through the backup router.

Step 8: Lock Down SSH to LAN Only

Once the router is live on the internet, its public WAN IP (117.20.x.x) is immediately visible to automated scanners. By default, SSH is accessible from anywhere. Lock it down to LAN-only with an access-class:

ip access-list standard SSH_ACCESS
 permit 192.168.8.0 0.0.0.255
 deny any log
!
line vty 0 4
 access-class SSH_ACCESS in

The deny any log is important — it logs every blocked attempt, so you can see show ip access-lists SSH_ACCESS and watch the hit counter climb. Within minutes of the router going live, you'll see external scanners already hitting it.

The router still listens on TCP port 22 from the WAN side (Cisco doesn't close the port), but drops the connection before authentication for any source IP outside 192.168.8.0/24. SSH from inside your LAN works normally.

The Swap

Once verified, the physical swap is straightforward:

  1. Unplug the main router's WAN and LAN cables
  2. Plug them into the backup router's Gi0/1 (WAN) and Gi0/0 (LAN)
  3. The backup router takes over at 192.168.8.1 with identical config + IPv6

LAN clients don't notice — same gateway IP, same DHCP pool, same DNS. They'll additionally start getting IPv6 addresses via SLAAC automatically.

Note — give the modem time after the swap. After plugging the WAN cable into the new router, Gi0/1 may show up/up physically but receive zero DHCP response for several minutes. This is normal — the modem (especially after a reset) needs time to fully come back up and accept a new client. If show dhcp lease shows state Purging and DHCP Lease server: 0.0.0.0, just wait 2–5 minutes before troubleshooting further. You can monitor with:

show interface GigabitEthernet0/1 | include input rate|Last input

Once you see input rate climbing above 0 and Last input ticking, the modem is responding and a DHCP lease will follow shortly.

Key Takeaways

  • SSHv1 routers: use an old Ubuntu 14.04 Docker container with OpenSSH 6.6 — it's the cleanest solution
  • Serial config push: write directly to the TTY device, not through screen's paste buffer — it's more reliable
  • IPv6 on Cisco IOS: ipv6 nd other-config-flag + ipv6 dhcp server gives you SLAAC addresses + DHCPv6 DNS info, which is all most LAN clients need
  • ISP IPv6 PD: if DHCPv6-PD stays in SOLICIT indefinitely, your ISP doesn't have it enabled — contact them and ask for "IPv6 Prefix Delegation (IA-PD)". Once enabled, the ISP assigns a /48 and LAN clients get full IPv6 internet via SLAAC automatically
  • Dual-NIC same subnet: always use policy routing — two default routes with different metrics is not enough when both NICs share a subnet
  • Lock down VTY immediately: apply access-class to restrict SSH to LAN-only before the router goes live on the internet — scanners hit public IPs within minutes

Comments (0)

Leave a Comment
Your email won't be published. We'll only use it to notify you of replies to your comment.
Loading comments...
Previous Article
post-thumb

Apr 12, 2026

My Thoughts on Using Claude CoWork: The GUI Frontier

A first-hand look at Claude CoWork — Anthropic's GUI-based AI agent — exploring its browser-only scope, how it compares to Claude Code, and what the road ahead might look like for AI-driven desktop automation.

Next Article
post-thumb

Apr 04, 2026

Repurpose Your Old PCs: How To Install Alpine Linux on Them

Turn an old, dusty PC into a reliable 4G/5G backup internet gateway using Alpine Linux and Android USB tethering — no expensive hardware required.

agico

We transform visions into reality. We specializes in crafting digital experiences that captivate, engage, and innovate. With a fusion of creativity and expertise, we bring your ideas to life, one pixel at a time. Let's build the future together.

Copyright ©  2026  TYO Lab