Felipe Hernández

Ingeniero Civil Industrial · Control de Gestión · Soluciones a medida (.NET / SQL Server)

Sentinel: encender máquinas críticas de forma remota con Wake-on-LAN

17 jun. 2026 · Felipe Hernández · 7 min
Homelab Software #homelab #wake-on-lan #docker #dotnet #csharp #self-hosted
Sentinel: encender máquinas críticas de forma remota con Wake-on-LAN

Hay una clase de equipos en cualquier homelab —o en cualquier oficina chica— que no quiero tener encendidos 24×7: consumen energía, hacen ruido, generan calor y se desgastan. Pero son críticos: un NAS de almacenamiento, un servidor con la VM que necesito, el equipo de respaldos. El problema clásico es que el día que los necesito, estoy fuera de casa. Y un equipo apagado no se enciende solo con un ping.

La solución a ese problema tiene casi 30 años y se llama Wake-on-LAN. Lo que armé es la pieza que faltaba para usarlo cómodo desde el celular: Sentinel, un centinela liviano que monitorea mis equipos y los despierta con un botón, corriendo en un contenedor Docker dentro de un equipito que siempre está encendido.

Este post documenta cómo funciona, el detalle que rompe el WOL en el 90% de los intentos, y los requisitos reales del lado del equipo que quieres despertar. El proyecto es open source (MIT, en GitHub).

Qué es (y qué no es)

Sentinel es una app ASP.NET Core en .NET 10 que hace tres cosas:

  • Monitorea una lista de equipos por ping ICMP y chequeo de puertos TCP.
  • Enciende cualquiera de ellos enviando un paquete mágico de Wake-on-LAN.
  • Expone un dashboard web (una tarjeta por equipo, con estado y botón "Encender") y una API REST para integrarlo con scripts, Home Assistant o un bot.

No es un orquestador, ni reemplaza un IPMI/iLO. Es deliberadamente simple: un solo contenedor, sin base de datos, con la lista de equipos en un archivo JSON editable en caliente desde el propio dashboard.

La clave de diseño es dónde corre: en un equipo de muy bajo consumo que está siempre encendido y que, idealmente, arranca solo cuando vuelve la corriente. En mi caso es un mini-dispositivo ARM, pero sirve cualquier cosa que aguante un contenedor liviano. Ese equipito es el "centinela" que queda vivo para despertar a los grandes cuando hace falta.

El corazón: el paquete mágico

Wake-on-LAN es engañosamente simple. El "paquete mágico" es un datagrama que contiene 6 bytes 0xFF seguidos de 16 repeticiones de la MAC del equipo destino. Nada más. La NIC del equipo apagado —que sigue con energía de standby— escucha ese patrón y le da la orden de encender a la placa.

Construirlo y enviarlo son unas pocas líneas:

// 6 bytes 0xFF + 16 repeticiones de la MAC = 102 bytes
var packet = new byte[6 + 16 * 6];
for (var i = 0; i < 6; i++)
    packet[i] = 0xFF;
for (var i = 0; i < 16; i++)
    Array.Copy(mac, 0, packet, 6 + i * 6, 6);

using var client = new UdpClient { EnableBroadcast = true };
var endpoint = new IPEndPoint(IPAddress.Parse(broadcastAddress), port);

// Se envía dos veces por si se pierde el primer datagrama UDP.
await client.SendAsync(packet, packet.Length, endpoint);
await client.SendAsync(packet, packet.Length, endpoint);

Se manda por UDP broadcast al puerto 9 (o 7). Como es broadcast y el equipo destino está apagado (no tiene IP activa), no hay handshake ni confirmación: disparas y rezas. Por eso se envía dos veces.

El detalle que rompe el WOL: la red de Docker

Acá está el 90% de los "no me funciona el Wake-on-LAN". El paquete mágico es un broadcast de capa 2. Si metes Sentinel en un contenedor con la red bridge por defecto de Docker, ese broadcast se queda dentro de la red virtual del contenedor y nunca sale a tu LAN física. El botón "Encender" parece funcionar, no da error… y no enciende nada.

La solución es correr el contenedor en network_mode: host, para que comparta la pila de red del anfitrión y el broadcast salga de verdad a la LAN:

services:
  sentinel:
    image: ghcr.io/mrphipes/sentinel:latest
    network_mode: host          # imprescindible para el broadcast L2 (y el ping)
    restart: unless-stopped
    volumes:
      - ./data:/app/data        # lista de equipos persistente

¿No puedes usar host networking (por ejemplo en algunos NAS o paneles que no lo exponen)? Entonces no uses el broadcast global 255.255.255.255: configura el broadcast dirigido de tu subred192.168.1.255 para una 192.168.1.0/24— que el router sí sabe entregar dentro del segmento.

Monitoreo que no miente: ping o puerto

Para el estado de cada equipo no me confío solo del ping: hay equipos que bloquean ICMP por firewall y aparecerían "caídos" estando perfectamente vivos. Sentinel hace doble chequeo y reporta un equipo como en línea si responde el ping o si alguno de sus puertos TCP está abierto:

{
  "Id": "nas",
  "Name": "NAS de casa",
  "Host": "192.168.1.10",
  "MacAddress": "AA:BB:CC:DD:EE:01",
  "Ports": [
    { "Name": "SMB", "Number": 445 },
    { "Name": "SSH", "Number": 22 }
  ]
}

Así el dashboard te dice no solo "está prendido", sino "está prendido y el SMB ya responde" —que es lo que de verdad te importa cuando lo despertaste para usar un servicio puntual.

La API REST acompaña esa lógica:

# Estado en vivo de todos los equipos
curl http://centinela.local:8080/api/devices

# Encender el NAS
curl -X POST http://centinela.local:8080/api/devices/nas/wake

Ese segundo curl es lo que me permite automatizar: un acceso directo en el celular, una Shortcut, o un comando de un bot pueden encender el NAS antes de que llegue a casa.

Lo que casi nadie te dice: los requisitos del equipo a despertar

El emisor es la parte fácil. Lo que falla silenciosamente es el receptor. Para que un equipo se deje despertar:

  1. WOL habilitado en la BIOS/UEFI del equipo ("Wake on LAN", "Power On by PCI-E", según la placa).
  2. WOL habilitado en la NIC desde el sistema operativo. En Linux se verifica con ethtool <iface>: la línea Supports Wake-on: debe incluir una g (magic packet) y Wake-on: debe estar en g (no en d de disabled). Se activa con ethtool -s <iface> wol g —y ojo, muchas distros no lo persisten entre reinicios, así que hay que dejarlo en un script de arranque.
  3. El equipo debe conservar energía en la NIC: apagado suave o suspendido, no desenchufado.

Y la advertencia más importante, que confunde a todo el mundo:

Wake-on-LAN no te salva de un corte de luz. Si se va la corriente, la NIC se queda sin energía de standby y no hay paquete mágico que valga. Para ese escenario lo correcto es la opción de UEFI "Restore on AC Power Loss = Power On" (que el equipo arranque solo al volver la luz). Son mecanismos distintos y complementarios: WOL para despertar a demanda, AC power recovery para sobrevivir cortes. Idealmente quieres los dos.

Empaquetado para vivir en un equipo mínimo

Como el centinela vive en un dispositivo ARM de bajo consumo, la imagen se construye multi-arquitectura (amd64 + arm64 + arm/v7) con GitHub Actions y se publica en ghcr.io. La base es Alpine —la imagen Debian por defecto de .NET no trae arm32— y se cross-compila para no emular el SDK ARM, que sería dolorosamente lento.

El resultado es un contenedor de pocas decenas de MB que arranca en un par de segundos y se reinicia solo después de un corte de luz gracias a restart: unless-stopped. Exactamente lo que quiero de un equipo que tiene un solo trabajo: estar siempre ahí para despertar a los demás.

Conclusión

Wake-on-LAN es una tecnología vieja, pero el problema que resuelve —tener apagado lo que no necesito encendido, sin perder la capacidad de levantarlo a distancia— sigue tan vigente como siempre. Lo que faltaba era la pieza cómoda alrededor: un centinela liviano, con dashboard y API, que viva en el equipo que nunca se apaga.

Si vas a montar algo así, recuerda los dos puntos que cuestan tiempo: network_mode: host en el emisor y ethtool ... wol g persistente en el receptor. Con eso resuelto, encender el NAS desde el celular a tres cuadras de la casa deja de ser un truco y pasa a ser parte de la rutina.


Comentarios (0)