NAS with Autosuspend, WakeOnLAN and SSHFS Automount
May 30, 2020
This post describes the setup of some convenient features that I deployed for the NAS, to automatically save power, make it wake up and mount it on the client only when needed.
Autosuspend
Autosuspend is a nice tool to let a server suspend if it is idle (with configurable conditions). For Fedora there is no official package available, so I installed it from source:
git clone https://github.com/languitar/autosuspend.git; cd autosuspend python3 setup.py install --prefix=/usr mv /usr/local/lib/python3.7/site-packages/autosuspend-3.0.0.dev0-py3.7.egg/etc/* /etc mv /usr/local/lib/python3.7/site-packages/autosuspend-3.0.0.dev0-py3.7.egg/lib/systemd/system/* /usr/local/lib/systemd/system/Starting with usual git clone and python module install, unfortunately the setup does not install the config and service files, so I had to move them manually afterwards.
Based on the default config this is resulting the
/etc/autosuspend.conf:[general] interval = 30 idle_time = 900 suspend_cmd = /usr/bin/systemctl suspend wakeup_cmd = sh -c 'echo 0 > /sys/class/rtc/rtc0/wakealarm && echo {timestamp:.0f} > /sys/class/rtc/rtc0/wakealarm' woke_up_file = /var/run/autosuspend-just-woke-up lock_file = /var/lock/autosuspend.lock lock_timeout = 30 # This will use the Users check with the custom name RemoteUsers. # Custom names are necessary in case a check class is used multiple times. # Custom names can also be used for clarification. [check.RemoteUsers] class = Users enabled = true name = .* terminal = .* host = [0-9].* # Custom [check.SSH] class = ActiveConnection ports = 22 enabled = true [check.NetworkBandwidth] enabled = true interfaces = eno1 threshold_send = 200 threshold_receive = 400Three checks are enabled here, RemoteUser checks is someone is currently logged in over ssh, the ActiveConnection check on port 22 will reliably detect SSHFS connections. Also if there are other services causing some bandwidth usage it will detect it and not suspend with the last check.
After starting/enabling with
systemctl enable --now autosuspend.serviceit should look like this insystemctl status autosuspend.service:● autosuspend.service - A daemon to suspend your server in case of inactivity Loaded: loaded (/etc/systemd/system/autosuspend.service; disabled; vendor preset: disabled) Active: active (running) since Fri 2020-05-15 12:23:19 CEST; 8h ago Docs: https://autosuspend.readthedocs.io/en/latest/systemd_integration.html Main PID: 1348 (autosuspend) Tasks: 1 (limit: 4536) Memory: 15.4M CGroup: /system.slice/autosuspend.service └─1348 /usr/bin/python3 /usr/bin/autosuspend -l /etc/autosuspend-logging.conf daemon May 15 20:50:50 nas-server autosuspend[1348]: 2020-05-15 20:50:50,740 - autosuspend.Processor - INFO - Starting new check iteration May 15 20:50:50 nas-server autosuspend[1348]: 2020-05-15 20:50:50,752 - autosuspend.Processor - INFO - Check SSH matched. Reason: Ports [22] are connected May 15 20:50:50 nas-server autosuspend[1348]: 2020-05-15 20:50:50,753 - autosuspend.Processor - INFO - System is active. Resetting stateHere we see that it currently detects the SSH connection and does not suspend when I am logged in.
Wake On LAN
First make sure WOL is set up on the server and works from the client with
wol xx:xx:xx:xx:xx:xxusing the MAC address of the server. This usually has to be enabled in the BIOS and might also need some software, read more here.Now we want the client to wake up the server automatically. I searched for some guidance and found this blog post, he used a custom socket that triggers WOL on connection. It works, but I observed reduced performance with this approach: instead of >900 Mbit/s it delivered only about 300 Mbit/s, because all data must go through netcat and the local socket.
So I came up with a solution where the data does not get intercepted and therefore does not impact the performance. For that an extra systemd service is running to check if the server is already up and if not sends the WOL packet. For example on ArchLinux custom services should be placed into
/etc/systemd/system, I created there anas-online.service:[Unit] Description=Continuously check if the host is up, otherwise try WOL on start After=network.target network-online.target PartOf=mnt.mount [Service] Environment=HOST=nas-server Environment=PORT=22 Environment=MAC=xx:xx:xx:xx:xx:xx ExecStartPre=/bin/sh -c 'for n in `seq 1 6`; do nc -z ${HOST} ${PORT} && break || wol $MAC && sleep 10; done' ExecStart=/bin/sh -c 'while :; do (nc -z -w 1s ${HOST} ${PORT} && echo "Host is up!" && sleep 30) || break; done'In the [Unit] section it is defined as PartOf
mnt.mount(which we will create in the next section), this makes systemd propagate start/stop commands from the mount to this unit. The [Service] contains 2 small shell scripts. Pre start runs a maximum of 6 times a loop where it checks withnc -z(netcat zero IO) if the target is up, otherwise it sends the WOL packet and waits 10 secs. Then the main script just check every 30 secs if the target is still online and logs it. Per default this runs indefinitely, but as described above it does get stopped ifmnt.mountgets inactive.Test it with
systemctl start nas-online.service,systemctl stop nas-online.serviceandsystemctl status nas-online.service:* nas-online.service - Continuously check if host is up, otherwise try WOL on start Loaded: loaded (/etc/systemd/system/nas-online.service; static; vendor preset: disabled) Active: inactive (dead) since Sat 2020-05-30 16:06:16 CEST; 4min 3s ago Process: 3589 ExecStartPre=/bin/sh -c for n in `seq 1 6`; do nc -z ${HOST} ${PORT} && break || wol $MAC && sleep 10; done (code=exited, status=0/SUCCESS) Process: 3768 ExecStart=/bin/sh -c while :; do (nc -z -w 1s ${HOST} ${PORT} && echo "Host is up!" && sleep 30) || break; done (code=killed, signal=TERM) Main PID: 3768 (code=killed, signal=TERM) May 30 16:05:01 pc-arch systemd[1]: Starting Continuously check if host is up, otherwise try WOL on start... May 30 16:05:04 pc-arch sh[3617]: Waking up xx:xx:xx:xx:xx:xx... May 30 16:05:14 pc-arch systemd[1]: Started Continuously check if host is up, otherwise try WOL on start. May 30 16:05:14 pc-arch sh[3774]: Host is up! May 30 16:05:44 pc-arch sh[4140]: Host is up! May 30 16:06:15 pc-arch sh[4198]: Host is up! May 30 16:06:16 pc-arch systemd[1]: Stopping Continuously check if host is up, otherwise try WOL on start... May 30 16:06:16 pc-arch systemd[1]: nas-online.service: Succeeded. May 30 16:06:16 pc-arch systemd[1]: Stopped Continuously check if host is up, otherwise try WOL on start.Automount
The Systemd automount feature can automatically mount it when an access to the mountpoint is detected and unmount if it was idle for a specified time.
First it is important to login as root with SSH and accept the fingerprint for the server, otherwise it will not work because it is not in the known hosts list (like describe here):
sudo -i ssh -p 2222 jk@nas-serverAlso it is of course not possible to enter a password, so make sure pubkey authentication is properly configured on the server.
Then an mount entry in
/etc/fstabcan be added:jk@nas-server:/mnt /mnt fuse.sshfs noauto,x-systemd.requires=nas-online.service,identityfile=/home/jk/.ssh/nas_ed25519,user,allow_other,default_permissions 0 0Here we need a few options:
- noauto: Disable direct mount on boot
- x-systemd.requires=: Require online check/WOL to start
- identityfile=: Specify the SSH keys, it will run as root and does not read the user ssh config
- user: Allow user to mount/unmount
- allow_other: Allow other users (than root) to access
- default_permissions: Use permissions from the server
The
systemd-fstab-generatorwill automatically produce an unit for the mountpoint, in this casemnt.mount.Now we need another unit:
mnt.automountwith the simple content:[Automount] Where=/mnt TimeoutIdleSec=60
Wherejust specifies the mountpoint, also the filename must match the mount unit filename, which is based on the path.TimeoutIdleSecenables the automatic unmount, if it was idle for at least 60 secs in this case, you might want to set this higher.Note: With the x-systemd.automount fstab option the generator could also create the automount.service, but then the requires is applied to the automount and that would wake up the NAS always at the boot. We want to have it on the mount, because that wakes up the NAS only if it is actually mounted/used.
Finally start and enable it with
systemctl enable --now mnt.automount. On any access to/mntthe automount will trigger the mount.You can see if it triggered with
systemctl status mnt.automount:● mnt.automount Loaded: loaded (/etc/fstab; generated) Active: active (running) since Fri 2020-05-15 19:49:22 CEST; 28min ago Triggers: ● mnt.mount Where: /mnt Docs: man:fstab(5) man:systemd-fstab-generator(8) Mai 15 19:49:22 pc-arch systemd[1]: Set up automount mnt.automount. Mai 15 19:49:27 pc-arch systemd[1]: mnt.automount: Got automount request for /mnt, triggered by 55768 (dolphin) Mai 15 20:02:14 pc-arch systemd[1]: mnt.automount: Got automount request for /mnt, triggered by 59368 (nvim)and
systemctl status mnt.mount:● mnt.mount - /mnt Loaded: loaded (/etc/fstab; generated) Active: active (mounted) since Fri 2020-05-15 20:30:41 CEST; 9min ago TriggeredBy: ● mnt.automount Where: /mnt What: jk@localhost:/mnt Docs: man:fstab(5) man:systemd-fstab-generator(8) Tasks: 7 (limit: 19042) Memory: 2.3M CGroup: /system.slice/mnt.mount ├─61440 ssh -x -a -oClearAllForwardings=yes -oport=2222 -oidentityfile=/home/jk/.ssh/nas_ed25519 -2 jk@localhost -s sftp └─61448 /usr/bin/mount.fuse.sshfs jk@localhost:/mnt /mnt -o rw,noexec,nosuid,nodev,port=2222,identityfile=/home/jk/.ssh/nas_ed25519,allow_other,default_permissions,user Mai 15 20:30:40 pc-arch systemd[1]: Mounting /mnt... Mai 15 20:30:41 pc-arch systemd[1]: Mounted /mnt.I hope it was helpful, let me know if it worked in the comments!
A civil engineer with a longlife fondness for Software Libero