Closed edwardzhou closed 10 months ago
This doesn't directly answer your question, but https://github.com/nerves-hub/nerves_hub_web/pull/1139 and https://github.com/nerves-hub/nerves_hub_link/pull/141 might be a better localhost experience.
The PRs should be merged in within the coming weeks with the focus on an easier, quicker, and more straight forward experience for running smaller hub installs.
This isn't neccessarily a problem with NervesHub, but rather configuration. There are a few things to note here:
ca.pem
instead of device-root-ca.pem
/certs
is not a default path in Nerves systems which implies you're doing a custom partition and/or mounting, or those files may not exist where you think?# In IEx or some other place. This maybe need to be IO.inspect/1 and printed so it can be copied to config
cert = File.read!("device-1234-cert.pem") |> X509.Certificate.from_pem!() |> X509.Certificate.to_der()
key_der = File.read!("device-1234-key.pem") |> X509.PrivateKey.from_pem!() |> X509.PrivateKey.to_der()
cacerts = File.read!("ca.pem") |> X509.from_pem() |> Enum.map(&X509.Certificate.to_der/1)
# in your config of rpi4
config :nerves_hub_link,
ssl: [cert: cert, key: {:ECPrivateKey, key_der}, cacerts: cacerts]
NervesHubLink.Configurator
behavior in another module which does the file reading and conversion
device-1234-cert.pem
is the one used in the test suite, then this could be mismatched with a different device identifier in web. For me, it was registered to the only device in SmartKiosk
product of NervesTeam
org. If its not there, then you need to create a new device record somewhere and upload the device-1234-cert.pem
record to itMay I know the script of creating ceritifications which in test/fixtures/ssl?
I will shadow the steps to trying to create my own.
I've also been a bit stuck here for some weeks. I made a Mix task for converting certificates to DER (not the prettiest code 😅):
defmodule Mix.Tasks.Device.Certs do
use Mix.Task
@shortdoc "Generate DER certs for device"
@ssl_path "rootfs_overlay/etc/ssl"
@spec process_args([String.t()]) :: {:ok, %{ca: String.t(), key: String.t(), cert: String.t()}} | {:error, String.t()}
defp process_args(args) do
options = OptionParser.parse(args, switches: [ca: :string, key: :string, cert: :string])
case options do
{[ca: ca_path, key: key_path, cert: cert_path], _, _} when is_binary(ca_path) and is_binary(key_path) and is_binary(cert_path) ->
{:ok, %{ca: ca_path, key: key_path, cert: cert_path}}
_ ->
{:error, "Invalid arguments. Please specify --ca, --key, and --cert paths correctly."}
end
end
@spec run([String.t()]) :: :ok | {:error, String.t()}
def run(args) do
with {:ok, paths} <- process_args(args),
:ok <- convert_and_save(paths.ca, "#{@ssl_path}/ca.der", :cert),
:ok <- convert_and_save(paths.key, "#{@ssl_path}/key.der", :key),
:ok <- convert_and_save(paths.cert, "#{@ssl_path}/cert.der", :cert) do
IO.puts("DER certificates generated successfully.")
:ok
else
{:error, message} ->
Mix.raise(message)
end
end
@spec convert_and_save(String.t(), String.t(), :cert | :key) :: :ok | {:error, String.t()}
defp convert_and_save(input_path, output_path, type) do
try do
# Remember parent directories
:ok = File.mkdir_p(Path.dirname(output_path))
pem = File.read!(input_path)
der = case type do
:cert -> pem |> X509.Certificate.from_pem!() |> X509.Certificate.to_der()
:key -> pem |> X509.PrivateKey.from_pem!() |> X509.PrivateKey.to_der()
end
File.write!(output_path, der)
:ok
rescue
e in File.Error ->
{:error, "File error for #{input_path}: #{e.message}"}
e in X509.DecodeError ->
{:error, "X509 conversion error for #{input_path}: #{e.message}"}
end
end
end
So I ran this which converted the certificates to DER and saved them to my rootfs_overlay/etc/ssl directory:
mix device.certs --ca /Users/guille/repos/nerves_hub_web/test/fixtures/ssl/ca.pem --key /Users/guille/repos/nerves_hub_web/test/fixtures/ssl/device-1234-key.pem --cert /Users/guille/repos/nerves_hub_web/test/fixtures/ssl/device-1234-cert.pem
In my config.exs:
base_path = "rootfs_overlay/etc/ssl"
cert = File.read!("#{base_path}/cert.der")
key_der = File.read!("#{base_path}/key.der")
cacerts = File.read!("#{base_path}/ca.der")
config :nerves_hub_link,
remote_iex: true,
socket: [
json_library: Jason,
heartbeat_interval: 45_000
],
ssl: [cert: cert, key: {:ECPrivateKey, key_der}, cacerts: cacerts],
device_api_host: "192.168.1.163",
device_api_sni: '192.168.1.163',
device_api_port: 4001
I compiled and flashed the firmware but when the Device starts I see the following error. It seems like it can't properly handle the binary stream from the DER cert/key.
21:45:15.177 [warn] [NervesHubLink] No CA store or :cacerts have been specified. Request will fail
21:45:15.178 [error] GenServer #PID<0.2191.0> terminating
** (Protocol.UndefinedError) protocol Enumerable not implemented for <<48, 130, 1, 168, 48, 130, 1, 77, 160, 3, 2, 1, 2, 2, 21, 0, 136, 78, 75, 120, 25, 130, 154, 40, 67, 250, 98, 145, 1, 28, 77, 163, 110, 156, 2, 100, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, 48, 48, ...>> of type BitString. This protocol is implemented for the following type(s): CircularBuffer, Date.Range, File.Stream, Function, GenEvent.Stream, HashDict, HashSet, IO.Stream, Jason.OrderedObject, List, Map, MapSet, Range, Stream
(elixir 1.14.5) lib/enum.ex:1: Enumerable.impl_for!/1
(elixir 1.14.5) lib/enum.ex:166: Enumerable.reduce/3
(elixir 1.14.5) lib/enum.ex:4307: Enum.map/2
(mint 1.5.2) lib/mint/core/transport/ssl.ex:568: Mint.Core.Transport.SSL.add_partial_chain_fun/1
(mint 1.5.2) lib/mint/core/transport/ssl.ex:443: Mint.Core.Transport.SSL.add_verify_opts/2
(mint 1.5.2) lib/mint/core/transport/ssl.ex:432: Mint.Core.Transport.SSL.ssl_opts/2
(mint 1.5.2) lib/mint/core/transport/ssl.ex:328: Mint.Core.Transport.SSL.connect/4
(mint 1.5.2) lib/mint/http1.ex:133: Mint.HTTP1.connect/4
Last message: {:continue, :connect}
State: %Slipstream.Connection.State{connection_id: "a95e90b20b1c204c", trace_id: "5a184d4b2cdb5e4635c60e82050683d2", client_pid: #PID<0.2190.0>, client_ref: #Reference<0.902908580.3528196100.212553>, config: %Slipstream.Configuration{uri: %URI{scheme: "wss", authority: "192.168.1.163:4001", userinfo: nil, host: "192.168.1.163", port: 4001, path: "/socket/websocket", query: nil, fragment: nil}, heartbeat_interval_msec: 30000, headers: [], serializer: Slipstream.Serializer.PhoenixSocketV2Serializer, json_parser: Jason, reconnect_after_msec: [1096, 2036, 5935, 11595, 21504, 32890, 62803], rejoin_after_msec: [5000], mint_opts: [protocols: [:http1], transport_opts: [server_name_indication: '192.168.1.163', versions: [:"tlsv1.2"], verify: :verify_peer, cert: <<48, 130, 1, 213, 48, 130, 1, 123, 160, 3, 2, 1, 2, 2, 21, 0, 183, 38, 240, 145, 34, 215, 157, 121, 125, 226, 176, 62, 76, 89, 115, ...>>, key: {:ECPrivateKey, <<48, 119, 2, 1, 1, 4, 32, 76, 68, 12, 57, 248, 89, 250, 122, 82, 104, 126, 255, 253, 167, 150, 132, 14, 185, 177, 93, 146, ...>>}, cacerts: <<48, 130, 1, 168, 48, 130, 1, 77, 160, 3, 2, 1, 2, 2, 21, 0, 136, 78, 75, 120, 25, 130, 154, 40, 67, 250, 98, 145, 1, ...>>]]
Ok saw my error now:
config.exs
ssl: [cert: cert, key: {:ECPrivateKey, key_der}, cacerts: [cacerts]],
Seems like cacerts needs to be a list!
Now I get the following error:
22:31:25.764 [info] TLS :client: In state :certify at ssl_handshake.erl:2140 generated CLIENT ALERT: Fatal - Handshake Failure
- {:bad_cert, :hostname_check_failed}
22:31:25.766 [warn] [NervesHubLink] error: {:error, %Mint.TransportError{reason: {:tls_alert, {:handshake_failure, 'TLS client: In state certify at ssl_handshake.erl:2140 generated CLIENT ALERT: Fatal - Handshake Failure\n {bad_cert,hostname_check_failed}'}}}}
and if I set
device_api_sni: ~c"device.nerves-hub.org",
I get
22:42:35.499 [warn] [NervesHubLink] error: {:error, %Mint.TransportError{reason: {:tls_alert, {:handshake_failure, 'TLS client: In state cipher received SERVER ALERT: Fatal - Handshake Failure\n'}}}}
@guillego ca.pem
is a few certs compiled into one file. You're effectively giving one giant cacerts DER binary but it should be broken up into their individual CA DERs and then included in the list.
Or simply change your ca.pem
to be the single top level root Ca which I think should work as well
That makes a lot more sense! Refactored my CA cert conversion and loading:
On my mix task
@spec process_ca_file(String.t(), String.t()) :: :ok | {:error, String.t()}
defp process_ca_file(input_path, output_dir) do
try do
:ok = File.mkdir_p(output_dir)
input_path
|> File.read!()
|> String.split("\n\n", trim: true)
|> Enum.with_index(1)
|> Enum.map(fn {cert, index} ->
{Certificate.pem_to_der(cert), "cacert_#{pad_zero(index, 3)}.der"}
end)
|> Enum.each(fn {der, filename} -> File.write!(Path.join(output_dir, filename), der) end)
:ok
rescue
e in [File.Error, X509.DecodeError] ->
{:error, "Error processing CA file: #{e.message}"}
end
end
config.exs
cacerts = "#{base_path}/nerves_hub_ca/*.der" |> Path.wildcard() |> Enum.map(&File.read!(&1))
However I still get a Handshake failure. I'll keep investigating, seems to be closer now thanks for all the help!
08:40:44.945 [info] TLS :client: In state :cipher received SERVER ALERT: Fatal - Handshake Failure
08:40:44.946 [warn] [NervesHubLink] error: {:error, %Mint.TransportError{reason: {:tls_alert, {:handshake_failure, 'TLS client: In state cipher received SERVER ALERT: Fatal - Handshake Failure\n'}}}}
@edwardzhou hope my code helps!
Hello! Hope you've all been having great Christmas days! 🎄
I've been trying different things around this over the past few days and can't figure out what else to do 😅
Starting from scratch, steps I followed:
openssl genrsa -des3 -out nerves_hub_dev_ca.key 2048
openssl req -x509 -new -nodes -key nerves_hub_dev_ca.key -sha256 -days 1825 -out nerves_hub_dev_rootca.pem
openssl ecparam -name prime256v1 -genkey -noout -out device-40928a.pem
openssl req -new -key device-40928a.pem -out device-40928a.csr
base_path = "rootfs_overlay/etc/ssl"
cert = File.read!("#{base_path}/nerves_hub_cert.der") key_der = File.read!("#{base_path}/nerves_hub_key.der") cacerts = "#{base_path}/nerves_hub_ca/*.der" |> Path.wildcard() |> Enum.map(&File.read!(&1))
config :nerves_hub_link, remote_iex: true, socket: [ json_library: Jason, heartbeat_interval: 45_000 ], cacerts: cacerts, ssl: [cert: cert, key: {:ECPrivateKey, key_der}, cacerts: cacerts, log_level: :debug], device_api_host: "192.168.1.108", device_api_sni: ~c"device.nerves-hub.org", device_api_port: 4001
(There's only one CA cert here, the one I created in step 2 of the Device root CA section).
6. I run mix firmware and mix burn and start my device
7. See the following errors
15:37:08.379 [info] TLS :client: In state :certify at ssl_handshake.erl:2138 generated CLIENT ALERT: Fatal - Unknown CA
15:37:08.381 [warn] [NervesHubLink] error: {:error, %Mint.TransportError{reason: {:tls_alert, {:unknown_ca, 'TLS client: In state certify at ssl_handshake.erl:2138 generated CLIENT ALERT: Fatal - Unknown CA\n'}}}}
And in my nervesHubWeb:
0000 - 15 03 03 00 02 02 30 ......0 [notice] TLS :server: In state :certify received CLIENT ALERT: Fatal - Unknown CA
So it seems that even though I registered my CA it doesn't recognize it.
From what I understand I would also need to register my device into nerves hub with a command like this:
mix nerves_hub.device create --identifier 4917bafd-cb8d-4667-b6d1-1dfd1b40928a --description TestDevice --tag dev
However I can't run any of the nerves_hub_cli commands without errors, for instance this one:
NervesHub server: localhost:4001 (same error in port 4000, not sure which one I should connect to) NervesHub organization: MyNewOrg ** (ArgumentError) errors were found at the given arguments:
1st argument: not a binary
:erlang.binary_to_atom(nil, :utf8) (tesla 1.8.0) lib/tesla/adapter/mint.ex:161: Tesla.Adapter.Mint.open_conn/2 (tesla 1.8.0) lib/tesla/adapter/mint.ex:121: Tesla.Adapter.Mint.do_request/5 (tesla 1.8.0) lib/tesla/adapter/mint.ex:61: Tesla.Adapter.Mint.call/2 (tesla 1.8.0) lib/tesla/middleware/json.ex:57: Tesla.Middleware.JSON.call/3 (tesla 1.8.0) lib/tesla/middleware/follow_redirects.ex:46: Tesla.Middleware.FollowRedirects.redirect/3 (nerves_hub_cli 2.0.0-dev) lib/nerves_hub_cli/api.ex:42: NervesHubCLI.API.request/4 (nerves_hub_cli 2.0.0-dev) lib/mix/tasks/nerves_hub.device.ex:278: Mix.Tasks.NervesHub.Device.create/3
Is nerves_hub_cli still the way to do these things?
@guillego SSL is vague by design. The Unknown CA
could be referencing the device cert, signer CA, or even the NervesHub server CA which is unknown.
If your end goal here is just to get a device connected to a local instance, then I would abandon writing files and hardcode DER values directly into the application config and make the firmware. Below is a configuration which successfully connects to a fresh NervesHub instance for device-1234-cert.pem
.
It also has the config needed to use nerves_hub_cli
with the same local instance on the unauthenticated web port 4000
. First run mix nerves_hub.user auth
to create the token. Then you can run the mix tasks. (Note that you should use nerves_hub_cli
main branch as it is undergoing lots of cleanup and the latest hex releases may work differently)
```elixir # Device HTTP connection. config :nerves_hub_link, device_api_host: "192.168.1.226", device_api_port: 4001, device_api_sni: ~c"device.nerves-hub.org", configurator: NervesHubLink.Configurator.Default, ssl: [ cert: # nerves_hub_web/test/fixtures/ssl/device-1234-cert.pem <<48, 130, 1, 213, 48, 130, 1, 123, 160, 3, 2, 1, 2, 2, 21, 0, 183, 38, 240, 145, 34, 215, 157, 121, 125, 226, 176, 62, 76, 89, 115, 14, 180, 240, 210, 177, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, 48, 55, 49, 18, 48, 16, 6, 3, 85, 4, 10, 12, 9, 78, 101, 114, 118, 101, 115, 72, 117, 98, 49, 33, 48, 31, 6, 3, 85, 4, 3, 12, 24, 78, 101, 114, 118, 101, 115, 72, 117, 98, 32, 68, 101, 118, 105, 99, 101, 32, 82, 111, 111, 116, 32, 67, 65, 48, 32, 23, 13, 50, 50, 49, 50, 49, 53, 50, 48, 48, 48, 48, 48, 90, 24, 15, 50, 48, 53, 50, 49, 50, 49, 53, 50, 49, 48, 48, 48, 48, 90, 48, 39, 49, 15, 48, 13, 6, 3, 85, 4, 10, 12, 6, 106, 111, 110, 106, 111, 110, 49, 20, 48, 18, 6, 3, 85, 4, 3, 12, 11, 100, 101, 118, 105, 99, 101, 45, 49, 50, 51, 52, 48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 203, 146, 85, 193, 252, 4, 13, 190, 69, 108, 79, 5, 0, 238, 0, 150, 97, 194, 97, 148, 60, 5, 220, 228, 181, 23, 149, 150, 19, 250, 207, 220, 46, 251, 233, 10, 167, 173, 237, 143, 129, 168, 183, 54, 40, 130, 5, 95, 211, 44, 224, 18, 184, 28, 255, 250, 151, 168, 205, 188, 155, 121, 115, 234, 163, 114, 48, 112, 48, 9, 6, 3, 85, 29, 19, 4, 2, 48, 0, 48, 14, 6, 3, 85, 29, 15, 1, 1, 255, 4, 4, 3, 2, 5, 160, 48, 19, 6, 3, 85, 29, 37, 4, 12, 48, 10, 6, 8, 43, 6, 1, 5, 5, 7, 3, 2, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 250, 22, 188, 70, 156, 245, 153, 172, 82, 156, 167, 111, 51, 189, 53, 17, 130, 101, 195, 114, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, 128, 20, 202, 167, 15, 94, 238, 102, 229, 201, 146, 85, 31, 89, 159, 116, 230, 28, 193, 141, 15, 126, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, 3, 72, 0, 48, 69, 2, 33, 0, 181, 8, 140, 199, 123, 44, 193, 1, 103, 203, 56, 157, 172, 91, 213, 17, 118, 14, 81, 86, 226, 246, 235, 192, 88, 77, 110, 85, 7, 97, 156, 159, 2, 32, 28, 83, 169, 142, 175, 203, 226, 223, 118, 41, 0, 168, 100, 174, 26, 94, 82, 7, 122, 217, 90, 199, 35, 224, 24, 91, 224, 194, 115, 38, 168, 12>>, key: # nerves_hub_web/test/fixtures/ssl/device-1234-key.pem {:ECPrivateKey, <<48, 119, 2, 1, 1, 4, 32, 76, 68, 12, 57, 248, 89, 250, 122, 82, 104, 126, 255, 253, 167, 150, 132, 14, 185, 177, 93, 146, 77, 112, 213, 83, 106, 244, 176, 255, 142, 141, 139, 160, 10, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 161, 68, 3, 66, 0, 4, 203, 146, 85, 193, 252, 4, 13, 190, 69, 108, 79, 5, 0, 238, 0, 150, 97, 194, 97, 148, 60, 5, 220, 228, 181, 23, 149, 150, 19, 250, 207, 220, 46, 251, 233, 10, 167, 173, 237, 143, 129, 168, 183, 54, 40, 130, 5, 95, 211, 44, 224, 18, 184, 28, 255, 250, 151, 168, 205, 188, 155, 121, 115, 234>>}, cacerts: [ # nerves_hub_web/test/fixtures/ssl/root-ca.pem <<48, 130, 1, 168, 48, 130, 1, 77, 160, 3, 2, 1, 2, 2, 21, 0, 136, 78, 75, 120, 25, 130, 154, 40, 67, 250, 98, 145, 1, 28, 77, 163, 110, 156, 2, 100, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, 48, 48, 49, 18, 48, 16, 6, 3, 85, 4, 10, 12, 9, 78, 101, 114, 118, 101, 115, 72, 117, 98, 49, 26, 48, 24, 6, 3, 85, 4, 3, 12, 17, 78, 101, 114, 118, 101, 115, 72, 117, 98, 32, 82, 111, 111, 116, 32, 67, 65, 48, 32, 23, 13, 50, 50, 49, 50, 49, 53, 50, 48, 48, 48, 48, 48, 90, 24, 15, 50, 48, 53, 50, 49, 50, 49, 53, 50, 49, 48, 48, 48, 48, 90, 48, 48, 49, 18, 48, 16, 6, 3, 85, 4, 10, 12, 9, 78, 101, 114, 118, 101, 115, 72, 117, 98, 49, 26, 48, 24, 6, 3, 85, 4, 3, 12, 17, 78, 101, 114, 118, 101, 115, 72, 117, 98, 32, 82, 111, 111, 116, 32, 67, 65, 48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 33, 39, 185, 125, 50, 219, 186, 66, 209, 30, 159, 170, 5, 64, 110, 101, 2, 245, 141, 36, 23, 61, 49, 48, 209, 229, 106, 63, 219, 138, 217, 30, 169, 82, 52, 137, 53, 128, 210, 191, 214, 96, 50, 143, 100, 172, 111, 178, 71, 24, 51, 5, 234, 162, 180, 126, 62, 197, 139, 170, 214, 133, 69, 169, 163, 66, 48, 64, 48, 14, 6, 3, 85, 29, 15, 1, 1, 255, 4, 4, 3, 2, 1, 6, 48, 15, 6, 3, 85, 29, 19, 1, 1, 255, 4, 5, 48, 3, 1, 1, 255, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 158, 135, 68, 248, 62, 94, 43, 114, 152, 1, 154, 172, 147, 15, 142, 166, 114, 84, 48, 100, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, 3, 73, 0, 48, 70, 2, 33, 0, 238, 75, 105, 140, 209, 248, 171, 34, 40, 179, 2, 88, 96, 243, 213, 4, 205, 35, 209, 128, 137, 123, 133, 89, 112, 217, 100, 87, 114, 188, 174, 50, 2, 33, 0, 244, 57, 176, 222, 148, 112, 98, 16, 243, 98, 21, 199, 146, 211, 94, 79, 3, 252, 150, 56, 184, 214, 104, 0, 36, 215, 131, 249, 109, 243, 69, 165>> ] ] config :nerves_hub_cli, home_dir: Path.expand(".nerves-hub"), host: "192.168.1.226", port: 4000, scheme: "http" ```
This same config was used in nerves_hub_link/config/dev.exs
and ran localizing with iex -S mix
.
The problems that I see with using openssl to generate your own cert is that the entitlements are different/missing than what is typically expected for NervesHub. I'd recommend using the mix tasks for now. These run locally without making requests to a server.
$ git clone git@github.com:nerves-hub/nerves_key && cd nerves_key
$ mix nerves_key.signer create your-signer --years-valid 20
$ cd nerves_hub_web
$ mix nerves_hub.device create --identifier poser --tag poser --description "It's a poser device"
$ mix nerves_hub.device cert create poser --signer-cert nerves-hub/your-signer.cert --signer-key nerves-hub/your-signer.key
From there, you can use the CLI or just manually create the device and upload the device certificate via the web UI (which I think would be easier in your case). Once the device certificate exists in NervesHub, you do not need the signer cert registered or included in the requests.
Thanks a lot @jjcarstens! Makes sense to start with the simplest case by hardcoding the values and once that works, start to change things to a better approach.
I'll let you know how that goes in a bit.
Do I also need to register the root CA certificate in my NervesHubWeb organization like I was trying before?
What you were doing before was registering a signer CA which is only needed for JITP
The root CA fixture was used to create a cert for the DeviceEndpoint. It's just like any other server certificate for a website except that it is self-signed for local testing which is the reason you need to explicitly include it in cacerts
of a device connecting
@guillego @edwardzhou I was wondering, do you need to use SSL certs? as in, if there was a way to get this all running without SSL certs, would you be interested?
For my understanding, the original design that nerves-hub using certs here is for security between nerves-hub and trusted-devices. I'm also fine if there is any alternative. because ssl certs is such painful now.
We should have https://github.com/nerves-hub/nerves_hub_web/pull/1139 merged within the next week, possibly sooner.
This setup is great for home use or prototyping. SSL secures the transport, and the websocket connection is secured using an AWS style signature. Plus, just-in-time Device registration is supported out of the box.
This also means it is easier to run NervesHub on a PaaS (eg. I have it running on Fly.io)
This is the NervesHub Link config that goes with it : https://github.com/nerves-hub/nerves_hub_link/pull/141
Certs are still recommended for production deployments, but for most people, where they are just getting started with NervesHub, these new Shared Secrets will make it a hell of a lot easier to get up and running.
@joshk Yes! I think that would be super useful, especially as you say to get it quickly up and running on a PaaS like fly.io! All the recent PRs in NervesHubWeb look amazing and I'm really excited to see them merged and test them!
@jjcarstens Thanks A LOT for the help! I hadn't thought about using nerves_key for generating the signer certificates.
With that I was able to finally generate correct certificates and have a successful connection between my device and my local nerves hub!! 🙌
I wrote my process in this gist. Perhaps with a little more love (and some reviews) it could become documentation? @edwardzhou let me know if this helps!
HOWEVER! I created firmware signing keys and signed/published firmware but I have an error when I try to deploy new firmware versions! I'll be chasing this a bit more but here is the error in case anyone has seen it before:
01:18:28.573 [info] Resuming download attempt number 8 http://localhost:4000/firmware/3/aac59f58-51f1-586e-7f31-699c7df18812.fw
01:18:28.574 [error] [NervesHubLink] Nonfatal HTTP download error: %Mint.TransportError{reason: :econnrefused}
HOWEVER! I created firmware signing keys and signed/published firmware but I have an error when I try to deploy new firmware versions! I'll be chasing this a bit more but here is the error in case anyone has seen it before:
01:18:28.573 [info] Resuming download attempt number 8 http://localhost:4000/firmware/3/aac59f58-51f1-586e-7f31-699c7df18812.fw 01:18:28.574 [error] [NervesHubLink] Nonfatal HTTP download error: %Mint.TransportError{reason: :econnrefused}
Found the issue! It was right in front of my face. Turns out I needed to change the config in nerves_hub_web/dev.exs so that the public path to the firmware is not referenced as localhost but as the actual network hostname of the server:
This is the default config for the Endpoint:
config :nerves_hub, NervesHubWeb.Endpoint,
url: [
host: System.get_env("WEB_HOST", "localhost"),
scheme: System.get_env("WEB_SCHEME", "http"),
port: String.to_integer(System.get_env("WEB_PORT", "4000"))
],
http: [ip: {0, 0, 0, 0}, port: 4000],
So I just needed to set the env var for WEB_HOST
to my LAN IP address. Et voilá it worked!
Thanks for all the help!
HOWEVER! I created firmware signing keys and signed/published firmware but I have an error when I try to deploy new firmware versions! I'll be chasing this a bit more but here is the error in case anyone has seen it before:
01:18:28.573 [info] Resuming download attempt number 8 http://localhost:4000/firmware/3/aac59f58-51f1-586e-7f31-699c7df18812.fw 01:18:28.574 [error] [NervesHubLink] Nonfatal HTTP download error: %Mint.TransportError{reason: :econnrefused}
Found the issue! It was right in front of my face. Turns out I needed to change the config in nerves_hub_web/dev.exs so that the public path to the firmware is not referenced as localhost but as the actual network hostname of the server:
This is the default config for the Endpoint:
config :nerves_hub, NervesHubWeb.Endpoint, url: [ host: System.get_env("WEB_HOST", "localhost"), scheme: System.get_env("WEB_SCHEME", "http"), port: String.to_integer(System.get_env("WEB_PORT", "4000")) ], http: [ip: {0, 0, 0, 0}, port: 4000],
So I just needed to set the env var for
WEB_HOST
to my LAN IP address. Et voilá it worked!Thanks for all the help!
Great job. I will take a try as well.
The whole setup process is in this gist, not sure if you missed it in the previous message 😄
🎉 !!
Thanks @guillego! I'm going to close this for now as the errors seen are with configuration (and the pains of learning SSL 😢). Thanks for the gist and hopefully we can get some of those more clear instructions into the main repo to aid others as well
Thanks @jjcarstens ! Indeed the pains of learning all the moving pieces of SSL, but it was so rewarding! The issue was opened by @edwardzhou even though it seems indeed from my experience to be a config/docs problem rather than an issue with the repo itself.
Thanks for all the awesome work on Nerves/NervesHub @joshk @jjcarstens, looking forward to gaining a bit more experience to contribute.
Environment MacOSX 14.1 (23B74)
Elixir 1.15.7-otp-26 Erlang 26.1.2 nerves 1.10.4 nerves_system_rpi4 1.24.1 nerves_hub_link 2.0.0
Nerves_hub_web
vi config/dev.exs , configure ssl
device-1234-cert.pem and device-1234-key.pem and device-root-ca.pem were copied to rpi4 project, config.exs as following
but got warning on both local nerves-hub-web and device. nerves-hub-web log:
rpi4 device log: