Una solución de control remoto y secuencias de comandos remotas, creada con .NET, Blazor y SignalR Core.
¡Estoy buscando mantenedores que me ayuden! Si es un desarrollador de .NET y está interesado en ayudar a seguir avanzando de forma remota, envíeme un DM en Discord a jaredatimmy
.
Subreddit: https://www.reddit.com/r/remotely_app/
Docker: https://hub.docker.com/r/immybot/remotely
Tutorial: https://www.youtube.com/watch?v=t-TFvr7sZ6M (¡Gracias, @bmcgonag!)
mkdir -p /var/www/remotely wget -q https://raw.githubusercontent.com/immense/Remotely/master/docker-compose/docker-compose.yml docker-compose up -d
El único proxy inverso admitido es Caddy, y sólo cuando está directamente frente a Internet. La configuración predeterminada de Caddy proporciona todo lo que ASP.NET Core y SignalR necesitan para funcionar correctamente.
Si tiene problemas de red con cualquier otra configuración, como con un firewall adicional o con Nginx, busque soporte de la comunidad en la pestaña Discusiones, en Reddit u otro sitio social. Los mantenedores remotos simplemente no pueden proporcionar orientación y soporte para todas las configuraciones posibles del entorno.
Dicho esto, ASP.NET Core requiere que se establezcan los siguientes encabezados cuando se está detrás de un proxy inverso: X-Forwarded-Proto
, X-Forwarded-Host
y X-Forwarded-For
. Estos se correlacionan con el esquema (http/https), la URL de la solicitud original y la dirección IP del cliente, respectivamente. El esquema y el host resultantes se inyectan en los instaladores y clientes de escritorio, para que sepan dónde enviar las solicitudes. La dirección IP del cliente se utiliza en la información del dispositivo.
El código de forma remota no analiza ni maneja estos valores. Se realiza internamente mediante el middleware integrado de ASP.NET Core. Si los valores no aparecen como se esperaba, es porque faltaban encabezados, no contenían los valores correctos, no estaban en el formato correcto o no provenían de una cadena de servidores proxy conocidos (ver más abajo).
Para evitar ataques de inyección, ASP.NET Core acepta de forma predeterminada solo encabezados reenviados desde direcciones de bucle invertido. De forma remota también agregará la IP de la puerta de enlace de Docker (172.28.0.1) definida en el archivo docker-compose. Si está utilizando una configuración no predeterminada, debe agregar todas las direcciones de firewall y proxy inverso a la matriz KnownProxies
en Server Config.
Si no puede configurar correctamente sus servidores proxy inversos, al menos puede forzar el uso del esquema HTTPS configurando Force Client HTTPS
en la página de configuración del servidor.
La documentación completa de Microsoft sobre el tema se puede encontrar aquí: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer
Los datos de forma remota se guardarán en el contenedor en /app/AppData
, que se montará en /var/www/remotely/
en su host Docker.
Esta carpeta contendrá Remotely.db y los registros generados por el servidor.
Estos archivos persistirán durante el desmontaje y la configuración de nuevos contenedores de forma remota.
Si actualiza desde una versión de Remotely que no es Docker, sobrescriba el archivo DB de su instalación anterior.
Utilice Caddy como proxy inverso si desea exponer el sitio a Internet.
Si esta es la primera vez, cree su cuenta haciendo clic en el botón Register
en la página principal.
Las organizaciones se utilizan para agrupar usuarios, dispositivos y otros elementos de datos en un solo grupo.
De forma predeterminada, solo puede existir una organización en un servidor.
El botón Register
desaparecerá.
Las personas ya no podrán crear cuentas por sí mismas.
Para permitir el autorregistro, aumente MaxOrganizationCount
o configúrelo en -1 (consulte la sección Configuración).
Esta cuenta será tanto el administrador del servidor como el administrador de la organización.
Se crea automáticamente una organización para la cuenta.
Puede habilitar el registro HTTP para ver todas las solicitudes y respuestas en los registros del servidor, incluidos los encabezados. Esto puede resultar útil para depurar problemas de proxy inverso, API o SignalR. La opción se puede habilitar en la página de configuración del servidor.
Después de cambiar lo anterior, debe reiniciar el contenedor para que los cambios surtan efecto.
Los siguientes pasos configurarán su máquina con Windows 11 para construir el servidor y los clientes de forma remota.
Instale Visual Studio 2022.
SDK de .NET (última versión).
MSBuild (que selecciona automáticamente los compiladores Roslyn).
Objetivos de NuGet y tareas de compilación.
SDK de .NET Framework 4.8.
Para la depuración y el desarrollo, necesitará todas las cargas de trabajo relevantes.
ASP.NET y desarrollo web
Desarrollo de escritorio .NET
Desarrollo multiplataforma .NET Core
Enlace: https://visualstudio.microsoft.com/downloads/
Debería tener seleccionadas las siguientes cargas de trabajo:
Debe tener seleccionados los siguientes componentes individuales:
Instale Git para Windows.
Enlace: https://git-scm.com/downloads
Instale el último nodo LTS:
Enlace: https://nodejs.org/
Clona el repositorio de git: git clone https://github.com/immense/Remotely --recurse
Al depurar, el agente utilizará una ID de dispositivo predefinida y se conectará a https://localhost:5001.
En el entorno de desarrollo, el servidor asignará todos los agentes conectados a la primera organización.
Los dos anteriores le permiten depurar el agente y el servidor juntos y ver su dispositivo en la lista.
La primera cuenta creada será la de administrador tanto del servidor como de la organización creada para la cuenta.
Un administrador de la organización tiene acceso a la página de la organización y a las entradas de registro del servidor específicas de su organización. Un administrador del servidor tiene acceso a la página de configuración del servidor y puede ver las entradas del registro del servidor que no pertenecen a una organización.
Dentro de la sección Cuenta, hay una pestaña para la marca, que se aplicará a los clientes de soporte rápido y al instalador de Windows.
Sin embargo, los clientes deberán haber sido creados desde la fuente con la URL del servidor codificada en las aplicaciones para que puedan recuperar la información de la marca.
El proveedor de la base de datos, las cadenas de conexión y el puerto ASP.NET Core se pueden configurar mediante variables de entorno en docker-compose.yml
.
El resto de la configuración se realiza en la página Configuración del servidor una vez que haya iniciado sesión.
AllowApiLogin: si se permite el inicio de sesión a través del controlador API. Se recomiendan tokens de acceso API en lugar de este enfoque.
Dispositivos prohibidos: una serie de ID de dispositivos, nombres o direcciones IP para prohibir. Cuando intenten conectarse, se enviará inmediatamente un comando de desinstalación.
DataRetentionInDays: cuánto tiempo se conservarán los registros y otros datos en el servidor. Establezca en -1 para retener indefinidamente (no recomendado).
DBProvider: determina cuál de las tres cadenas de conexión (en la parte superior) se utilizará. El proveedor de base de datos apropiado para el tipo de base de datos se carga automáticamente en el código.
EnableWindowsEventLog: si se deben agregar también entradas de registro del servidor al registro de eventos de Windows.
EnforceAttendedAccess: se solicitará a los clientes que permitan intentos de control remoto desatendidos.
EnableRemoteControlRecording: si se guardan grabaciones de sesiones de control remoto en el servidor.
Se guardarán en /app/AppData/recordings
.
Su retención se rige por DataRetentionInDays
.
ForceClientHTTPS: obliga a los instaladores y clientes de escritorio a utilizar el esquema HTTPS, incluso si los encabezados reenviados están mal configurados.
KnownProxies: si su proxy inverso está en una máquina diferente y reenvía solicitudes al servidor remoto, deberá agregar la IP del servidor proxy inverso a esta matriz.
MaxOrganizationCount: de forma predeterminada, puede existir una organización en el servidor, que se crea automáticamente cuando se registra la primera cuenta. Posteriormente, se desactivará el autorregistro.
Establezca esto en -1 o increméntelo a un número específico para permitir el arrendamiento múltiple.
RedirectToHttps: si ASP.NET Core redirigirá todo el tráfico de HTTP a HTTPS. Esto es independiente de las configuraciones de Caddy, Nginx e IIS que hacen lo mismo.
RemoteControlNotifyUsers: si se debe mostrar una notificación al usuario final cuando se inicia una sesión de control remoto desatendida.
RemoteControlRequiresAuthentication: si la página de control remoto requiere autenticación para establecer una conexión.
Require2FA: requiere que los usuarios configuren 2FA antes de poder usar la aplicación principal.
Smpt-: configuración SMTP para correos electrónicos del sistema generados automáticamente (como registro y restablecimiento de contraseña).
Tema: El tema de color que se utilizará para el sitio. Los valores son "Claro" u "Oscuro". Esto también se puede configurar por usuario en Cuenta - Opciones.
TrustedCorsOrigins: para solicitudes de API de origen cruzado a través de JavaScript. Los sitios web enumerados en esta matriz podrán realizar solicitudes a la API. Esto no otorga autenticación, que todavía es necesaria en la mayoría de los puntos finales.
UseHsts: si ASP.NET Core utilizará seguridad de transporte estricta HTTP.
UseHttpLogging: habilita el registro para todas las solicitudes HTTP. También habilita entradas de registro adicionales en ClientDownloadsController
con respecto al esquema efectivo, el host y la dirección IP remota como resultado del procesamiento de encabezados reenviados.
Debe establecer explícitamente un nivel de registro para Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware
para que esto funcione. Consulte appsettings.json para ver un ejemplo.
De forma predeterminada, de forma remota utiliza una base de datos SQLite. Cuando se ejecuta por primera vez, crea un archivo según lo especificado para la cadena de conexión SQLite en appsettings.json.
Puede cambiar la base de datos cambiando DBProvider
en ApplicationOptions
a SQLServer
o PostgreSQL
.
En los clientes, los registros se mantienen en %ProgramData%RemotelyLogs
Dentro del contenedor del servidor, los registros se escribirán en /app/AppData/logs
, que (de forma predeterminada) se montará en /var/www/remotely/Logs
en el host.
Los registros integrados de ASP.NET Core se escriben en la consola (stdout). Puede redirigir esto a un archivo si lo desea.
En IIS, esto se puede hacer en el archivo web.config estableciendo stdoutLogEnabled en verdadero.
En servidores Windows, los registros anteriores también se pueden escribir en el registro de eventos de Windows.
Esto se habilita en la configuración del servidor configurando EnableWindowsEventLog en verdadero.
Puede configurar niveles de registro y otras configuraciones en appsettings.json.
Más información: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/
Windows: solo se prueba la última versión de Windows 11. Windows 7 y 8.1 deberían funcionar, aunque el rendimiento se reducirá en Windows 7.
Windows 2019/2022 también debería funcionar, pero no se prueba con regularidad.
Linux: solo se prueba la última versión LTS de Ubuntu.
Para el cliente de "soporte rápido" de Ubuntu, primero debe instalar las siguientes dependencias:
libc6-dev
libxtst-dev
xclip
libx11-dev
libxrandr-dev
Lo ideal sería realizar el control remoto desde una computadora o computadora portátil real. Sin embargo, he intentado que el control remoto sea al menos algo utilizable desde un dispositivo móvil. Aquí están los controles:
Clic izquierdo: un solo toque
Haga clic con el botón derecho: mantenga presionado y luego suelte
Hacer clic y arrastrar: mantenga presionado y luego arrastre
Hay una página en /get-support
donde los usuarios finales pueden solicitar soporte. Cuando se envía el formulario, aparece una alerta en la página principal, encima de la cuadrícula.
Se coloca un acceso directo a esta página en la carpeta Program FilesRemotely
. Puedes copiarlo donde quieras. También puede copiarlo en el escritorio automáticamente usando el interruptor -supportshortcut
en el instalador.
.NET tiene dos métodos de implementación: dependiente del marco y autónomo.
Las implementaciones dependientes del marco requieren que el tiempo de ejecución .NET esté instalado en las computadoras de destino. Debe ser la misma versión que se utilizó para crear la aplicación.
Las implementaciones autónomas incluyen una copia del tiempo de ejecución, por lo que no es necesario instalarlo en las computadoras de destino. Como resultado, el tamaño total del archivo es mucho mayor.
.NET utiliza identificadores de tiempo de ejecución a los que se dirige la construcción.
Enlace: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
Hay algunas teclas de acceso directo disponibles cuando se usa la consola.
/ : Slash te permitirá cambiar entre shells. Los nombres se pueden configurar en la página Opciones.
Arriba/Abajo: utilice la flecha arriba/abajo para recorrer el historial de entradas.
Ctrl + Q: borra la ventana de salida.
El puerto de host (lado izquierdo) se puede configurar en docker-compose.yml
. El puerto del contenedor (lado derecho) no debe cambiarse. Consulte los documentos de redacción para obtener más detalles.
De forma remota tiene una API básica, que se puede explorar en https://{your_server_url}/swagger
. La mayoría de los puntos finales requieren autenticación a través de un token de acceso API, que se puede crear yendo a Cuenta - Acceso API.
Al acceder a la API desde el navegador en otro sitio web, deberá configurar CORS en appsettings agregando la URL de origen del sitio web a la matriz TrustedCorsOrigins. Si no está familiarizado con cómo funciona CORS, le recomiendo leerlo antes de continuar. Por ejemplo, si quisiera crear un formulario de inicio de sesión en https://exmaple.com que iniciara sesión en la API remota, necesitaría agregar "https://example.com" a TrustedCorsOrigins.
Cada solicitud a la API debe tener un encabezado denominado "X-Api-Key". El valor debe ser el ID y el secreto de la clave API, separados por dos puntos (es decir, [ApiKey]:[ApiSecret]).
A continuación se muestra un ejemplo de solicitud de API:
POST https://localhost:5001/API/Scripting/ExecuteCommand/PSCore/f2b0a595-5ea8-471b-975f-12e70e0f3497 HTTP/1.1 Content-Type: application/json X-Api-Key: 31fb288d-af97-4ce1-ae7b-ceebb98281ac:HLkrKaZGExYvozSPvcACZw9awKkhHnNK User-Agent: PostmanRuntime/7.22.0 Accept: */* Cache-Control: no-cache Host: localhost:5001 Accept-Encoding: gzip, deflate, br Content-Length: 12 Connection: close Get-Location
A continuación se muestran ejemplos del uso de la API de inicio de sesión basada en cookies (JavaScript):
// Log in with one request, then launch remote control with another. fetch("https://localhost:5001/api/Login/", { method: "post", credentials: "include", mode: "cors", body: '{"email":"[email protected]", "password":"P@ssword1"}', headers: { "Content-Type": "application/json", } }).then(response=>{ if (response.ok) { fetch("https://localhost:44351/api/RemoteControl/Viewer/b68c24b0-2c67-4524-ad28-dadea7a576a4", { method: "get", credentials: "include", mode: "cors" }).then(response=>{ if (response.ok) { response.text().then(url=>{ window.open(url); }) } }) } }) // Log in and launch remote control in the same request. fetch("https://localhost:5001/api/RemoteControl/Viewer/", { method: "post", credentials: "include", mode: "cors", body: '{"email":"[email protected]", "password":"P@ssword1", "deviceID":"b68c24b0-2c67-4524-ad28-dadea7a576a4"}', headers: { "Content-Type": "application/json", } }).then(response=>{ if (response.ok) { response.text().then(url=>{ window.open(url); }) } })
La API de alertas le brinda la posibilidad de agregar funciones de monitoreo y alertas a los puntos finales de su dispositivo. Esta característica está destinada a agregar una funcionalidad básica de tipo RMM sin alejarse demasiado del propósito principal de Remotely.
Las alertas se pueden configurar para mostrar una notificación en el sitio web de Remotely, enviar un correo electrónico y/o realizar una solicitud de API por separado.
Para usar Alertas, primero deberá crear un token API (o varios tokens) para que lo utilicen sus dispositivos. Luego cree una tarea programada o algún otro script recurrente para realizar el trabajo. A continuación se muestra un ejemplo de cómo usar PowerShell para crear un trabajo programado que verifica el espacio en disco diariamente.
$Trigger = New-JobTrigger -Daily -At "5 AM" $Option = New-ScheduledJobOption -RequireNetwork Register-ScheduledJob -ScriptBlock { $OsDrive = Get-PSDrive -Name C $FreeSpace = $OsDrive.Free / ($OsDrive.Used + $OsDrive.Free) if ($FreeSpace -lt .1) { Invoke-WebRequest -Uri "https://localhost:5001/api/Alerts/Create/" -Method Post -Headers @{ X-Api-Key="3e9d8273-1dc1-4303-bd50-7a133e36b9b7:S+82XKZdvg278pSFHWtUklqHENuO5IhH" } -Body @" { "AlertDeviceID": "f2b0a595-5ea8-471b-975f-12e70e0f3497", "AlertMessage": "Low hard drive space. Free Space: $([Math]::Round($FreeSpace * 100))%", "ApiRequestBody": null, "ApiRequestHeaders": null, "ApiRequestMethod": null, "ApiRequestUrl": null, "EmailBody": "Low hard drive space for device Maker.", "EmailSubject": "Hard Drive Space Alert", "EmailTo": "[email protected]", "ShouldAlert": true, "ShouldEmail": true, "ShouldSendApiRequest": false } "@ -ContentType "application/json" } } -Name "Check OS Drive Space" -Trigger $Trigger -ScheduledJobOption $Option