a3nm's blog

Wake-on-LAN: suspend and resume machines from the network

— updated

Do you leave computers running, just on the off chance that you will need to ssh into them or otherwise access them remotely? I used to do this and feel a bit bad about wasting energy to power mostly idle machines, but I recently discovered Wake-on-LAN, which allows you to power or resume your computer from the network. I vaguely knew this existed, but I had no idea that it was something stable and available on normal computers. In fact, as it turns out, it works mostly out-of-the-box on my machines.

The basic principle of Wake-on-LAN is to setup your computer's network interface to react to specific incoming packets by powering up or resuming the machine, allowing you to suspend or power down the machine, and turn it up or wake it up remotely.

When to use it

When can you use Wake-on-LAN? First, of course, you cannot do this on machines that have to stay on because an actual server is running on them. Of course, however, such services should probably be run on low-power machines to avoid wasting energy. Second, it only works with Ethernet, so if your machine doesn't have a wired connection you are out of luck.

Third, your network interface must support Wake-on-LAN, which you can enable as follows, using the ethtool command (packaged in Debian with the same name). I'm assuming that eth0 is your network interface:

sudo ethtool -s eth0 wol g

You can then check that it works by issuing:

sudo ethtool eth0 | grep 'Wake-on: g'

If Wake-on: g is indeed returned, then Wake-on-LAN is enabled on your machine.

Earlier versions of this guide incorrectly explained how to enable Wake-on-LAN after explaining how to test for it.

How to enable it persistently

You probably want to enable Wake-on-LAN on the target machine (the one to wake up remotely) automatically at boot. What worked for me on Debian is to use udev following these instructions. In fact, this is an excellent guide and I am paraphrasing a lot from it.

For future purposes you should also retrieve the MAC address of the interface of the target machine, I will call this MACADDR:

ip addr show dev eth0 | grep 'link/ether' | awk '{print $2}'

And retrieve its public IP address (I use IPv4), I will call this IPADDR:

curl -4 icanhazip.com

How to send the packets

Now that Wake-on-LAN is enabled, you will need another machine to send the magic packet to wake up the target machine. To do this, I use the command wakeonlan from the Debian package of the same name.

The easiest is to do it from a computer on the same LAN, where you can just do:

wakeonlan MACADDR

If you are not on the same LAN, then either you should ssh to a computer of the LAN where you can do this, or you should set up forwarding. For instance, with a Freebox, you can make it work like this:

  • enable the specific Wake-on-LAN proxy option;
  • set up a permanent DHCP lease for your machine based on MACADDR so it always has the same IP address in the LAN (if you haven't done so already),
  • configure a redirection from UDP and TCP port 9 from the WAN to the target machine (use different public ports if you have different target machines on the LAN);
  • reboot your Freebox and renew the DHCP leases from the target machines

You can then do, from any computer:

wakeonlan -i IPADDR MACADDR

Of course, in terms of security it is a bit worrying that this is possible, because there is no authentication. You can be reassured by the fact that an attacker would need to know your MACADDR to be able to wake up your machines in your stead, but as it is sent in the clear when doing a Wake-on-LAN, that's not so reassuring. Also, you have to hope that your network controller, with its fancy Wake-on-LAN features, does not have flaws that could allow an attacker to do more than just wake the computer up...

In fact, the setup with the forwarding didn't work reliably for me after all, so, if you can, it's better to ssh to something on the same LAN to wake the machine up instead.

To test the setup, an easier way than actually suspending the machine, especially if you can't resume it manually in case of failure, is to check with socat that the target machine can actually receive the magic packets. On the target machine, do:

sudo socat -u udp-recv:9,reuseaddr -

Now test sending the magic packet; if things work correctly, some garbage (corresponding to the raw packet) should appear. If nothing appears, the packet is not being received by the target machine and you should troubleshoot this.

If the target machine can receive the packet, you can make it suspend to RAM using pm-suspend (package pm-utils in Debian). Do the following on the target machine:

sudo pm-suspend

The target machine should go to sleep, spending a minimal amount of energy to keep the RAM powered. Now, sending the magic packet from another machine should cause the target machine to resume. Hopefully all network interfaces should become usable (and all hardware should remain in the same state as before), so you can then ssh into the target machine a few seconds later, use it in the normal way, and just put it back to sleep with pm-suspend once you're done with it.

comments welcome at a3nm<REMOVETHIS>@a3nm.net