diff --git a/DOCUMENTACION.md b/DOCUMENTACION.md
index f4b7399..60ead77 100644
--- a/DOCUMENTACION.md
+++ b/DOCUMENTACION.md
@@ -118,20 +118,36 @@ Usuario SSH.
### `password`
-Password SSH. Se guarda en `config.json`, por lo que el archivo debe permanecer protegido. Si `privateKeyPath` esta configurado, la clave privada tiene prioridad y no se usa `password`.
+Password SSH. Se guarda en `config.json`, por lo que el archivo debe permanecer protegido. Si el dispositivo usa `authMethod: "key"`, no se usa `password`.
+
+### `authMethod`
+
+Metodo de autenticacion SSH por dispositivo. Valores recomendados:
+
+- `password`: usa `username` y `password`.
+- `key`: usa `username` y la clave privada global configurada en `sshPrivateKeyPath`.
### `privateKeyPath`
-Ruta de la clave privada SSH dentro del contenedor o del host donde corre el monitor. Debe apuntar a una clave privada legible por el proceso del monitor. Para uso en Docker, monta la clave o una carpeta `.ssh` dentro del contenedor. Las claves con passphrase requieren agente SSH disponible; para monitorizacion unattended suele usarse una clave sin passphrase protegida por permisos de archivo.
+Campo heredado para configuraciones antiguas con clave privada por dispositivo. La interfaz nueva usa la clave global del monitor y deja este campo vacio.
## Autenticacion SSH por Clave Privada
El monitor soporta dos metodos de autenticacion por dispositivo:
- Password SSH: usar `password` y dejar `privateKeyPath` vacio.
-- Clave privada: dejar `password` vacio y configurar `privateKeyPath`.
+- Clave privada global: dejar `password` vacio y seleccionar `authMethod: "key"`.
-Cuando `privateKeyPath` tiene valor, el backend usa clave privada y no usa el password.
+Cuando un dispositivo tiene `authMethod: "key"`, el backend usa la clave privada global configurada en `sshPrivateKeyPath`. El campo `privateKeyPath` por dispositivo queda solo como compatibilidad con configuraciones antiguas.
+
+### Configuracion global de claves
+
+```json
+"sshPrivateKeyPath": "/ssh/monitor_rpi_ed25519",
+"sshPublicKeyPath": "/ssh/monitor_rpi_ed25519.pub"
+```
+
+La clave privada se queda solo en el monitor. La clave publica se muestra en el configurador y puede copiarse o descargarse para instalarla en las RPi remotas.
### 1. Guardar la clave privada en el volumen del monitor
@@ -144,15 +160,15 @@ En la RPi donde corre el contenedor, guarda las claves en:
Ejemplo:
```text
-/home/yamaray/docker/monitorRPi/ssh/carabanes_monitor_ed25519
-/home/yamaray/docker/monitorRPi/ssh/carabanes_monitor_ed25519.pub
+/home/yamaray/docker/monitorRPi/ssh/monitor_rpi_ed25519
+/home/yamaray/docker/monitorRPi/ssh/monitor_rpi_ed25519.pub
```
La clave privada debe quedar protegida:
```bash
chmod 700 /home/yamaray/docker/monitorRPi/ssh
-chmod 600 /home/yamaray/docker/monitorRPi/ssh/carabanes_monitor_ed25519
+chmod 600 /home/yamaray/docker/monitorRPi/ssh/monitor_rpi_ed25519
```
El `docker-compose.yml` debe montar esa carpeta dentro del contenedor:
@@ -167,8 +183,9 @@ volumes:
Dentro de la configuracion del dispositivo, la ruta debe ser la ruta vista por el contenedor:
```json
+"authMethod": "key",
"password": "",
-"privateKeyPath": "/ssh/carabanes_monitor_ed25519"
+"privateKeyPath": ""
```
### 2. Instalar la clave publica en la Raspberry destino
@@ -187,7 +204,7 @@ chmod 600 ~/.ssh/authorized_keys
En `authorized_keys` pega el contenido de la clave publica:
```text
-carabanes_monitor_ed25519.pub
+monitor_rpi_ed25519.pub
```
El archivo correcto en Linux/OpenSSH es:
@@ -203,13 +220,13 @@ No es `authorised_keys`.
Una vez montada la clave, puedes probar desde la RPi host:
```bash
-docker exec -it monitor-rpi ssh -i /ssh/carabanes_monitor_ed25519 -o IdentitiesOnly=yes pi@HOST_REMOTO
+docker exec -it monitor-rpi ssh -i /ssh/monitor_rpi_ed25519 -o IdentitiesOnly=yes pi@HOST_REMOTO
```
Si el dispositivo usa un puerto distinto:
```bash
-docker exec -it monitor-rpi ssh -i /ssh/carabanes_monitor_ed25519 -o IdentitiesOnly=yes -p 34000 pi@192.168.0.1
+docker exec -it monitor-rpi ssh -i /ssh/monitor_rpi_ed25519 -o IdentitiesOnly=yes -p 34000 pi@192.168.0.1
```
Si la conexion funciona sin pedir password, el monitor tambien podra consultar ese dispositivo.
diff --git a/config.example.json b/config.example.json
index 9061fd3..357849c 100644
--- a/config.example.json
+++ b/config.example.json
@@ -3,6 +3,8 @@
"refreshIntervalSeconds": 30,
"idleScanIntervalSeconds": 300,
"sshTimeoutSeconds": 8,
+ "sshPrivateKeyPath": "/ssh/monitor_rpi_ed25519",
+ "sshPublicKeyPath": "/ssh/monitor_rpi_ed25519.pub",
"temperatureThresholdsC": {
"warning": 60,
"hot": 70,
@@ -37,6 +39,7 @@
"host": "192.168.0.46",
"username": "pi",
"password": "",
+ "authMethod": "password",
"privateKeyPath": "",
"role": "Home Assistant Local",
"port": 22,
@@ -50,6 +53,7 @@
"host": "192.168.0.57",
"username": "pi",
"password": "",
+ "authMethod": "password",
"privateKeyPath": "",
"role": "Home Assistant CabaƱa",
"port": 22,
@@ -63,6 +67,7 @@
"host": "192.168.0.53",
"username": "yamaray",
"password": "",
+ "authMethod": "password",
"privateKeyPath": "",
"role": "Docker",
"port": 22,
@@ -76,6 +81,7 @@
"host": "192.168.0.130",
"username": "pi",
"password": "",
+ "authMethod": "password",
"privateKeyPath": "",
"role": "Docker - Daniel",
"port": 22,
@@ -89,6 +95,7 @@
"host": "192.168.0.254",
"username": "yamaray",
"password": "",
+ "authMethod": "password",
"privateKeyPath": "",
"role": "nginx - wireguard ",
"port": 22,
@@ -102,6 +109,7 @@
"host": "192.168.0.37",
"username": "pi",
"password": "",
+ "authMethod": "password",
"privateKeyPath": "",
"role": "MQTT - varios",
"port": 22,
@@ -115,6 +123,7 @@
"host": "192.168.0.60",
"username": "yamaray",
"password": "",
+ "authMethod": "password",
"privateKeyPath": "",
"role": "Meshcore-Interface",
"port": 22,
@@ -128,6 +137,7 @@
"host": "192.168.1.47",
"username": "pi",
"password": "",
+ "authMethod": "password",
"privateKeyPath": "",
"role": "Reserva",
"port": 22,
diff --git a/config.html b/config.html
index 81ae6ce..f24ec0b 100644
--- a/config.html
+++ b/config.html
@@ -154,6 +154,45 @@
gap: 10px;
}
+ .ssh-key-panel {
+ margin-top: 16px;
+ display: grid;
+ gap: 12px;
+ padding: 12px;
+ border: 1px solid var(--line);
+ border-radius: 16px;
+ background: var(--panel-2);
+ }
+
+ .ssh-key-fields {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(220px, 1fr));
+ gap: 10px;
+ }
+
+ .public-key-box {
+ display: grid;
+ gap: 8px;
+ }
+
+ .public-key-box textarea {
+ width: 100%;
+ min-height: 78px;
+ resize: vertical;
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ background: var(--input);
+ color: var(--text);
+ padding: 10px;
+ font: 13px ui-monospace, "Cascadia Code", Consolas, monospace;
+ }
+
+ .public-key-actions {
+ display: flex;
+ gap: 8px;
+ flex-wrap: wrap;
+ }
+
.threshold-row {
display: grid;
grid-template-columns: 110px repeat(3, minmax(120px, 1fr));
@@ -198,9 +237,8 @@
.field-port { grid-column: span 1; }
.field-username { grid-column: span 2; }
.field-auth { grid-column: span 2; }
- .password-credential, .key-credential { grid-column: span 4; }
+ .password-credential { grid-column: span 4; }
.field-delete { grid-column: span 2; }
- .device[data-auth-method="password"] .key-credential { display: none; }
.device[data-auth-method="key"] .password-credential { display: none; }
.credential-note {
@@ -262,6 +300,17 @@
}
button:hover, a:hover { border-color: var(--info); }
+ .secondary-action {
+ background: var(--panel);
+ border-color: var(--info);
+ color: var(--info);
+ font-weight: 650;
+ }
+
+ .secondary-action:hover {
+ background: color-mix(in srgb, var(--info) 18%, var(--panel));
+ }
+
.danger {
background: var(--offline-bg);
border-color: var(--offline-line);
@@ -396,11 +445,12 @@
@media (max-width: 1180px) {
.device { grid-template-columns: repeat(6, minmax(0, 1fr)); align-items: start; }
- .field-name, .field-role, .field-host, .password-credential, .key-credential { grid-column: span 3; }
+ .field-name, .field-role, .field-host, .password-credential { grid-column: span 3; }
.field-id, .field-model, .field-location, .field-username, .field-auth, .field-active, .field-delete { grid-column: span 2; }
.field-port { grid-column: span 1; }
.credential-note { grid-column: span 4; }
.top-grid { grid-template-columns: repeat(2, 1fr); }
+ .ssh-key-fields { grid-template-columns: 1fr; }
.threshold-row { grid-template-columns: 90px repeat(3, minmax(100px, 1fr)); }
}
@@ -410,7 +460,7 @@
.top-grid, .device { grid-template-columns: 1fr; }
.field-active, .field-name, .field-id, .field-role, .field-model, .field-location,
.field-host, .field-port, .field-username, .field-auth, .password-credential,
- .key-credential, .credential-note, .field-delete { grid-column: span 1; }
+ .credential-note, .field-delete { grid-column: span 1; }
.threshold-row { grid-template-columns: 1fr; }
}
@@ -452,6 +502,26 @@
+
+
Clave SSH del monitor
+
+
+
+
+
+
+
+
+
Temperatura
@@ -588,9 +658,10 @@
const devicesEl = document.querySelector("#devices");
const statusEl = document.querySelector("#status");
const dashboardLink = document.querySelector("#dashboardLink");
+ const publicKeyEl = document.querySelector("#sshPublicKey");
function deviceTemplate(device, index) {
- const authMethod = device.privateKeyPath ? "key" : "password";
+ const authMethod = device.authMethod || (device.privateKeyPath ? "key" : "password");
return `