README.md

# SSHSubsystemFwup

[![CircleCI](https://circleci.com/gh/nerves-project/ssh_subsystem_fwup/tree/main.svg?style=svg)](https://circleci.com/gh/nerves-project/ssh_subsystem_fwup/tree/main)
[![Hex version](https://img.shields.io/hexpm/v/ssh_subsystem_fwup.svg "Hex version")](https://hex.pm/packages/ssh_subsystem_fwup)

This library provides an [ssh](https://en.wikipedia.org/wiki/Secure_Shell)
subsystem that applies Nerves "over-the-air" firmware updates. It is an
alternative to
[`nerves_firmware_ssh`](https://github.com/nerves-project/nerves_firmware_ssh)
that extracts the update service to a `:ssh.daemon/1` spec. This trims down the
responsibilities of the library and makes it possible to:

1. Customize ssh authentication (for example, password-based auth is possible)
2. Handle host keys differently and more securely
3. Run firmware updates on port 22 with other ssh services

In addition, the protocol for sending updates over ssh has been simplified. If
you're coming from `nerves_firmware_ssh`, you'll have used the `upload.sh`
script or `mix upload`. This library provides the same interface. If using
`upload.sh`, you will need to rerun `mix firmware.gen.script` since the script
has changed.

## Installation

The easiest installation is to use
[`nerves_ssh`](https://github.com/nerves-project/nerves_ssh) and have it bring
in this library as a dependency. See that project for details.

However, if you do not want to use `nerves_ssh`, here's what do do. First, add
the dependency:

```elixir
def deps do
  [{:ssh_subsystem_fwup, "~> 0.5.0"}]
end
```

Then add ssh subsystem spec to the call that starts the `ssh` daemon. This code
will look something like:

```elixir
    {:ok, ref} =
      :ssh.daemon([
        {:subsystems, [SSHSubsystemFwup.subsystem_spec()]}
      ])
```

You will likely have many more options passed to the `ssh.daemon`.

## Uploading firmware

There are two ways of uploading firmware. The first is to run:

```shell
mix upload
```

That doesn't work for everyone due to `ssh` authentication preferences. The
alternative is to use commandline `ssh`. For convenience, `ssh_subsystem_fwup`
can generate a script that makes this easier. Go to your Nerves project
directory and run:

```shell
mix firmware.gen.script
```

This should create an `upload.sh` script. Frequently when starting out, you can
run `./upload.sh` without arguments since it will guess that it's supposed to
upload to `nerves.local`. To specify a device to upload to, pass the device's
hostname as the first argument. For example:

```shell
$ ./upload.sh nerves-1234.local
fwup: Upgrading partition B
|====================================| 100% (32.34 / 32.34) MB
Success!
Elapsed time: 4.720 s
Disconnected from 172.31.207.89 port 22
```

Note that the `.local` address assumes that mDNS has been configured on the
device and that mDNS works on your network and OS. That's not always the case
and a frequent source of frustration when it fails. When in doubt, check that
you can upload to the device's IP address. You can get the IP address from your
router or by connecting to the device's IEx prompt and running `ifconfig`.

## Upload protocol

It's not necessary to use the `upload.sh` script. The following line is
equivalent:

```shell
cat $firmware | ssh -s $nerves_device fwup
```

## License

All source code is licensed under the
[Apache License, 2.0](https://opensource.org/licenses/Apache-2.0).