NoMachine Wake-on-LANWAN Over the Internet

Copyright © 2024 by Jim Avera. Openly licensed by CC BY 4.0

(updated 09/28/2024. LibreOffice source is here)


NoMachine currently (as of 8.11.3) only supports waking up a sleeping server on the local network.

It is possible to wake up a machine over the Internet using a separate utility and “advanced” routing and DDNS. Here’s how. If you already know the basics, skip to “Step by Step Instructions”.

WoL Basics

A server is awakened when it’s network interface receives a “magic packet” containing that interface’s own MAC Address encoded in a certain way. The supposedly-powered-off machine must keep some logic powered so it can listen for the magic packet; this must be enabled in the OS and BIOS.

WoL may only work from certain sleep states and not from a “power off” state (or vice-versa). It depends on the host’s hardware and firmware.

The “magic packet” data pattern is 6 bytes of 0xFF followed by 16 repetitions of the 6-byte MAC Address. This can appear anywhere within the packet and it does not matter what kind of packet it is or what protocol was used to send it.

A link-level broadcast is usually used for local WoL because it reaches every device on the local net without special routing. This will not work over the Internet, which only handles IP packets. To route WoL over the Internet, you must manage routing to get the packet delivered to the powered-off server’s NIC.

IP Basics

IP (Internet Protocol) operates over Ethernet and other link-level protocols. IP is a foundation on which TCP and UDP operate. TCP provides a “reliable stream” but can not work if one end is sleeping or powered off. UDP is an “unreliable datagram” service which requires no cooperation from the receiving end – and therefore is perfect for our needs.

An IP Address identifies a specific network interface. Routers have multiple interfaces and multiple IP addresses. “Public” IP Addresses are globally unique and can be used on the Internet; they are assigned by domain administrators. “Private network” addresses such as 192.168.x.y may be used by anyone inside a private network, but are not unique and may never be used on the Internet.

Network Address Translation (NAT) is used by routers when local hosts use private-network IP addresses. The router acts as a transparent proxy when local hosts communicate with Internet hosts by exchanging its own public IP address with the local hosts’ private addresses in all packets in a conversation. Thus local hosts do nothing special – they talk to public IP addresses on the Internet the same way they talk to private-network addresses used by local hosts. However, the reverse is not true – an Internet host can not explicitly contact a local host; it can only contact the router using the router’s public IP address.

A Port Number identifies a software end-point within an IP Address, allowing many concurrent conversations to use the same IP Address. A UDP packet specifies both sender and receiver with [IP Address, Port Number] pairs. “Well known” port numbers are used by servers that listen for unsolicited requests; for example port 80 is for http (web server) and port 9 is for a “discard service” (accepts anything and discards it, ala /dev/null).

Port Forwarding” is where a router relays packets received from the Internet at a specific Port Number to an internal IP Address. This allows an external host to initiate contact with a local host when NAT is being used. However a unique Port Number (at the router’s public IP Address) must be used for each point of contact. The port number the router receives the packet on can be different than the port number the packet is forwarded to.

Sending WoL Packets through the Internet

Some kind of IP packet must be used so it can travel through IP routers and eventually to the physical LAN segment connected to the sleeping server.

We will use a UDP packet containing the WoL magic bytes, sent to an otherwise-unused port at your router’s public IP Address, which the router forwards to Port 9 at the sleeping server’s local IP Address (port 9, used by a “discard service” is used so that if the server is already awake it won’t do anything harmful). For simplicity, people often also use port 9 on the public IP Address, but this is not necessary.

In fact, multiple public port numbers can be used if you have multiple wakeup-able hosts (all the forwarded ports would be forwarded to port 9 on the corresponding local IP Addresses).

Some routers allow port-forwarding to an IP broadcast address on the LAN instead of to a single IP address. This might simplify the setup (i.e. for multiple hosts or to avoid ARP Binding – see blow) but could increase the attack surface by making every device on the LAN respond to a packet sent from the Internet. Therefore I don’t recommend doing this unless you have a large number of wakeup-able hosts or ARP Binding is not supported by your router.

A utility is needed on the client machine, such as your laptop, that can send the UDP packet to your DDNS (or static) public IP hostname. A simple Perl script which does this can be downloaded from https://abhweb.org/downloads/wol_wakeup_script.pl

The main requirements:

  1. Your router or an always-on local host must support DDNS unless your ISP provided a static public IP Address.

  2. The powered-off server must have an effectively-static local IP address.

  3. Your router must forward UDP packets from the Internet to the server’s IP address.

  4. Your router must route that IP to the powered-off server’s NIC without depending on the server to respond to ARP or similar requests.

Step By Step Instructions

  1. Prefer a wired network for the server, not Wi-Fi. Some WiFi interfaces can listen for a WoL packet when their host is powered off, but not all of them can. If you must use WiFi, confirm what WoL works (on the local network) before proceeding.

  2. Assign a fixed local IP address to the server: It is usually easiest to use the DHCP Address Reservation feature in your router to reserve a particular IP address for the MAC Address of the server which will be awakened by WoL. No change is made to the server – it will still use DHCP to request an IP address but will always get the same answer.

    To assign a true static IP: Configure your router to allocate only a subset of its private network range to DHCP clients (for example 192.168.1.2 through .199), and pick an address outside of that subset but still within the private network range as the server’s static IP (such as 192.168.1.200). Then configure the server to use the assigned IP address and not use DHCP.

  3. Use “MAC Binding” in your router to statically associate your server’s IP with it’s MAC Address. This obviates the need for the server to respond to ARP, which it can not do while sleeping. Be careful that DHCP Address Reservation and MAC Binding use the same IP:MAC pairing!

    Reboot both your router and server machine to verify that everything still works.

  4. Enable Wake-on-Lan in your server’s network interface. The method depends on the OS.

    1. For Ubuntu 24.04 or other Linux flavors which use the “NetworkManager”:

      GUI Method (Ethernet only, not WiFi): Run “Advanced Network Configuration” from the system start menu or GNOME overview, or run the command nm-connection-manager in a terminal.

      Under the “Ethernet” tab, select your interface, check the Wake on LAN “Magic” checkbox, and click “Save”.

      Command line Method (Ethernet):
      nmcli connection show
      Look for your network name (this example assumes “netplan-enp0s31f6”).

      nmcli connection show "netplan-enp0s31f6" | grep 802
      Look for “802...wake-on-lan:”. If it is set to “magic” it is already enabled. Otherwise…
      nmcli connection modify "netplan-enp0s31f6" 802-3-ethernet.wake-on-lan magic
      to enable it. Reboot.

      If you must use a WiFi with WOL see https://ubuntuhandbook.org/index.php/2024/08/enable-wake-on-lan-ubuntu/

    2. For Ubuntu 23.04 and earlier (or other Linux without “NetworkManager”):

      Run ip a and find the nic name (e.g. “enp0s31f6” might be an Ethernet port).

      Then sudo ethtool <nic name> | grep Wake : If “Supports Wake-on” contains the letter ‘g’ then WoL is supported (if it isn’t then you may have to enable something in the BIOS).
      If “Wake-on” contains ‘g’ then WoL is currently enabled; ‘d’ means disabled.

      To permanently enable WoL (valid in Ubuntu 23.04):

      sudo --preserve-env systemctl edit --force --full wol-enable.service
      which starts an editor. Edit the file if necessary to contain the following, then write it back:
      # optional comment
      [Unit]
      Description=Enable Wake-up on LAN

      [Service]
      Type=oneshot
      ExecStart=/sbin/ethtool -s <nic name> wol g

      [Install]
      WantedBy=basic.target


      Finally, run sudo systemctl daemon-reload and
      sudo systemctl enable wol-enable.service .

  5. Shut down your server and remove power to erase any state in the NIC. Then power up and reboot, and rerun ethtool <nic name> | grep Wake to verify that WoL was re-enabled on the interface (“Wake-on” should contain ‘g’ and not ‘d’).

  6. Verify that WoL works locally. Put your server to sleep and try to wake it up from another host on the LAN using NoMachine’s built-in local WoL support.

  7. Set up public-key-based NoMachine authentication and disable passwords. You will need to put the public key into $HOME/.nx/config/authorized.crt on the Linux server and the private key in a file in your client machine, and configure the NoMachine client connection to use it.
    Instructions are at https://kb.nomachine.com/AR02L00785
    Note: It is prudent to never expose password-protected services to the Internet.

  8. Forward NoMachine’s NX service from the Internet to your server using “Port Forwarding” in your router.

    The NX service uses port 4000 by default, which should not be changed. To help with testing, I suggest forwarding a different port number from the Internet, e.g. 4001, to port 4000 on your local server.

    To test: In another host, which could be on the same LAN, run NoMachine as a client and create a connection profile which uses your machine’s public IP address and port 4001. For the moment, find out your public IP from your router or by visiting https://whatismyipaddress.com/
    If NoMachine works, you can be sure the connection actually used the port-forwarding and didn’t somehow go directly to the server.

  9. Install a WoL utility on your client machine. A simple Perl script is at https://abhweb.org/downloads/wol_wakeup_script.pl
    Use Notepad or another editor to change the configuration settings at the top of the file:
    Set $target_mac to your server’s MAC address
    Set $fqdn_or_ip to your public IP address for now (“aaa.bbb.ccc.ddd”) unless
    you already have a DDNS public domain name.

    If your client is a Windows machine, install Strawberry Perl from https://strawberryperl.com/ (“System installer version”). Then double-click the file containing the wakeup script. If prompted for which application to use for .pl files, click “other” and navigate to the perl executable which by default is at C:\Strawberry\perl\bin\perl.exe . If instead the file opens with Notepad etc. you can right-click the file, then Properties, and change “Opens With”.

    After this initial setup, double-clicking the script file will run it, sending the WoL packet.

    To test, run sudo tcpdump -v -UlnXi <nic name> udp port 9 in a terminal on your server. Each time a UDP packet is sent to port 9 it will display the contents. Then run the wakup script on your client – you should see a hexadecimal dump of the UDP packet from tcpdump on the server.

    If that works, put your server to sleep and check that it wakes up when you send the WoL packet.

  10. Get a DDNS domain name (unless your public IP is static)

    You arrive at that cafe in Paris. Meanwhile, your ISP back home has changed the public IP address of your router. You need to find out what your new public IP is so you can call home.

    The solution is a Dynamic DNS (DDNS) domain name which automatically tracks the IP assigned by your ISP. This works by having your router (or an always-on local host) log into the DDNS service provider whenever your public IP address changes or at regular intervals. The DDNS service will detect your public IP address and update the DNS maps accordingly.

    I recommend https://www.noip.com/ . You can get a
    free domain name such as yourname.hopto.org . A completely-custom domain name is also possible.

  11. Test connecting via the Internet:
    On your client machine, create or edit a NoMachine client connection profile:

    In the “Address” section: Set “Host” to your public (DDNS) IP hostname and port to 4001
    (assuming you followed the suggestion in step 8));

    In the “Configuration” section check “Use key-based authentication with key you provide”
    and navigate to the path of the file containing the private key created in step 7).

    Click “Connect” to verify that you can connect to the server over the Internet when it is already powered on.

  12. Test remote WoL
    Shut down or sleep your server, and power off your router for a minute to ensure that it forgets any transient routing tables. Then turn the router on and wait a minute or so for it to boot up.

    Connect your client machine to the Internet via some other means, such as your neighbor’s WiFi or a cellphone hotspot.

    Edit the wakup Perl script (rightclick→Edit or open with Notepad). Change $fqdn_or_ip to your public (DDNS) IP hostname; save the file.

    Drum-roll! Double-click the wakeup script. Your server should come to life.

    Connect to the server using the NoMachine connection profile created above.

    Celebrate.

SECURITY CONSIDERATIONS

Port-forwarding exposes your LAN to Denial-Of-Service attacks where someone constantly floods forwarded ports with packets, which then must traverse your LAN before being (hopefully) discarded.

A more serious concern is security vulnerabilities in the software services behind forwarded ports.

In the application described here, two ports are forwarded:

(END)