Recently Added

Notes & Bookmarks

  1. Quasars; power and metrics beyond all comprehension. Staggeringly beautiful information... and very well written.
  2. "I'm sorry. I can't come in today. Religious holiday. The feast of...Maximum Occupancy."pic.twitter.com/mkgxPWfNj2
  3. Verifying myself: I am sgnls on Keybase.io. UJa01G4v3YRJYB1LFjDRSf1Nh0bh1sOykCbq / https://keybase.io/sgnls/sigs/UJa01G4v3YRJYB1LFjDRSf1Nh0bh1sOykCbq
  4. Be sure to take care of your own infrastructure(s); purge dumps, tunnel and lock-down egress transit, encrypt and permission CORRECTLY!
  5. It really doesn't matter what else gets released; Sikth's 'The Future in Whose Eyes?' is THE album of 2017. #albumoftheyear @SikthOfficialpic.twitter.com/P5houdf1yx

HS-210 : QNAP <-> Debian

Updated : 16:31:55pm, 16th Jun 2016

A few months ago, I came across a vendor selling off the QNAP HS-210 for ~£120, which was an incredible bargain. I toyed with getting two, maybe even three, of the units knowing they'd serve my requirements adequately and, for the money, efficiently too. As it goes, I ended up getting just one, and not two days later the vendor stopping selling it entirely... much to my frustration. I guess they were selling off their stockpile; hindsight, eh?

The unit itself is, well, frankly quirky. Clearly, it's beautiful, sleek and aesthetically pleasing. With two 'hot-swap' bays, it's also very manageable and the unit is actually fairly robust considering it's, really, just a T-bone embedded board with no fans. As such, it operates silently, which was my main desire. Obviously with this being a low-end model with only two bays (thus offering only RAID0/1), I wasn't expecting incredible write speeds... which is great, considering this is the biggest problem it has (though, not surprisingly, it does get incredibly hot).

QNAP HS-210

I have not performed any specific benchmarks and nor do I even have ballpark results, less any concrete figures from my experience, but suffice to say that the read operation is more than sufficient on a gigabit backbone. Writing larger blocks, or effectively queuing blocks with a copy, however, is really crippling. As in... mind-blowingly bad. RAID-1 is never going to offer me any sort of impressive speeds on any unit, but I often find myself canceling many a copy operation and re-scheduling it for a time I'm nowhere near it as it basically nullifies any further read requests until the I/O transaction(s) have completed...

How much of the bottleneck is down to the disks I'm using remains to be seen, but there's nothing really jaw-dropping according to QNAP's figures. This, however, is not my main frustration.

Whilst I was entertaining the acquisition of a QNAP device, I had one ultimate aim; a silent NAS device. I wasn't concerned so much with how much storage I had and nor was I that concerned with the aesthetics of the unit. Sure, it would have been sensible for me to just build a FreeNAS device (and I still intend to), but I wanted something simple. When I came across the HS-210 for just over £100, it was easily the most cost effective option.

QNAP HS-210

Of course, for me, that then gave me a bigger concern; what to run on it? Obviously the QNAP firmware is great, and possibly the best offering on all consumer-grade NAS solutions. Whilst QNAP offer some more resilient commercial-grade units, they're running an OS that's much the same.

The interface is slick, simple to use and provides an effective and decent front-end to control what runs under the bonnet. Handy, but ultimately not essential for me... and in fact, it just became a frustration knowing that I was running daemons like Apache, MySQL and PHP when I simply wasn't using them (at least directly); remember, this is not a particularly powerful headless unit (in reality it's on bar with a low-end Thin Client).

QNAP HS-210

Too often would I walk into my room to hear the disks whirring away, doing all manners of untold mysterious tasks. I just couldn't let it go, so I looked into what 'maintanance tasks' the unit was performing;

# m h dom m dow cmd
10 15 * * * /usr/bin/power_clean -c 2>/dev/null
#0 4 * * * /sbin/hwclock -s
0 3 * * * /sbin/vs_refresh
0 3 * * * /sbin/clean_reset_pwd
0-59/15 * * * * /etc/init.d/nss2_dusg.sh
30 7 * * * /sbin/clean_upload_file
30 3 * * * /sbin/notice_log_tool -v -R
0 3 * * * /bin/rm -rf /mnt/HDA_ROOT/twonkymedia/twonkymedia.db/cache/*
35 7 * * * /sbin/qbox_util -c  > /dev/null 2>/dev/null
0 3 * * 0 /etc/init.d/idmap.sh dump
4 3 * * 3 /etc/init.d/backup_conf.sh
42 11 * * * /usr/bin/qcloud_cli -c

Insane. Whilst a lot of these are required for (or at least assist) an always-on media server, I simply have not been using those features. Sure, I used Twonky years ago and still have the scripts to run the daemons, but I just felt dirty... that I didn't have full control over the unit and that I wasn't making use of 75% of it; iSCSI is handy, but I am not just using it at home anymore, and whilst SMB is great for my missus, neither of us made use of the chunky features (DLNA, the 'apps', myQNAPCloud etc.). Time to start again; make use of the hardware, but also do things 'my way'.

Installing Debian

The first thing I did was to remove the two drives, just in case something on the headless install did something to those mount points. When the unit is booted up, SSH in and plug in a USB drive onto which you backup the QNAP image (or you could just put it on the RAID before you down the drives);

# path to external drive; check dmesg
cd /share/external/sdh1
for i in /dev/mtdblock{0..5}; do cat $i > $(basename "$i"); done
cd ../
umount /share/external/sdh1

To re-image the NAND flash with Debian, download the core images and run the installer script;

cd /tmp
busybox wget http://ftp.debian.org/debian/dists/stable/main/installer-armel/current/images/kirkwood/network-console/qnap/ts-219/initrd
busybox wget http://ftp.debian.org/debian/dists/stable/main/installer-armel/current/images/kirkwood/network-console/qnap/ts-219/kernel
busybox wget http://ftp.debian.org/debian/dists/stable/main/installer-armel/current/images/kirkwood/network-console/qnap/ts-219/flash-debian
busybox wget http://ftp.debian.org/debian/dists/stable/main/installer-armel/current/images/kirkwood/network-console/qnap/ts-219/model
sh flash-debian

All being well, you should see a message and reboot as instructed;

Connecting to ftp.debian.org[130.89.148.12]:80
initrd               100% |***********************************************************|  9216 KB    00:00 ETA
Connecting to ftp.debian.org[130.89.148.12]:80
kernel               100% |***********************************************************|  2024 KB    00:00 ETA
Connecting to ftp.debian.org[130.89.148.12]:80
flash-debian         100% |***********************************************************|  3757       00:00 ETA
Connecting to ftp.debian.org[130.89.148.12]:80
model                100% |***********************************************************|    14       00:00 ETA
[/tmp] # sh flash-debian 
Updating MAC address...
Update /dev/mtdblock4 by using /tmp/debian.3987 done
Your MAC address is 01:03:06:AB:CD:EF
Writing debian-installer to flash... done.
Please reboot your QNAP device.

QNAP HS-210 (Debian Install)

Whilst the installer will aim to reuse a static configuration for the IP address, presume it will likely pull one from DHCP. Once identified, log in via SSH as installer with the password install (thereafter make use of the Debian documentation). If the device cannot contact DHCP (though, in reality, it seems the IP is forced static), then it will fallback to 192.168.1.100.

If you end up having a 192.168.1.100 address assigned, you will (unfortunately) discover that /etc/resolv.conf is not populated with the correct DNS server if your subnet is not 192.168.1.x/24;

~ # cat /etc/resolv.conf 
search example.org
nameserver 192.168.1.1
nameserver 10.3.6.1

I have added my DNS server (but left the original in as a reference). Depending on your network, it may even be prudent to add the IP 192.168.1.1 as a secondary IP on the interface of your gateway / firewall because the Debian install process you're going through is entirely headless and I have experienced many occasions where attempts to view or adjust the network settings from within in the installer drops network I/O entirely.

The process for installing Debian will take a long time, and longer depending to where you install it. I decided that I didn't want any part of the image on the drives, so plugged in an SD card (I guess I had to make some use of the feature).

Which options and modules you select are entirely personal choice; the core Debian kernel will install as a base image and you can always add the components you need afterwards. It is a safe assumption that if you're reading and performing this process, you have some awareness and experience with the configuration of a raw Linux kernel installation.

QNAP HS-210 (Debian Install)

You will almost certainly want to select a 'targeted' initrd, although it's not a requirement;

QNAP HS-210 (Debian Install)

Assuming you're now at a point where Debian is installed, re-add the drives and use mdadm to examine the RAID and proceed to populate the mdadm.conf file with the details of the array;

# Install mdadm (if not selected as part of the initialisation)
root@debian:~# apt-get install mdadm

# Check Disks for Array Superblocks
root@debian:~# mdadm --detail --scan
ARRAY /dev/md9 metadata=0.90 UUID=7c472cbf:35b7d7bf:43855575:2a5c0018
ARRAY /dev/md/2 metadata=1.0 name=2 UUID=76050db1:6e3deb63:578a2073:78f1d183
ARRAY /dev/md0 metadata=0.90 UUID=032f3849:9cfa1d52:991c52e2:ee2fa3f3 *
ARRAY /dev/md13 metadata=0.90 UUID=728ffa7b:4ed36ff5:5c14caf4:d22c9a05

* This is the crucial one we need; the rest are superfluous QNAP array(s)

# (non-Debian) mdadm --detail --scan >> /etc/mdadm.conf
root@debian:~# mdadm --detail --scan >> /etc/mdadm/mdadm.conf

root@debian:~# cat /proc/mdstat 
Personalities : [raid1] 
md13 : active (auto-read-only) raid1 sdb4[0] sdc4[1]
      458880 blocks [2/2] [UU]
      bitmap: 0/57 pages [0KB], 4KB chunk

md0 : active (auto-read-only) raid1 sdb3[0] sdc3[1]
      1951945600 blocks [2/2] [UU]
      
md2 : active (auto-read-only) raid1 sdb2[0] sdc2[2]
      530128 blocks super 1.0 [2/2] [UU]
      
md9 : active (auto-read-only) raid1 sdb1[0] sdc1[1]
      530048 blocks [2/2] [UU]
      bitmap: 0/65 pages [0KB], 4KB chunk

unused devices: 

This is NOT a problem; it is by design. The array will become R/W upon the first block change (i.e. write) 

It could be that you'll need to rebuild the array entirely, and again the official Linux kernel documentation is useful;

# Re-Assemble Array
root@debian:~# mdadm -A /dev/md0 /dev/sdb3 /dev/sdc3

(or)

# Re-Create Array
root@debian:~# mdadm --create --assume-clean --level=1--raid-devices=2 /dev/md0 /dev/sdb3 /dev/sdc3

If you've made it this far, I presume you will be aware of the sacrifice(s) that come with a clean install of Debian, sans all the components that the QNAP provided previously. Obviously you can do the necessary to make use of sshfs, Samba and Twonky to bring back the basic functionality of a NAS (at least as I require it).

Now is a good time to note that installing the Kirkwood kernel, along with the TS-219 images, will give you a functioning unit. However, you need to adjust the file at /etc/qcontrol/ts219.lua, specifically that which is highlighted in red because the unit does not have a fan like the TS-2xx models (you can see my version on the master branch on GitHub where I'll update the below to further remove superfluous monitoring of the 'fan');

# /etc/qcontrol/ts219.lua
--[[
	Debian configuration file for qcontrol (LUA syntax)
	Supports QNAP TS-110, TS-119, TS-210, TS-219, TS-219P and HS-210 (as TS-219) 
--]]

register("ts219")

-- Requires CONFIG_KEYBOARD_GPIO enabled in the kernel and
-- the kernel module gpio_keys to be loaded.
register("evdev", "/dev/input/by-path/platform-gpio-keys-event",
	408, "restart_button",
	133, "media_button")

register("system-status")

-- Set to "false" to suppress the sounding of the buzzer
buzzer = true

function system_status( status )
	logprint("System status: "..status)
	if status == "start" then
		piccmd("statusled", "greenon")
		piccmd("powerled", "on")
		if buzzer then piccmd("buzzer", "short") end
	elseif status == "stop" then
		piccmd("statusled", "redon")
		piccmd("powerled", "1hz")
		if buzzer then piccmd("buzzer", "short") end
	else
		logprint("Unknown system status")
	end
end

function power_button( time )
	os.execute("poweroff")
end

function restart_button( time )
	os.execute("reboot")
end

function media_button( time )
	piccmd("usbled", "8hz")
end

fanfail = 0

function fan_error(  )
	fanfail = fanfail + 1
	if fanfail == 3 then
		piccmd("statusled", "greenon")
	else
		if fanfail == 10 then
			fanfail = 0
		end
	end
end

function fan_normal(  )
	piccmd("statusled", "greenon")
	fanfail = 0
end

last_temp_log = nil
last_temp_value = 0

function logtemp( temp )
	local now = os.time()

	local function should_log(  )
		local delta_temp = math.abs(temp - last_temp_value)
		local delta_time = os.difftime(now, last_temp_log)

		-- Haven't previously logged, log now for the first time
		if ( not last_temp_log ) then
			return true
		end
		-- Temperature has changed by more than 5
		if ( delta_temp >= 5 ) then
			return true
		end
		-- More than 5 minutes have elapsed...
		if ( delta_time >= 300 ) then
			if ( delta_temp > 1 ) then
				--- ...and the change is by more than +/-1
				return true
			else
				--- ...insignificant change, wait another 5 minutes
				last_temp_log = now
				return false
			end
		end
		-- Otherwise no need to log
		return false
	end

	if ( should_log() ) then
		logprint(string.format("ts219: temperature %d", temp))
		last_temp_log = now
		last_temp_value = temp
	end
end

last_fan_setting = nil

function setfan( temp, speed )
	if ( ( not last_fan_setting ) or
	     ( last_fan_setting ~= speed ) ) then
		logprint(string.format("ts219: temperature %d setting fan to \"%s\"", temp, speed))
	end
	piccmd("fanspeed", speed)
	last_fan_setting = speed
end

-- hysteresis implementation:
--    - - > 35 > - - - > 40 > - - - > 50 > - - - > 65 > - - -
--  silence --    low    --  medium   --   high    -- full  |
--    - - < 32 < - - - < 35 < - - - < 45 < - - - < 55 < - - -
function temp( temp )
	logtemp(temp)
	if last_fan_setting == "full" then
		if temp < 55 then
			setfan(temp, "high")
		end
	elseif last_fan_setting == "high" then
		if temp > 65 then
			setfan(temp, "full")
		elseif temp < 45 then
			setfan(temp, "medium")
		end
	elseif last_fan_setting == "medium" then
		if temp > 50 then
			setfan(temp, "high")
		elseif temp < 35 then
			setfan(temp, "low")
		end
	elseif last_fan_setting == "low" then
		if temp > 40 then
			setfan(temp, "medium")
		elseif temp < 32 then
			setfan(temp, "silence")
		end
	elseif last_fan_setting == "silence" then
		if temp > 35 then
			setfan(temp, "low")
		end
	else
		setfan(temp, "high")
	end
end

confdir("/etc/qcontrol.d")
--
-- Local variables:
-- mode: lua
-- indent-level: 8
-- End:

Re-Installing QNAP Firmware

Recovering from this change is the true inverse of the above;

# path to mdt{0..5} images
cd /mnt/data/mdt/
for i in $PWD/mtdblock{1,2}; do cat $(basename "$i") > /dev/$i; done

A reboot should boot into the QNAP kernel, from where you will need to check your DHCP leases for the device's IP. Via it's HTTP interface, you will need to re-install the QNAP firmware.

SGNLS.net © 2006-2017

Comments, submissions and errors to desk[at]sgnls.net.

Material and content adheres to the Creative Commons (NC-SA 4.0) license.

v12.01151