println(
);

I have noticed that even though I've optimized my server to the point where its pulling around 60w it is still wasting energy by running all the damn time when its not being used. I estimate that there is only about 5 hours of actual usage a day on it, that means I'm losing big when it comes to my energy bill. The problem with that 5 hours of usage is that it comes at random times when either someone else or I decides to access one of the many services that it serves up. I could be watching a TV show i recorded from my couch or my roommate could be streaming an episode to their phone on the other side of the country. So how do I manage to get the server to stay asleep and wake up at a moments notice based on a request that could come from 1 room away or across the country?

WOL of course! It might not be used how it was intended but it works like a charm. Here is what you need:

  • A router or something on the network running linux. My DD-WRT Asus RT-N16 fits this bill perfectly. 
  • A WOL capable computer and a server that knows when to go to sleep. I'm using an Ubuntu 12.04 box.
  • A basic idea of what iptables is and does.  Here is a good overview: http://bodhizazen.net/Tutorials/iptables/

Alright with that out of the way here is how to go about doing this. 

Follow this guide to move the server to its own dedicated VLAN: Located here.

  • NOTE: You have to restart the router by doing exactly what it says or the second DCHP subnet will not come online and the server will still be served from the same subnet pool as before.
  • We do this step because normally all internal network traffic that is on the same subnet is handled by the routers internal switch and does not hit the actual router itself. So when we do this we force the traffic all the way up to the level where we can observe it passing through the router rather simply. From what I've read the performance hit is negligible and for sensitive machines like a server it allows for greater security because we can isolate it from the rest of the network and only allow to get to it what we want. 

Add the iptables rules to allow for communication between the VLANs by adding it to the firewall commands on the DD-WRT web GUI under Administration > Commands > Save Firewall. Of course i would advise trying these commands out by hand before committing them.

iptables -I FORWARD -i vlan+ -o vlan2 -j ACCEPT
  • What I am doing here is allowing communication out to the WAN from all the VLANs including the new one that was just made. In my case the WAN is on vlan2 and my new vlan is vlan3. 
  • At this step you can set up all the iptables rules regarding communication between the VLANs you want. 
  • Your server should now be at this point be operating normally and should be able to communicate as it needs to. 

Now that you have a working network connection for the server again you can proceed on to the WOL feature. Modify these iptables commands to your liking and add them to the Save Firewall noted above to set up log rules so that when the router sees and incoming valid request it gets logged so the WOL script can act on it. 

iptables -I FORWARD -o vlan3 -p tcp --syn --dport 22 -m limit --limit 1/min -j LOG --log-level 7 --log-prefix 'local '
iptables -I FORWARD -o vlan3 -p tcp --syn --dport 443 -m limit --limit 1/min -j LOG --log-level 7 --log-prefix 'local '
iptables -I FORWARD -o vlan3 -p tcp --syn --dport 139 -m limit --limit 1/min -j LOG --log-level 7 --log-prefix 'local '
iptables -I FORWARD -o vlan3 -p tcp --syn --dport 548 -m limit --limit 1/min -j LOG --log-level 7 --log-prefix 'local '
iptables -I FORWARD -o vlan3 -p tcp --syn --dport 3240 -m limit --limit 1/min -j LOG --log-level 7 --log-prefix 'local '
iptables -I FORWARD -o vlan3 -p tcp --syn --dport 45631 -m limit --limit 1/min -j LOG --log-level 7 --log-prefix 'local '

Let me break down these commands.

  • First we are attaching these commands to the FORWARD table because that handles internal network communication. Also since we only care about traffic going to our server we specify that the outbound path of the packet has to be to the server on VLAN3. 
  • -p tcp --syn signifies that I only should log the SYNC tcp type packets that get sent during initial connection. 
  • --dport 22  says what port the packet must be going to.
  • -m limit --limit 1/min -j LOG --log-level 7 --log-prefix 'local '  is the juicy bit. It means that it will only log 1 of these type of packets every minute. This helps keep the log clean immensely and helps to keep the WOL script from running erroneous WOL requests.  The 'local '  bit is used to provide a better way of parsing the log. 

After running these commands ​/var/log/messages​ now has entries like these when you make a connection with the server from inside the local network or outside. 

local IN=br0 OUT=vlan3 SRC=10.0.1.34 DST=10.0.10.145 LEN=64 TOS=0x00 PREC=0x00 TTL=63 ID=27548 DF PROTO=TCP SPT=54171 DPT=443 WINDOW=65535 RES=0x00 SYN URGP=0

For me /var/log/messages also had a butt load of other iptables log messages that i didn't need and subsequently caused issues with the WOL script. There are two solutions to this. Either append the commands above to log the requests into a different log file or disable all the existing extra logging. I choose the second route because I didn't want to handle setting up a new log file that rotates so my flash dive doesn't get filled up. 

  • Disable firewall logging from the GUI under ​Security > Firewall > Log 
  • Manually edit /opt/etc/init.d/S94fixtables and comment out any instance of -j LOG​ present. ( This one was tricky and i have no idea why the logging is forced on in this.  It appears this is only present when you install optware.  After commenting these out I didn't shouldn't see anymore random  [DROP BRUTEFORCE] , [DROP INVALID WAN] entries. Be warned though, if ipkg updates this file then the log entries come back again. )

Now for me after these two steps the log was clean enough to use for the script. I put the script under /opt/etc/wol but it really doesn't matter where it goes as long as its executable. Just plop this script somewhere and have it start automatically when the router boots. I've seen people have issues with the startup commands not running under Administration > Commands​ . So its possible to use their solution ( Forum link here ) or just create a service to start it. 

#!/bin/sh
#Enable JFFS2 and place script in /jffs/ then run on startup in web interface.
#You can check the log from http://192.168.1.1/user/wol.html

INTERVAL=5
NUMP=2
OLD=""
WOLPORT=9
TARGET=10.0.10.145
BROADCAST=10.0.10.255
MAC=6C:F0:49:02:0B:7D
WOL=/usr/sbin/wol
LOGFILE="/tmp/www/wol.html"

echo "<meta http-equiv=\"refresh\" content=\"10\">" > $LOGFILE
echo "["`date`"] AUTO WOL Script started. <br>" >> $LOGFILE

while sleep $INTERVAL;do
NEW=`dmesg | awk -F'[=| ]' '/local/ {print $19}' | tail -1`
SRC=`dmesg | awk -F'[=| ]' '/local/ {print $7}' | tail -1`
                                                                                                                             
if [ "$NEW" != "" -a "$NEW" != "$OLD" ]; then 

 if ping -qc $NUMP $TARGET >/dev/null; then                                                  
     echo "["`date`"] NOWAKE $TARGET was accessed by $SRC and is already alive. <br>">> $LOGFILE     
  else                                                                                         
      echo "["`date`"] WAKE $SRC causes wake on lan. <br>">> $LOGFILE                          
      `$WOL -i $BROADCAST -p $WOLPORT $MAC >> $LOGFILE`                                            
      echo "<br>" >> $LOGFILE                                                                   
      sleep 5                                                                                   
   fi                                                                                           
   OLD=$NEW                                                                                   
fi                                                                                                                                                                                
done 

This is a modification of the webserver wakeup script from the dd-wrt wiki and it is pretty much the same that they have there. I just changed the commands around for better logging and stripped out any extra code. It basically checks the dmesg log to see if a new entry has come in and if there has and the server is not pingable then it sends the WOL command. I have it checking the log every 5 seconds because most of the services I use have a long timeout period but it can be adjusted to happen more often. I also had a problem with pinging my server and it turned out to be a UFW rule that is enabled by default, here is how to allow ICMP pings. 

That's it, the router will now be sending WOL magic packets when ever a valid service tries to contact the server. I haven't gotten to the point where the server puts itself to sleep so I can't really describe that in detail just yet. My next step is to move the services that require the server to be constantly running over to the router and to use a pound​ to proxy the HTTP services so that only authenticated requests cause the server to wake up and start slinging content.