#!/usr/bin/env bash # Enable Wake-on-LAN on the primary network interface of a Proxmox/Debian host # Automates: https://i12bretro.github.io/tutorials/0608.html # - Installs ethtool # - Detects the primary network interface # - Checks WOL support # - Enables WOL and configures persistence via /etc/network/interfaces # - Verifies configuration # - Prints the MAC address and hostname set -euo pipefail # --- Helper functions -------------------------------------------------------- err() { echo "ERROR: $*" >&2 exit 1 } info() { echo "[*] $*" } # --- Preconditions ----------------------------------------------------------- if [[ $EUID -ne 0 ]]; then err "This script must be run as root (sudo)." fi if ! command -v ip >/dev/null 2>&1; then err "The 'ip' command is required but not found." fi # --- Install ethtool --------------------------------------------------------- if ! command -v ethtool >/dev/null 2>&1; then info "Installing ethtool..." apt-get update -y >/dev/null apt-get install -y ethtool >/dev/null else info "ethtool already installed." fi # --- Detect primary network interface ---------------------------------------- # 1) Try to get interface from default route PRIMARY_IF=$(ip route 2>/dev/null | awk '/default/ {print $5; exit}') # 2) Fallback: first interface with a private IPv4 address if [[ -z "${PRIMARY_IF:-}" ]]; then PRIMARY_IF=$(ip -o -4 addr show scope global | \ awk ' { split($4, a, "/"); ip = a[1]; if (ip ~ /^10\./ || ip ~ /^192\.168\./ || ip ~ /^172\.(1[6-9]|2[0-9]|3[0-1])\./) { print $2; exit; } }') fi [[ -n "${PRIMARY_IF:-}" ]] || err "Could not automatically determine primary network interface." info "Detected primary interface: ${PRIMARY_IF}" # --- Get MAC address & IP ---------------------------------------------------- MAC_ADDR=$(ip -o link show "$PRIMARY_IF" | awk '{for (i=1; i<=NF; i++) if ($i=="link/ether") print $(i+1)}') IP_ADDR=$(ip -o -4 addr show "$PRIMARY_IF" | awk '{print $4}') [[ -n "${MAC_ADDR:-}" ]] || err "Could not determine MAC address for interface ${PRIMARY_IF}." [[ -n "${IP_ADDR:-}" ]] || info "No IPv4 address detected on ${PRIMARY_IF} (continuing anyway)." info "Interface ${PRIMARY_IF} MAC: ${MAC_ADDR}" [[ -n "${IP_ADDR:-}" ]] && info "Interface ${PRIMARY_IF} IP: ${IP_ADDR}" # --- Check WOL support ------------------------------------------------------- info "Checking WOL support on ${PRIMARY_IF}..." ETHTOOL_OUTPUT=$(ethtool "$PRIMARY_IF" 2>/dev/null || true) [[ -n "$ETHTOOL_OUTPUT" ]] || err "ethtool failed on ${PRIMARY_IF}. Does this interface exist and support ethtool?" SUPPORTS_WOL=$(awk -F: '/Supports Wake-on/ {gsub(/ /,"",$2); print $2}' <<<"$ETHTOOL_OUTPUT") if [[ "$SUPPORTS_WOL" != *g* ]]; then err "Interface ${PRIMARY_IF} does NOT support Wake-on: g (Supports Wake-on: ${SUPPORTS_WOL}). Aborting." fi info "Interface ${PRIMARY_IF} supports Wake-on: g." # --- Enable WOL immediately -------------------------------------------------- info "Enabling WOL (g) on ${PRIMARY_IF} now..." ethtool -s "$PRIMARY_IF" wol g # --- Configure persistence in /etc/network/interfaces ------------------------ INTERFACES_FILE="/etc/network/interfaces" if [[ ! -f "$INTERFACES_FILE" ]]; then err "${INTERFACES_FILE} not found. Your system may be using another network config method (e.g., systemd-networkd, Netplan)." fi # Backup the file BACKUP_FILE="${INTERFACES_FILE}.bak-$(date +%F-%H%M%S)" cp "$INTERFACES_FILE" "$BACKUP_FILE" info "Backed up ${INTERFACES_FILE} to ${BACKUP_FILE}" # If an ethernet-wol or ethtool post-up line already exists for this interface, don't duplicate if grep -Eq "ethernet-wol g" "$INTERFACES_FILE" || \ grep -Eq "ethtool -s ${PRIMARY_IF} wol g" "$INTERFACES_FILE"; then info "WOL persistence settings already present in ${INTERFACES_FILE}; not adding again." else info "Adding 'ethernet-wol g' under iface ${PRIMARY_IF} in ${INTERFACES_FILE}..." # Check if iface stanza exists if grep -Eq "^iface[[:space:]]+${PRIMARY_IF}[[:space:]]" "$INTERFACES_FILE"; then # Insert 'ethernet-wol g' directly after the iface line for this interface awk -v iface="$PRIMARY_IF" ' { print $0 if ($1 == "iface" && $2 == iface && !seen) { print " ethernet-wol g" seen = 1 } } ' "$INTERFACES_FILE" > "${INTERFACES_FILE}.tmp" mv "${INTERFACES_FILE}.tmp" "$INTERFACES_FILE" info "Updated ${INTERFACES_FILE} to include ethernet-wol g for ${PRIMARY_IF}." else info "No iface stanza for ${PRIMARY_IF} found in ${INTERFACES_FILE}." info "Not modifying the file to avoid breaking your network configuration." info "You may need to manually add 'ethernet-wol g' to the appropriate iface section." fi fi # --- Verify WOL is enabled --------------------------------------------------- info "Verifying WOL is enabled on ${PRIMARY_IF}..." VERIFY_OUTPUT=$(ethtool "$PRIMARY_IF") WAKE_ON=$(awk -F: '/Wake-on/ {gsub(/ /,"",$2); print $2}' <<<"$VERIFY_OUTPUT") if [[ "$WAKE_ON" != "g" ]]; then err "WOL verification failed: Wake-on is '${WAKE_ON}', expected 'g'. Check BIOS settings and /etc/network/interfaces." fi info "WOL verification succeeded: Wake-on is '${WAKE_ON}'." # --- Final summary ----------------------------------------------------------- HOSTNAME=$(hostname) echo echo "===========================================" echo " Wake-on-LAN Configuration Summary" echo "===========================================" echo " Hostname : ${HOSTNAME}" echo " Interface : ${PRIMARY_IF}" echo " MAC : ${MAC_ADDR}" [[ -n "${IP_ADDR:-}" ]] && echo " IP : ${IP_ADDR}" echo " Wake-on : ${WAKE_ON}" echo "===========================================" echo "NOTE: Make sure WOL is enabled in your system BIOS/UEFI." echo exit 0