Automatically Wake NAS on Access

9k views Asked by At

I'm trying to get my NAS server to wake from an S3 sleep state when the NAS is accessed by a user. I want to do this to increase the longevity of the server, and also to limit its power usage. I've seen people asking for similar advice but none that I found provide a robust solution, most threads just ended unanswered.

So to just detail my problem quickly: At my home I have a custom built, from an old PC, NAS server, running Ubuntu server, which stores media and documents mainly. This server is currently set to sleep after a predefined inactive period. Currently the NAS can be brought out of the S3 state with a WOL magic packet. What I would like to achieve is that this magic packet is automatically sent to the server when a user accesses one of the shares from their PC. The users are primarily running windows 7. I'm not sure if this is entirely prevalent but I have a Linksys WRT54G running DD-WRT as my home router/DHCP/DNS.

During my research I came across many articles which just automatically woke the server on a timed loop, no real intelligence. The article given below seems to do what I want:

http://wdtvhd.com/index.php?showtopic=7908

A script is given which attempts to address this problem by using the DD-WRT router to send the wake-on-lan packets when a query is made. This seems like a good way to go about this, however I could not get the script given in the link to operate correctly.

I think that covers most aspects of my problem. Any assistance will be greatly appreciated.

3

There are 3 answers

3
Rabid On BEST ANSWER

Just thought I would post my eventual solution to the above mentioned problem. To solve the problem I wrote a custom script which runs on my dd-wrt router on a timed cron job. When this script runs it access the file

\proc\net\arp

Within in that file is stored a record of all currently leased IP address and the corresponding mac addresses. Thus my script compared the mac addresses stored within that file to a predefined list of mac address of PCs on my home network. The list is comprised only of the PCs I would like to be able to access the NAS server. If one of the PCs is found to have an active lease the router then sends the wake-on-lan magic packet. Which then wakes the server. At that point I thought I had achieved my goal, as the server switched on with any of the PCs on the network, and the wait was not too long. However, after completing this I found that my timed sleep for the server would initiate every 30 min or so and sleep the server only to be woken again a couples of seconds later.

So to solve that issue I just added another condition to my conditional statement that would sleep the server if none of the required PC had an active lease. To do this I used SSH and the built in dropbear ssh functionality of DD-WRT to sleep the server. Below is the script

#!/bin/ash

NAS="MA:CA:DD:RE:SS:00"

PC="MA:CA:DD:RE:SS:00"

varP='grep -o $PC /proc/net/arp'

while true
do
    echo 'Entered Loop'
    if ping -c 1 IPADDRESSOFNAS > /dev/null; then
            echo 'NAS is Already ON'

    if [[ "$varP" != "MA:CA:DD:RE:SS:00" ]]; then
                    echo 'All Hosts Offline'
                    echo IPADDRESSOFNAS  ssh-rsa NASPUPLICKEY
                    #HOME=/temp/root/
                    DROPBEAR_PASSWORD='NASPASSWORD' ssh root@IPADDRESSOFNAS pm-suspend &
            fi
            exit
    fi

    if [[ "$varP" == "MA:CA:DD:RE:SS:00" ]]; then
            echo 'waking from lan'
            /usr/sbin/wol -i BROADCASTADDRESSOFNETORK -p 9 MA:CA:DD:RE:SS:00
            /usr/sbin/wol -i BROADCASTADDRESSOFNETORK  -p 9 MA:CA:DD:RE:SS:00
            exit
    fi
    exit
done

DISCLAMER: The code is supplied as is. I am aware it is not pretty nor the best solution possible. But it works for me and thats all I really need.

Hope someone finds this useful!

6
rekire On

I insprected my NAS from WD and I can tell you that they uses memory drives for the /tmp, /var directories.

So are every logs written to the memory and the harddrive has not to be online. Hope that helps you a bit.

If someone want to access the harddrive the system will automatically upspinn your harddrive. So you will get what you want except that the system is always online.

0
Lau On

I made some changes to the script by @Rabid to add support for multiple PCs.

It also checks whether the entries found in ARP have their flag set to 0x2 ( =~ active ), as, for me, the ARP entries would remain listed for too long after the PC had gone offline.

#!/bin/bash
# This script is made to be run on an DD- / Open-WRT device to automatically wake a NAS 
# server if client PCs are online

# Settings

# Addresses of NAS that gets woken / put to sleep
MACofNAS="MA:CA:DD:RE:SS:00"
IPofNAS="192.168.2.1"
BroadcastAddress="192.168.2.255"
WOLPort=9

# Location of SSH Private Key on WRT (if used for login)
SSHPrivateKeyFile=~/.ssh/id_rsa

# MAC addresses of PCs of which the online status will be checked
PCs=(
    "MA:CA:DD:RE:SS:00" # PC1
    "MA:CA:DD:RE:SS:00" # PC2
    "MA:CA:DD:RE:SS:00" # PC3
    "MA:CA:DD:RE:SS:00" # PC4
)



# Determine if any PCs are on
SomePCisON=false
for index in ${!PCs[@]}; do
    # Try to detect PC's MAC address in ARP

    ## Look for all entries in ARP ...
    # PCFound=$(grep -o "${PCs[index]}" /proc/net/arp)

    # ... OR look only for entries with flag set to 0x2 ( ~ active )
    PCFound=$(grep "0x2" /proc/net/arp | grep -o "${PCs[index]}") 

    # If MAC address is found, the PC must be ON
    if [[ ${PCFound} ]]; then
        echo "PC ${PCs[index]} is ON"
        SomePCisON=true
    else
        echo "PC ${PCs[index]} is OFF"
    fi
done

if [[ "$SomePCisON" == true ]]; then
    echo "Some PCs are turned ON"
else
    echo "All PCs are turned OFF"
fi

# Check if NAS is ON
if ping -c 1 $IPofNAS > /dev/null; then
    echo 'NAS is ON'
    NASisON=true
else
    echo 'NAS is OFF'
    NASisON=false
fi

# If NAS is ON, but all PCs are OFF, put NAS to Sleep
if [[ "$NASisON" == true ]]; then

    # If no PCs are ON, put NAS to sleep
    if [[ "$SomePCisON" == false ]]; then
            echo 'All Hosts Offline'
            echo 'Suspending NAS'

            # Log in with password (as in @Rabid's script, didn't work for me) ...
            DROPBEAR_PASSWORD='NASPASSWORD' ssh root@IPADDRESSOFNAS pm-suspend &

            ## ... OR log in with authentication key
            # ssh -i $SSHPrivateKeyFile root@$IPADDRESSOFNAS pm-suspend &
    fi

# If NAS is OFF and any PCs are ON, wake NAS
elif [[ "$SomePCisON" == true ]]; then

    # Use wol package on DD-WRT ...
    echo 'Waking NAS from LAN, Broadcasting to '$BroadcastAddress\
        'on port '$WOLPort' for '$MACofNAS
    /usr/sbin/wol -i $BroadcastAddress -p $WOLPort $MACofNAS
    /usr/sbin/wol -i $BroadcastAddress -p $WOLPort $MACofNAS;

    ## ... OR use etherwake package on Open-WRT 
    ## ( Install with: opkg update && opkg install etherwake )
    # echo 'Waking NAS from LAN, '$MACofNAS
    # /usr/bin/etherwake $MACofNAS
    # /usr/bin/etherwake $MACofNAS
fi

To log in with an authentication key, make a key pair and place the public key in NAS:~/.ssh/authorized_keys:

On WRT (with Dropbear):

mkdir -p ~/.ssh

# Generate a private key and store it in ~/.ssh/id_rsa
dropbearkey -t rsa -f ~/.ssh/id_rsa

# Store the public key in ~/.ssh/id_rsa.pub
dropbearkey -t rsa -f ~/.ssh/id_rsa -y | grep ssh > ~/.ssh/id_rsa.pub

# Copy id_rsa.pub from WRT:~/.ssh/ to NAS:~/.ssh/
scp ~/.ssh/id_rsa.pub root@nas:~/.ssh/OpenWRT.pub 

On NAS (with OpenSSH):

# Back up the authorized_keys
cp ~/.ssh/authorized_keys ~/.ssh/authorized_keys_Backup

# Add the new public key to authorized_keys
cat ~/.ssh/OpenWRT.pub >> ~/.ssh/authorized_keys