

NervesSSH — nerves\_ssh v0.4.3

 try {

 var settings = JSON.parse(localStorage.getItem('ex\_doc:settings') || '{}');

 if (settings.theme === 'dark' ||

 ((settings.theme === 'system' || settings.theme == null) &&

 window.matchMedia('(prefers-color-scheme: dark)').matches)

 ) {

 document.body.classList.add('dark')

 }

 } catch (error) { }

 

Settings

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/README.md#L1 "View Source")

NervesSSH

=========================================================================================================================

[![CircleCI](https://circleci.com/gh/nerves-project/nerves_ssh/tree/main.svg?style=svg)](https://circleci.com/gh/nerves-project/nerves_ssh/tree/main)

[![Hex version](https://img.shields.io/hexpm/v/nerves_ssh.svg "Hex version")](https://hex.pm/packages/nerves_ssh)

Manage an SSH daemon and its subsystems on Nerves devices. It has the following

features:

1. Automatic startup of the SSH daemon on initialization

2. Ability to hook the SSH daemon into a supervision tree of your choosing

3. Easy setup of SSH firmware updates for Nerves

4. Easy shell and exec setup for Erlang, Elixir, and LFE

5. Some protection from easy-to-make mistakes that would cause ssh to not be

available

[Usage](#usage)

----------------

This library wraps Erlang/OTP's [SSH

daemon](http://erlang.org/doc/man/ssh.html#daemon-1) to make it easier to use

reliably with Nerves devices.

Most importantly, it makes it possible to segment failures in other OTP

applications from terminating the daemon and it recovers from rare scenarios

where the daemon terminates without automatically restarting.

It can be started automatically as an OTP application or hooked into a

supervision tree of your creation. Most Nerves users start it automatically as

an OTP application. This is easy, but may be limiting and it requires that you

use the application environment. See the following sections for options:

### 

[Starting as an OTP application](#starting-as-an-otp-application)

If you're using [`:nerves_pack`](https://hex.pm/packages/nerves_pack) v0.4.0 or

later, you don't need to do anything except verify the `:nerves_ssh`

configuration in your `config.exs` (see below). If you are not using

`:nerves_pack`, add `:nerves_ssh` to your `mix` dependency list:

```

def deps do

 [

 {:nerves\_ssh, "~> 0.1.0", targets: @all\_targets}

 ]

end

```

And then include it in `:shoehorn`'s `:init` list:

```

config :shoehorn,

 init: [:nerves\_runtime, :vintage\_net, :nerves\_ssh]

```

`:nerves_ssh` will work if you do not add it to the `:init` list. However, if

your main OTP application stops, OTP may stop `:nerves_ssh`, and that would make

your device inaccessible via SSH.

### 

[Starting as part of one of your supervision trees](#starting-as-part-of-one-of-your-supervision-trees)

If you want to do this, make sure that you do NOT specify `:nerves_ssh` in your

`config.exs`. The `:nerves_ssh` key decides whether or not to automatically launch

based on this.

Then when specifying the children for your supervisor, add [`NervesSSH`](NervesSSH.html) like

this:

```

 {NervesSSH, nerves\_ssh\_options}

```

The `nerves_ssh_options` should be a [`NervesSSH.Options`](NervesSSH.Options.html) struct. See the

`Configuration` section option fields that you may specify. Calling

`NervesSSH.Options.with_defaults(my_options_list)` to build the

`nerves_ssh_options` value is one way of getting reasonable defaults.

[Configuration](#configuration)

--------------------------------

NervesSSH supports the following configuration items:

* `:authorized_keys` - a list of SSH authorized key file string

* `:user_passwords` - a list of username/password tuples (stored in the

 clear!)

* `:port` - the TCP port to use for the SSH daemon. Defaults to `22`.

* `:subsystems` - a list of [SSH subsystems specs](https://erlang.org/doc/man/ssh.html#type-subsystem_spec) to start.

Defaults to SFTP and `ssh_subsystem_fwup`

* `:system_dir` - where to find host keys. Defaults to `"/data/nerves_ssh"`

* `:shell` - the language of the shell (`:elixir`, `:erlang`, `:lfe`, or

`:disabled`). Defaults to `:elixir`.

* `:exec` - the language to use for commands sent over ssh (`:elixir`,

`:erlang`, `lfe`, or `:disabled`). Defaults to `:elixir`.

* `:iex_opts` - additional options to use when starting up IEx

* `:daemon_option_overrides` - additional options to pass to [`:ssh.daemon/2`](https://www.erlang.org/doc/man/ssh.html#daemon-2).

These take precedence and are unchecked. Be careful using this since it can

break other options.

### 

[SSH host keys](#ssh-host-keys)

SSH identifies itself to clients using a host key. Clients can record the key

and use it to detect man-in-the-middle attacks and other shenanigans on future

connections. Host keys are stored in the `:system_dir` (see configuration) and

named `ssh_host_rsa_key`, `ssh_host_ed25519_key`, etc.

NervesSSH will create a host key the first time it starts if one does not exist.

The key will be stored in `:system_dir`. Be aware that the host key is not

encrypted or protected so anyone with access to the device can get it if they

choose.

If the `:system_dir` is not writable, NervesSSH will create an in-memory host

key so that users can still log in. In fact, even if the file system is

writable, NervesSSH will verify the host key before using it and recreate it if

corrupt. The goal is that broken host keys to not result in a situation where

it's impossible to log into a device. Your SSH client complaining about the host

key changing will be the hint that something is wrong.

NervesSSH currently supports

[Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519) and

[RSA](https://en.wikipedia.org/wiki/RSA_(cryptosystem)) host keys.

If you rewrite your MicroSD cards often and don't want to get SSH client errors,

add the following to your `~/.ssh/config`:

```

Host nerves.local

    UserKnownHostsFile /dev/null

    StrictHostKeyChecking no

```

[Authentication](#authentication)

----------------------------------

It's possible to set up a number of authentication strategies with the Erlang

SSH daemon. Currently, only simple public key and username/password

authentication setups are supported by `:nerves_ssh`. Both of them work fine for

getting started. As needs become more sophisticated, you can pass options to

`:daemon_option_overrides`.

### 

[Public key authentication](#public-key-authentication)

Public ssh keys can be specified so that matching clients can connect. These

come from files like your `~/.ssh/id_rsa.pub` or `~/.ssh/id_ecdsa.pub` that were

created when you created your `ssh` keys. If you haven't done this, the

following

[article](https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/)

may be helpful. Here's an example that uses the application config:

```

config :nerves\_ssh,

 authorized\_keys: [

 "ssh-rsa

AAAAB3NzaC1yc2EAAAADAQABAAAAgQDBCdMwNo0xOE86il0DB2Tq4RCv07XvnV7W1uQBlOOE0ZZVjxmTIOiu8XcSLy0mHj11qX5pQH3Th6Jmyqdj",

 "ssh-rsa

AAAAB3NzaC1yc2EAAAADAQABAAACAQCaf37TM8GfNKcoDjoewa6021zln4GvmOiXqW6SRpF61uNWZXurPte1u8frrJX1P/hGxCL7YN3cV6eZqRiF"

 ]

```

Here's another way that may work well for you that avoids needing to commit your

keys:

```

config :nerves\_ssh,

 authorized\_keys: [

 File.read!(Path.join(System.user\_home!, ".ssh/id\_rsa.pub"))

 ]

```

See [`NervesSSH.add_authorized_key/1`](NervesSSH.html#add_authorized_key/1) and [`NervesSSH.remove_authorized_key/1`](NervesSSH.html#remove_authorized_key/1)

for managing public keys at runtime.

### 

[Username/password authentication](#username-password-authentication)

The SSH console uses public key authentication by default, but it can be

configured for usernames and passwords via the `:user_passwords` key. This has

the form `[{"username", "password"}, ...]`. Keep in mind that passwords are

stored in the clear. This is not recommended for most situations.

```

config :nerves\_ssh,

 user\_passwords: [

 {"username", "password"}

 ]

```

You can use [`NervesSSH.add_user/2`](NervesSSH.html#add_user/2) and [`NervesSSH.remove_user/1`](NervesSSH.html#remove_user/1) for managing

credentials at runtime, but they are not saved to disk so restarting [`NervesSSH`](NervesSSH.html)

will cause them to be lost (such as a reboot or daemon crash)

[Upgrade from `NervesFirmwareSSH`](#upgrade-from-nervesfirmwaressh)

--------------------------------------------------------------------

If you are migrating from `:nerves_firmware_ssh`, or updating to `:nerves_pack >= 0.4.0`, you will need to make a few changes to your existing project.

1. Generate a `upload.sh` script by running [`mix firmware.gen.script`](https://hexdocs.pm/ssh_subsystem_fwup/0.6.1/Mix.Tasks.Firmware.Gen.Script.html) (if you

don't already have one)

	* This is necessary because you will no longer have access to your old

	[`mix upload`](https://hexdocs.pm/ssh_subsystem_fwup/0.6.1/Mix.Tasks.Upload.html) command because `nerves_firmware_ssh` is being removed from

	the project.

2. Change all `:nerves_firmware_ssh` config values to `:nerves_ssh`. A command

like this would probably do the trick:

```

 grep -RIl nerves\_firmware\_ssh config/ | xargs sed -i 's/nerves\_firmware\_ssh/nerves\_ssh/g'

```

3. Compile your new firmware that includes `:nerves_ssh` (or updated

`:nerves_pack`)

	* **NOTE** Compiling your new firmware for the first time will generate a

	warning about the old `upload.sh` script still being around. You can

	ignore that **this one time** because you will need it for uploading to an

	existing device still using port 8989.

4. Upload your new firmware with `:nerves_ssh` using the ***old*** `upload.sh`

script (or whatever other method you have been using for OTA firmware

updates)

5. After the new firmware with `:nerves_ssh` is on the device, then you'll need

to generate the new `upload.sh` script with [`mix firmware.gen.script`](https://hexdocs.pm/ssh_subsystem_fwup/0.6.1/Mix.Tasks.Firmware.Gen.Script.html), or see

[SSHSubsystemFwup](https://hexdocs.pm/ssh_subsystem_fwup/readme.html) for

other supported options

[Goals](#goals)

----------------

* [X] Support public key authentication

* [X] Support username/password authentication

* [X] Device generated server certificate and key

* [ ] Device generated username/password

[← Previous Page

 

API Reference](api-reference.html)

[Next Page →

 

Changelog](changelog.html)





NervesSSH — nerves\_ssh v0.4.3

 try {

 var settings = JSON.parse(localStorage.getItem('ex\_doc:settings') || '{}');

 if (settings.theme === 'dark' ||

 ((settings.theme === 'system' || settings.theme == null) &&

 window.matchMedia('(prefers-color-scheme: dark)').matches)

 ) {

 document.body.classList.add('dark')

 }

 } catch (error) { }

 

Settings

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh.ex#L1 "View Source")

NervesSSH

(nerves\_ssh v0.4.3)

======================================================================================================================================================

This library wraps Erlang/OTP's [SSH

daemon](http://erlang.org/doc/man/ssh.html#daemon-1) to make it easier to use

reliably with Nerves devices.

Most importantly, it makes it possible to segment failures in other OTP

applications from terminating the daemon and it recovers from rare scenarios

where the daemon terminates without automatically restarting.

It can be started automatically as an OTP application or hooked into a

supervision tree of your creation. Most Nerves users start it automatically as

an OTP application. This is easy, but may be limiting and it requires that you

use the application environment. See the following sections for options:

### 

[Starting as an OTP application](#module-starting-as-an-otp-application)

If you're using [`:nerves_pack`](https://hex.pm/packages/nerves_pack) v0.4.0 or

later, you don't need to do anything except verify the `:nerves_ssh`

configuration in your `config.exs` (see below). If you are not using

`:nerves_pack`, add `:nerves_ssh` to your `mix` dependency list:

```

def deps do

 [

 {:nerves\_ssh, "~> 0.1.0", targets: @all\_targets}

 ]

end

```

And then include it in `:shoehorn`'s `:init` list:

```

config :shoehorn,

 init: [:nerves\_runtime, :vintage\_net, :nerves\_ssh]

```

`:nerves_ssh` will work if you do not add it to the `:init` list. However, if

your main OTP application stops, OTP may stop `:nerves_ssh`, and that would make

your device inaccessible via SSH.

### 

[Starting as part of one of your supervision trees](#module-starting-as-part-of-one-of-your-supervision-trees)

If you want to do this, make sure that you do NOT specify `:nerves_ssh` in your

`config.exs`. The `:nerves_ssh` key decides whether or not to automatically launch

based on this.

Then when specifying the children for your supervisor, add [`NervesSSH`](NervesSSH.html#content) like

this:

```

 {NervesSSH, nerves\_ssh\_options}

```

The `nerves_ssh_options` should be a [`NervesSSH.Options`](NervesSSH.Options.html) struct. See the

`Configuration` section option fields that you may specify. Calling

`NervesSSH.Options.with_defaults(my_options_list)` to build the

`nerves_ssh_options` value is one way of getting reasonable defaults.

[Configuration](#module-configuration)

---------------------------------------

NervesSSH supports the following configuration items:

* `:authorized_keys` - a list of SSH authorized key file string

* `:user_passwords` - a list of username/password tuples (stored in the

 clear!)

* `:port` - the TCP port to use for the SSH daemon. Defaults to `22`.

* `:subsystems` - a list of [SSH subsystems specs](https://erlang.org/doc/man/ssh.html#type-subsystem_spec) to start.

Defaults to SFTP and `ssh_subsystem_fwup`

* `:system_dir` - where to find host keys. Defaults to `"/data/nerves_ssh"`

* `:shell` - the language of the shell (`:elixir`, `:erlang`, `:lfe`, or

`:disabled`). Defaults to `:elixir`.

* `:exec` - the language to use for commands sent over ssh (`:elixir`,

`:erlang`, `lfe`, or `:disabled`). Defaults to `:elixir`.

* `:iex_opts` - additional options to use when starting up IEx

* `:daemon_option_overrides` - additional options to pass to [`:ssh.daemon/2`](https://www.erlang.org/doc/man/ssh.html#daemon-2).

These take precedence and are unchecked. Be careful using this since it can

break other options.

### 

[SSH host keys](#module-ssh-host-keys)

SSH identifies itself to clients using a host key. Clients can record the key

and use it to detect man-in-the-middle attacks and other shenanigans on future

connections. Host keys are stored in the `:system_dir` (see configuration) and

named `ssh_host_rsa_key`, `ssh_host_ed25519_key`, etc.

NervesSSH will create a host key the first time it starts if one does not exist.

The key will be stored in `:system_dir`. Be aware that the host key is not

encrypted or protected so anyone with access to the device can get it if they

choose.

If the `:system_dir` is not writable, NervesSSH will create an in-memory host

key so that users can still log in. In fact, even if the file system is

writable, NervesSSH will verify the host key before using it and recreate it if

corrupt. The goal is that broken host keys to not result in a situation where

it's impossible to log into a device. Your SSH client complaining about the host

key changing will be the hint that something is wrong.

NervesSSH currently supports

[Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519) and

[RSA](https://en.wikipedia.org/wiki/RSA_(cryptosystem)) host keys.

If you rewrite your MicroSD cards often and don't want to get SSH client errors,

add the following to your `~/.ssh/config`:

```

Host nerves.local

    UserKnownHostsFile /dev/null

    StrictHostKeyChecking no

```

[Authentication](#module-authentication)

-----------------------------------------

It's possible to set up a number of authentication strategies with the Erlang

SSH daemon. Currently, only simple public key and username/password

authentication setups are supported by `:nerves_ssh`. Both of them work fine for

getting started. As needs become more sophisticated, you can pass options to

`:daemon_option_overrides`.

### 

[Public key authentication](#module-public-key-authentication)

Public ssh keys can be specified so that matching clients can connect. These

come from files like your `~/.ssh/id_rsa.pub` or `~/.ssh/id_ecdsa.pub` that were

created when you created your `ssh` keys. If you haven't done this, the

following

[article](https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/)

may be helpful. Here's an example that uses the application config:

```

config :nerves\_ssh,

 authorized\_keys: [

 "ssh-rsa

AAAAB3NzaC1yc2EAAAADAQABAAAAgQDBCdMwNo0xOE86il0DB2Tq4RCv07XvnV7W1uQBlOOE0ZZVjxmTIOiu8XcSLy0mHj11qX5pQH3Th6Jmyqdj",

 "ssh-rsa

AAAAB3NzaC1yc2EAAAADAQABAAACAQCaf37TM8GfNKcoDjoewa6021zln4GvmOiXqW6SRpF61uNWZXurPte1u8frrJX1P/hGxCL7YN3cV6eZqRiF"

 ]

```

Here's another way that may work well for you that avoids needing to commit your

keys:

```

config :nerves\_ssh,

 authorized\_keys: [

 File.read!(Path.join(System.user\_home!, ".ssh/id\_rsa.pub"))

 ]

```

See [`NervesSSH.add_authorized_key/1`](#add_authorized_key/1) and [`NervesSSH.remove_authorized_key/1`](#remove_authorized_key/1)

for managing public keys at runtime.

### 

[Username/password authentication](#module-username-password-authentication)

The SSH console uses public key authentication by default, but it can be

configured for usernames and passwords via the `:user_passwords` key. This has

the form `[{"username", "password"}, ...]`. Keep in mind that passwords are

stored in the clear. This is not recommended for most situations.

```

config :nerves\_ssh,

 user\_passwords: [

 {"username", "password"}

 ]

```

You can use [`NervesSSH.add_user/2`](#add_user/2) and [`NervesSSH.remove_user/1`](#remove_user/1) for managing

credentials at runtime, but they are not saved to disk so restarting [`NervesSSH`](NervesSSH.html#content)

will cause them to be lost (such as a reboot or daemon crash)

[Upgrade from `NervesFirmwareSSH`](#module-upgrade-from-nervesfirmwaressh)

---------------------------------------------------------------------------

If you are migrating from `:nerves_firmware_ssh`, or updating to `:nerves_pack >= 0.4.0`, you will need to make a few changes to your existing project.

1. Generate a `upload.sh` script by running [`mix firmware.gen.script`](https://hexdocs.pm/ssh_subsystem_fwup/0.6.1/Mix.Tasks.Firmware.Gen.Script.html) (if you

don't already have one)

	* This is necessary because you will no longer have access to your old

	[`mix upload`](https://hexdocs.pm/ssh_subsystem_fwup/0.6.1/Mix.Tasks.Upload.html) command because `nerves_firmware_ssh` is being removed from

	the project.

2. Change all `:nerves_firmware_ssh` config values to `:nerves_ssh`. A command

like this would probably do the trick:

```

 grep -RIl nerves\_firmware\_ssh config/ | xargs sed -i 's/nerves\_firmware\_ssh/nerves\_ssh/g'

```

3. Compile your new firmware that includes `:nerves_ssh` (or updated

`:nerves_pack`)

	* **NOTE** Compiling your new firmware for the first time will generate a

	warning about the old `upload.sh` script still being around. You can

	ignore that **this one time** because you will need it for uploading to an

	existing device still using port 8989.

4. Upload your new firmware with `:nerves_ssh` using the ***old*** `upload.sh`

script (or whatever other method you have been using for OTA firmware

updates)

5. After the new firmware with `:nerves_ssh` is on the device, then you'll need

to generate the new `upload.sh` script with [`mix firmware.gen.script`](https://hexdocs.pm/ssh_subsystem_fwup/0.6.1/Mix.Tasks.Firmware.Gen.Script.html), or see

[SSHSubsystemFwup](https://hexdocs.pm/ssh_subsystem_fwup/readme.html) for

other supported options

[Goals](#module-goals)

-----------------------

* [X] Support public key authentication

* [X] Support username/password authentication

* [X] Device generated server certificate and key

* [ ] Device generated username/password

[Summary](#summary)

====================

[Functions](#functions)

------------------------

[add\_authorized\_key(name \\ NervesSSH, key)](#add_authorized_key/2)

Add an SSH public key to the authorized keys

[add\_user(name \\ NervesSSH, user, password)](#add_user/3)

Add a user credential to the SSH daemon

[child\_spec(init\_arg)](#child_spec/1)

Returns a specification to start this module under a supervisor.

[configuration(name \\ NervesSSH)](#configuration/1)

Read the configuration options

[info(name \\ NervesSSH)](#info/1)

Return information on the running ssh daemon.

[remove\_authorized\_key(name \\ NervesSSH, key)](#remove_authorized_key/2)

Remove an SSH public key from the authorized keys

[remove\_user(name \\ NervesSSH, user)](#remove_user/2)

Remove a user credential from the SSH daemon

[Functions](#functions)

========================

[Link to this function](#add_authorized_key/2 "Link to this function")

add\_authorized\_key(name \\ NervesSSH, key)

============================================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh.ex#L67 "View Source")

```

@spec add_authorized_key([GenServer.name](https://hexdocs.pm/elixir/GenServer.html#t:name/0)(), [String.t](https://hexdocs.pm/elixir/String.html#t:t/0)()) :: :ok

```

Add an SSH public key to the authorized keys

This also persists the key to `{USER_DIR}/authorized_keys` so that it can be

used after restarting.

Call [`configuration/0`](#configuration/0) to get the current list of authorized keys.

Example:

```

iex> NervesSSH.add\_authorized\_key("ssh-ed25519 AAAAC3NzaC...")

```

[Link to this function](#add_user/3 "Link to this function")

add\_user(name \\ NervesSSH, user, password)

============================================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh.ex#L90 "View Source")

```

@spec add_user([GenServer.name](https://hexdocs.pm/elixir/GenServer.html#t:name/0)(), [String.t](https://hexdocs.pm/elixir/String.html#t:t/0)(), [String.t](https://hexdocs.pm/elixir/String.html#t:t/0)() | nil) :: :ok

```

Add a user credential to the SSH daemon

Setting password to `""` or `nil` will effectively be passwordless

authentication for this user

[Link to this function](#child_spec/1 "Link to this function")

child\_spec(init\_arg)

======================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh.ex#L6 "View Source")

Returns a specification to start this module under a supervisor.

See [`Supervisor`](https://hexdocs.pm/elixir/Supervisor.html).

[Link to this function](#configuration/1 "Link to this function")

configuration(name \\ NervesSSH)

================================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh.ex#L38 "View Source")

```

@spec configuration([GenServer.name](https://hexdocs.pm/elixir/GenServer.html#t:name/0)()) :: [NervesSSH.Options.t](NervesSSH.Options.html#t:t/0)()

```

Read the configuration options

[Link to this function](#info/1 "Link to this function")

info(name \\ NervesSSH)

=======================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh.ex#L48 "View Source")

```

@spec info([GenServer.name](https://hexdocs.pm/elixir/GenServer.html#t:name/0)()) :: {:ok, [keyword](https://hexdocs.pm/elixir/typespecs.html#built-in-types)()} | {:error, :bad_daemon_ref}

```

Return information on the running ssh daemon.

See [ssh.daemon\_info/1](http://erlang.org/doc/man/ssh.html#daemon_info-1).

[Link to this function](#remove_authorized_key/2 "Link to this function")

remove\_authorized\_key(name \\ NervesSSH, key)

===============================================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh.ex#L79 "View Source")

```

@spec remove_authorized_key([GenServer.name](https://hexdocs.pm/elixir/GenServer.html#t:name/0)(), [String.t](https://hexdocs.pm/elixir/String.html#t:t/0)()) :: :ok

```

Remove an SSH public key from the authorized keys

This looks for an exact match. Call [`configuration/0`](#configuration/0) to get the list of

authorized keys to find those to remove. The `{USER_DIR}/authorized_keys`

will be updated to save the change.

[Link to this function](#remove_user/2 "Link to this function")

remove\_user(name \\ NervesSSH, user)

=====================================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh.ex#L98 "View Source")

```

@spec remove_user([GenServer.name](https://hexdocs.pm/elixir/GenServer.html#t:name/0)(), [String.t](https://hexdocs.pm/elixir/String.html#t:t/0)()) :: :ok

```

Remove a user credential from the SSH daemon





NervesSSH.Exec — nerves\_ssh v0.4.3

 try {

 var settings = JSON.parse(localStorage.getItem('ex\_doc:settings') || '{}');

 if (settings.theme === 'dark' ||

 ((settings.theme === 'system' || settings.theme == null) &&

 window.matchMedia('(prefers-color-scheme: dark)').matches)

 ) {

 document.body.classList.add('dark')

 }

 } catch (error) { }

 

Settings

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/exec.ex#L1 "View Source")

NervesSSH.Exec

(nerves\_ssh v0.4.3)

================================================================================================================================================================

This module contains helper methods for running commands over SSH

[Summary](#summary)

====================

[Functions](#functions)

------------------------

[run\_elixir(cmd)](#run_elixir/1)

Run one Elixir command coming over ssh

[run\_lfe(cmd)](#run_lfe/1)

Run one LFE command coming over ssh

[Functions](#functions)

========================

[Link to this function](#run_elixir/1 "Link to this function")

run\_elixir(cmd)

================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/exec.ex#L12 "View Source")

```

@spec run_elixir([charlist](https://hexdocs.pm/elixir/typespecs.html#built-in-types)()) :: {:ok, [binary](https://hexdocs.pm/elixir/typespecs.html#built-in-types)()} | {:error, [binary](https://hexdocs.pm/elixir/typespecs.html#built-in-types)()}

```

Run one Elixir command coming over ssh

[Link to this function](#run_lfe/1 "Link to this function")

run\_lfe(cmd)

=============

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/exec.ex#L34 "View Source")

```

@spec run_lfe([charlist](https://hexdocs.pm/elixir/typespecs.html#built-in-types)()) :: {:ok, [iolist](https://hexdocs.pm/elixir/typespecs.html#built-in-types)()} | {:error, [binary](https://hexdocs.pm/elixir/typespecs.html#built-in-types)()}

```

Run one LFE command coming over ssh





NervesSSH.Options — nerves\_ssh v0.4.3

 try {

 var settings = JSON.parse(localStorage.getItem('ex\_doc:settings') || '{}');

 if (settings.theme === 'dark' ||

 ((settings.theme === 'system' || settings.theme == null) &&

 window.matchMedia('(prefers-color-scheme: dark)').matches)

 ) {

 document.body.classList.add('dark')

 }

 } catch (error) { }

 

Settings

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/options.ex#L1 "View Source")

NervesSSH.Options

(nerves\_ssh v0.4.3)

======================================================================================================================================================================

Defines option for running the SSH daemon.

The following fields are available:

* `:name` - a name used to reference the NervesSSH-managed SSH daemon. Defaults to [`NervesSSH`](NervesSSH.html).

* `:authorized_keys` - a list of SSH authorized key file string

* `:port` - the TCP port to use for the SSH daemon. Defaults to `22`.

* `:subsystems` - a list of [SSH subsystems specs](https://erlang.org/doc/man/ssh.html#type-subsystem_spec) to start. Defaults to SFTP and `ssh_subsystem_fwup`

* `:user_dir` - where to find authorized\_keys file

* `:system_dir` - where to find host keys

* `:shell` - the language of the shell (`:elixir`, `:erlang`, `:lfe` or `:disabled`). Defaults to `:elixir`.

* `:exec` - the language to use for commands sent over ssh (`:elixir`, `:erlang`, or `:disabled`). Defaults to `:elixir`.

* `:iex_opts` - additional options to use when starting up IEx

* `:user_passwords` - a list of username/password tuples (stored in the clear!)

* `:daemon_option_overrides` - additional options to pass to [`:ssh.daemon/2`](https://www.erlang.org/doc/man/ssh.html#daemon-2). These take precedence and are unchecked. Be careful using this since it can break other options.

[Summary](#summary)

====================

[Types](#types)

----------------

[language()](#t:language/0)

[t()](#t:t/0)

[Functions](#functions)

------------------------

[add\_authorized\_key(opts, key)](#add_authorized_key/2)

Add an authorized key

[add\_user(opts, user, password)](#add_user/3)

Add user credential to SSH options

[daemon\_options(opts)](#daemon_options/1)

Return :ssh.daemon\_options()

[decode\_authorized\_keys(opts)](#decode_authorized_keys/1)

Decode the authorized keys into Erlang public key format

[load\_authorized\_keys(opts)](#load_authorized_keys/1)

Load authorized keys from the authorized\_keys file

[new(opts \\ [])](#new/1)

Convert keyword options to the NervesSSH.Options

[remove\_authorized\_key(opts, key)](#remove_authorized_key/2)

Remove an authorized key

[remove\_user(opts, user)](#remove_user/2)

Remove user credential from SSH options

[sanitize(opts)](#sanitize/1)

Go through the options and fix anything that might crash

[save\_authorized\_keys(opts)](#save_authorized_keys/1)

Save the authorized keys to authorized\_keys file

[with\_defaults(opts \\ [])](#with_defaults/1)

Create a new NervesSSH.Options and fill in defaults

[Types](#types)

================

[Link to this type](#t:language/0 "Link to this type")

language()

==========

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/options.ex#L28 "View Source")

```

@type language() :: :elixir | :erlang | :lfe | :disabled

```

[Link to this type](#t:t/0 "Link to this type")

t()

===

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/options.ex#L30 "View Source")

```

@type t() :: %NervesSSH.Options{

  authorized_keys: [[String.t](https://hexdocs.pm/elixir/String.html#t:t/0)()],

  daemon_option_overrides: [keyword](https://hexdocs.pm/elixir/typespecs.html#built-in-types)(),

  decoded_authorized_keys: [[:public\_key.public\_key](https://www.erlang.org/doc/man/public_key.html#type-public_key)()],

  exec: [language](#t:language/0)(),

  iex_opts: [keyword](https://hexdocs.pm/elixir/typespecs.html#built-in-types)(),

  name: [GenServer.name](https://hexdocs.pm/elixir/GenServer.html#t:name/0)(),

  port: [non\_neg\_integer](https://hexdocs.pm/elixir/typespecs.html#basic-types)(),

  shell: [language](#t:language/0)(),

  subsystems: [[:ssh.subsystem\_spec](https://www.erlang.org/doc/man/ssh.html#type-subsystem_spec)()],

  system_dir: [Path.t](https://hexdocs.pm/elixir/Path.html#t:t/0)(),

  user_dir: [Path.t](https://hexdocs.pm/elixir/Path.html#t:t/0)(),

  user_passwords: [{[String.t](https://hexdocs.pm/elixir/String.html#t:t/0)(), [String.t](https://hexdocs.pm/elixir/String.html#t:t/0)()}]

}

```

[Functions](#functions)

========================

[Link to this function](#add_authorized_key/2 "Link to this function")

add\_authorized\_key(opts, key)

===============================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/options.ex#L103 "View Source")

```

@spec add_authorized_key([t](#t:t/0)(), [String.t](https://hexdocs.pm/elixir/String.html#t:t/0)()) :: [t](#t:t/0)()

```

Add an authorized key

[Link to this function](#add_user/3 "Link to this function")

add\_user(opts, user, password)

===============================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/options.ex#L165 "View Source")

```

@spec add_user([t](#t:t/0)(), [String.t](https://hexdocs.pm/elixir/String.html#t:t/0)(), [String.t](https://hexdocs.pm/elixir/String.html#t:t/0)() | nil) :: [t](#t:t/0)()

```

Add user credential to SSH options

[Link to this function](#daemon_options/1 "Link to this function")

daemon\_options(opts)

=====================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/options.ex#L87 "View Source")

```

@spec daemon_options([t](#t:t/0)()) :: [:ssh.daemon\_options](https://www.erlang.org/doc/man/ssh.html#type-daemon_options)()

```

Return :ssh.daemon\_options()

[Link to this function](#decode_authorized_keys/1 "Link to this function")

decode\_authorized\_keys(opts)

==============================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/options.ex#L143 "View Source")

```

@spec decode_authorized_keys([t](#t:t/0)()) :: [t](#t:t/0)()

```

Decode the authorized keys into Erlang public key format

[Link to this function](#load_authorized_keys/1 "Link to this function")

load\_authorized\_keys(opts)

============================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/options.ex#L122 "View Source")

```

@spec load_authorized_keys([t](#t:t/0)()) :: [t](#t:t/0)()

```

Load authorized keys from the authorized\_keys file

[Link to this function](#new/1 "Link to this function")

new(opts \\ [])

===============

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/options.ex#L62 "View Source")

```

@spec new([keyword](https://hexdocs.pm/elixir/typespecs.html#built-in-types)()) :: [t](#t:t/0)()

```

Convert keyword options to the NervesSSH.Options

[Link to this function](#remove_authorized_key/2 "Link to this function")

remove\_authorized\_key(opts, key)

==================================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/options.ex#L112 "View Source")

```

@spec remove_authorized_key([t](#t:t/0)(), [String.t](https://hexdocs.pm/elixir/String.html#t:t/0)()) :: [t](#t:t/0)()

```

Remove an authorized key

[Link to this function](#remove_user/2 "Link to this function")

remove\_user(opts, user)

========================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/options.ex#L174 "View Source")

```

@spec remove_user([t](#t:t/0)(), [String.t](https://hexdocs.pm/elixir/String.html#t:t/0)()) :: [t](#t:t/0)()

```

Remove user credential from SSH options

[Link to this function](#sanitize/1 "Link to this function")

sanitize(opts)

==============

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/options.ex#L278 "View Source")

```

@spec sanitize([t](#t:t/0)()) :: [t](#t:t/0)()

```

Go through the options and fix anything that might crash

The goal is to make options "always work" since it is painful to

debug typo's, etc. that cause the ssh daemon to not start.

[Link to this function](#save_authorized_keys/1 "Link to this function")

save\_authorized\_keys(opts)

============================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/options.ex#L152 "View Source")

```

@spec save_authorized_keys([t](#t:t/0)()) :: :ok | {:error, [File.posix](https://hexdocs.pm/elixir/File.html#t:posix/0)()}

```

Save the authorized keys to authorized\_keys file

[Link to this function](#with_defaults/1 "Link to this function")

with\_defaults(opts \\ [])

==========================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/options.ex#L76 "View Source")

```

@spec with_defaults([keyword](https://hexdocs.pm/elixir/typespecs.html#built-in-types)()) :: [t](#t:t/0)()

```

Create a new NervesSSH.Options and fill in defaults





NervesSSH.UserPasswords — nerves\_ssh v0.4.3

 try {

 var settings = JSON.parse(localStorage.getItem('ex\_doc:settings') || '{}');

 if (settings.theme === 'dark' ||

 ((settings.theme === 'system' || settings.theme == null) &&

 window.matchMedia('(prefers-color-scheme: dark)').matches)

 ) {

 document.body.classList.add('dark')

 }

 } catch (error) { }

 

Settings

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/user_passwords.ex#L1 "View Source")

NervesSSH.UserPasswords

(nerves\_ssh v0.4.3)

===================================================================================================================================================================================

Default module used for checking User/Password combinations

This will allow 3 attempts to login with a username and password

and then send SSH\_MSG\_DISCONNECT

[Summary](#summary)

====================

[Functions](#functions)

------------------------

[check(name, user, password, ip, attempt)](#check/5)

[Functions](#functions)

========================

[Link to this function](#check/5 "Link to this function")

check(name, user, password, ip, attempt)

========================================

[View Source](https://github.com/nerves-project/nerves_ssh/blob/v0.4.3/lib/nerves_ssh/user_passwords.ex#L19 "View Source")

```

@spec check(

  name :: [GenServer.name](https://hexdocs.pm/elixir/GenServer.html#t:name/0)(),

  [:erlang.string](https://www.erlang.org/doc/man/erlang.html#type-string)(),

  [:erlang.string](https://www.erlang.org/doc/man/erlang.html#type-string)(),

  [:ssh.ip\_port](https://www.erlang.org/doc/man/ssh.html#type-ip_port)(),

  :undefined | [non\_neg\_integer](https://hexdocs.pm/elixir/typespecs.html#basic-types)()

) :: [boolean](https://hexdocs.pm/elixir/typespecs.html#built-in-types)() | :disconnect | {[boolean](https://hexdocs.pm/elixir/typespecs.html#built-in-types)(), [non\_neg\_integer](https://hexdocs.pm/elixir/typespecs.html#basic-types)()}

```

