Skip to content

Routers, switches and appliances ​

Many network devices accept SSH logins but implement only a small SCP server for moving firmware and configuration files. There is no SFTP, often no shell, and sometimes paths look like flash:image.bin instead of Unix paths.

Connect with SCP directly ​

Skip the SFTP probe, and give the device time to answer:

ts
import { connect } from 'node-scp';

await using device = await connect({
  host: '10.0.0.10',
  username: 'admin',
  password: process.env.DEVICE_PASSWORD,
  protocol: 'scp',
  readyTimeout: 30_000,
});

await device.upload('./firmware.bin', 'flash:firmware.bin');
await device.download('config.txt', './backup/config.txt');

The part after the host is passed to the device as is, so device specific names such as flash:firmware.bin or bootflash: work when the device understands them. Paths with only letters, digits and _@%+=:,./- are sent without quotes, which is what devices without a shell expect.

Things that differ between vendors ​

  • Enable the SCP server first. Many devices ship with it off. Cisco IOS, for example, needs ip scp server enable.

  • Directory copies (recursive: true) are often not supported. Copy files one by one.

  • Preserving times (preserve: true) sends extra T records that some devices reject. Leave it off.

  • Legacy algorithms. Older devices only offer old ciphers or key exchanges. Enable them explicitly through the ssh2 algorithms option, for example:

    ts
    await connect({
      host: '10.0.0.10',
      username: 'admin',
      password,
      protocol: 'scp',
      algorithms: { kex: { append: ['diffie-hellman-group14-sha1'] } },
    });
  • Keyboard interactive logins. Some devices ask for the password through keyboard-interactive. Set tryKeyboard: true and answer in beforeConnect:

    ts
    await connect({
      host,
      username,
      tryKeyboard: true,
      protocol: 'scp',
      beforeConnect: (ssh) =>
        ssh.on('keyboard-interactive', (_name, _instructions, _lang, prompts, finish) =>
          finish(prompts.map(() => password)),
        ),
    });

When something fails ​

ErrorUsual cause
ERR_SCP_UNAVAILABLEThe SCP server is disabled, or the device only allows SFTP.
ERR_SCP_PROTOCOLThe device answered in an unexpected way. Try without recursive and preserve.
ERR_PERMISSION_DENIEDThe account lacks the privilege level for file transfers.
ERR_TIMEOUTThe device is slow to accept the login; raise readyTimeout.

If a device of yours needs something else, please open an issue with the device model and the error message.

Released under the MIT License.