My first home server

I am very proud of this little machine. Initially, I had the following things on the list of requirements:

  1. Fully compatible with Linux (in particular, Arch Linux)
  2. Silent (in particular, fanless)
  3. Low-power
  4. Compact and beautiful

Selected hardware:

  1. Motherboard: ASRock Q1900DC-ITX
  2. RAM (2): Kingston KVR16LS11/8
  3. SSD: Kingston SV300S37A/120G
  4. HDD (2): Western Digital WD10JFCX
  5. Power adapter: Targus Compact Laptop & USB Tablet Charger (APA042EU)
  6. Case: Streacom F1CWS Evo Chassis

The main reasons for choosing this particular motherboard were the low power consumption, convenience of a decent integrated CPU (Intel J1900), fanless design, Mini-ITX form factor, and complete compatibility with Linux. Other interesting features include 4 SATA connectors (2.0 and 3.0), plenty of USB ports (2.0 and 3.0), several graphics outputs (HDMI, DVI-D and D-Sub, all up to a resolution of 1920 by 1200 at 60Hz), and an integrated power supply unit which accepts any voltage between 9 and 19V, ±10%. An additional important detail is that the motherboard supports Wake-on-LAN. In terms of RAM, 2 8GB DDR3L modules were used, resulting in the maximum 16GB supported by the motherboard. As for non-volatile memory, a 120GB SSD and 2 1TB HDDs were used, with the goal of installing the operating system and services on the SSD while leaving the HDDs exclusively for storage. The SSD is just a regular SSD. On the other hand, the HDDs were selected based on reliability and acoustic specifications. The power required by the motherboard is supplied by a very compact and energy-efficient 90W power adapter. Based on the user manual of the motherboard, number of RAM modules and number of disks, 90W are enough to power the system. It is worth noting that the adapter comes with an integrated 2.1A USB fast charging port. Regarding the case, the F1CWS Evo is compatible with the Mini-ITX form factor, robust, and also quite small, especially considering that it can hold up to 3 2.5” disks. The case is made entirely of aluminum with a very beautiful sandblast finish.

The software currently running in the previously described hardware is a minimal install of Arch Linux with remote administration through SSH, RAID 1, LVM, an SMB server for local file sharing and an HTTP server (Apache) with PHP and WebDAV support. Everything is installed based on the following 3 bash scripts. Running the first bash script after booting from an Arch Linux image installs the base system on the SSD and configures SSH. In order for the script to execute properly, there must be internet connectivity and the public key key.pub intended to be used with SSH must be placed in the same directory as the script.

#!/bin/bash
if [ ! -f 'key.pub' ]; then exit 1; fi
curl -o list 'https://www.archlinux.org/mirrorlist/?country=PT&use_mirror_status=on'
if [ ! -f 'list' ]; then exit 2; fi
mv list /etc/pacman.d/mirrorlist
sed -i -e 's/#Server/Server/' /etc/pacman.d/mirrorlist
sgdisk -Z /dev/sda
sgdisk -n 1:2048:+512M -t 1:EF00 /dev/sda
sgdisk -n 2:0:+16G -t 2:8300 /dev/sda
sgdisk -n 3:0:+4G -t 3:8200 /dev/sda
sgdisk -n 4:0:0 -t 4:8300 /dev/sda
mkfs.fat -F 32 /dev/sda1
mkfs.ext4 -F /dev/sda2
mkswap /dev/sda3
mount /dev/sda2 /mnt
mkdir /mnt/boot
mount /dev/sda1 /mnt/boot
pacstrap /mnt base
echo "UUID=$(lsblk -no UUID /dev/sda2) / ext4 rw,relatime,data=ordered 0 1
UUID=$(lsblk -no UUID /dev/sda1) /boot vfat rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro 0 2
UUID=$(lsblk -no UUID /dev/sda3) none swap defaults 0 0" > /mnt/etc/fstab
echo 'vm.swappiness=10' > /mnt/etc/sysctl.d/99-sysctl.conf
sed -i -e 's/#en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /mnt/etc/locale.gen
arch-chroot /mnt locale-gen
echo 'LANG=en_US.UTF-8' > /mnt/etc/locale.conf
ln -s /usr/share/zoneinfo/Europe/Lisbon /mnt/etc/localtime
arch-chroot /mnt hwclock --utc
sed -i -e 's/MODULES=""/MODULES="i915"/' /mnt/etc/mkinitcpio.conf
arch-chroot /mnt mkinitcpio -p linux
arch-chroot /mnt bootctl --path=/boot install
echo 'title "Arch Linux"
efi /vmlinuz-linux
options initrd=/intel-ucode.img initrd=/initramfs-linux.img root=/dev/sda2 rw' > /mnt/boot/loader/entries/arch.conf
echo 'default arch' > /mnt/boot/loader/loader.conf
echo 'SRV' > /mnt/etc/hostname
sed -i -e 's/localhost/localhost SRV/2' /mnt/etc/hosts
arch-chroot /mnt pacman -S --needed --noconfirm \
$(echo '
dosfstools
efibootmgr
gptfdisk
intel-ucode
ntfs-3g
openssh
unzip
wget
zip
apache
ffmpeg
php
php-apache
rsync
samba')
echo '[Match]
Name=en*
[Network]
Address=192.168.1.100/24
DHCP=no
DNS=192.168.1.254
Gateway=192.168.1.254' > /mnt/etc/systemd/network/10-static.network
mv /mnt/etc/resolv.conf /mnt/etc/resolv.conf.default
ln -s /run/systemd/resolve/resolv.conf /mnt/etc/resolv.conf
cp /mnt/etc/ssh/sshd_config /mnt/etc/ssh/sshd_config.default
echo 'AuthorizedKeysFile /etc/ssh/authorized_keys
ChallengeResponseAuthentication no
LogLevel VERBOSE
MaxAuthTries 6
MaxSessions 1
PasswordAuthentication no
PermitRootLogin prohibit-password
Port 22
Protocol 2
PubkeyAuthentication yes
SyslogFacility AUTH
UsePAM no' > /mnt/etc/ssh/sshd_config
cat key.pub > /mnt/etc/ssh/authorized_keys
arch-chroot /mnt systemctl enable systemd-networkd.service systemd-resolved.service sshd.socket
echo 'ROOT'
arch-chroot /mnt passwd
umount -R /mnt

Only the mirrors from Portugal are considered in the script. The root password is requested at the end. After rebooting, the IP will be set to 192.168.1.100 static and SSH will be ready for key-based passwordless login on port 22. The second script configures the last physical partition of the SSD for LVM and creates 2 logical partitions, combines the 2 HDDs in RAID 1, configures the resulting space for LVM and creates 4 logical partitions.

#!/bin/bash
pvcreate /dev/sda4
vgcreate vg0 /dev/sda4
lvcreate --name lv0 --size 64G vg0
lvcreate --name lv1 --size 26G vg0
mkfs.ext4 /dev/vg0/lv0
mkfs.ext4 /dev/vg0/lv1
sgdisk -Z /dev/sdb
sgdisk -Z /dev/sdc
sgdisk -n 1:2048:+931G -t 1:FD00 /dev/sdb
sgdisk -n 1:2048:+931G -t 1:FD00 /dev/sdc
mdadm --create --metadata=1.2 --raid-devices=2 --level=1 /dev/md0 /dev/sdb1 /dev/sdc1
cp /etc/mdadm.conf /etc/mdadm.conf.default
echo -e "DEVICE partitions\n$(mdadm --detail --scan)" > /etc/mdadm.conf
mdadm --assemble /dev/md0
pvcreate /dev/md0
vgcreate vg1 /dev/md0
lvcreate --name lv0 --size 512G vg1
lvcreate --name lv1 --size 128G vg1
lvcreate --name lv2 --size 128G vg1
lvcreate --name lv3 --size 128G vg1
mkfs.ext4 /dev/vg1/lv0
mkfs.ext4 /dev/vg1/lv1
mkfs.ext4 /dev/vg1/lv2
mkfs.ext4 /dev/vg1/lv3
mkdir /srv/http/cloud
mkdir /srv/smb
mkdir /srv/smb/n0
mkdir /srv/smb/n1
mkdir /srv/smb/n2
mkdir /srv/smb/n3
echo "UUID=$(lsblk -no UUID /dev/vg0/lv0) /srv/http/cloud ext4 rw,relatime,data=ordered 0 2
UUID=$(lsblk -no UUID /dev/vg0/lv1) /home ext4 rw,relatime,data=ordered 0 2
UUID=$(lsblk -no UUID /dev/vg1/lv0) /srv/smb/n0 ext4 rw,relatime,data=ordered 0 2
UUID=$(lsblk -no UUID /dev/vg1/lv1) /srv/smb/n1 ext4 rw,relatime,data=ordered 0 2
UUID=$(lsblk -no UUID /dev/vg1/lv2) /srv/smb/n2 ext4 rw,relatime,data=ordered 0 2
UUID=$(lsblk -no UUID /dev/vg1/lv3) /srv/smb/n3 ext4 rw,relatime,data=ordered 0 2" >> /etc/fstab

After rebooting, the partitions will be automatically mounted. The third and last script takes care of configuring the SMB server and the Apache HTTP server.

#!/bin/bash
echo '[global]
create mask = 0744
directory mask = 0755
disable netbios = yes
disable spoolss = yes
dns proxy = no
force create mode = 0600
force directory mode = 0755
guest account = nobody
load printers = no
log file = /var/log/samba/samba.log
log level = 0
map to guest = Bad User
max log size = 5000
printcap name = /dev/null
printing = bsd
security = user
server string = SMB
workgroup = GROUP
[n0]
browseable = no
guest ok = yes
max connections = 5
only guest = yes
path = /srv/smb/n0/n0
writable = yes
[n1]
browseable = no
guest ok = yes
max connections = 5
only guest = yes
path = /srv/smb/n1/n1
writable = yes
[n2]
browseable = no
guest ok = yes
max connections = 5
only guest = yes
path = /srv/smb/n2/n2
writable = yes
[n3]
browseable = no
guest ok = yes
max connections = 5
only guest = yes
path = /srv/smb/n3/n3
writable = yes' > /etc/samba/smb.conf
mkdir /srv/smb/n0/n0
mkdir /srv/smb/n1/n1
mkdir /srv/smb/n2/n2
mkdir /srv/smb/n3/n3
chown nobody:nobody /srv/smb/n0/n0
chown nobody:nobody /srv/smb/n1/n1
chown nobody:nobody /srv/smb/n2/n2
chown nobody:nobody /srv/smb/n3/n3
cp /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.default
echo 'ServerRoot "/etc/httpd"
Listen 80
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule logio_module modules/mod_logio.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so
LoadModule dav_lock_module modules/mod_dav_lock.so
LoadModule dir_module modules/mod_dir.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule php7_module modules/libphp7.so
User http
Group http
ServerAdmin r12624@gmail.com
DavLockDB "/etc/httpd/conf/davlock/davlock"
DocumentRoot "/srv/http"
RewriteEngine on
RewriteRule "^/$" "/index.php" [PT]
<Directory "/">
Require all denied
Options None
AllowOverride None
DirectoryIndex disabled
</Directory>
<Directory "/srv/http">
<FilesMatch "^(index|error)\.php$">
Require all granted
</FilesMatch>
<Files "favicon.ico">
Require all granted
</Files>
<Files "robots.txt">
Require all granted
</Files>
</Directory>
<Directory "/srv/http/core">
Require all granted
Options FollowSymLinks
DirectoryIndex index.html index.php
</Directory>
<Directory "/srv/http/cloud">
Require all granted
</Directory>
<Directory "/srv/http/cloud/h-?*-end">
Dav On
</Directory>
<Location "/cloud/lost+found">
DirectorySlash Off
</Location>
<FilesMatch "\.php$">
SetHandler application/x-httpd-php
</FilesMatch>
ErrorLog "/var/log/httpd/error_log"
LogLevel info
LogFormat "%{%Y-%m-%d %H:%M:%S %z}t %h \"%r\" %>s %I %O \"%{Referer}i\" \"%{User-agent}i\"" simple
CustomLog "/var/log/httpd/access_log" simple
PidFile "/run/httpd/httpd.pid"
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 250
MaxConnectionsPerChild 0
MaxMemFree 2048
ErrorDocument 400 /error.php
ErrorDocument 401 /error.php
ErrorDocument 402 /error.php
ErrorDocument 403 /error.php
ErrorDocument 404 /error.php
ErrorDocument 405 /error.php
ErrorDocument 406 /error.php
ErrorDocument 407 /error.php
ErrorDocument 408 /error.php
ErrorDocument 409 /error.php
ErrorDocument 410 /error.php
ErrorDocument 411 /error.php
ErrorDocument 412 /error.php
ErrorDocument 413 /error.php
ErrorDocument 414 /error.php
ErrorDocument 415 /error.php
ErrorDocument 416 /error.php
ErrorDocument 417 /error.php
ErrorDocument 500 /error.php
ErrorDocument 501 /error.php
ErrorDocument 502 /error.php
ErrorDocument 503 /error.php
ErrorDocument 504 /error.php
ErrorDocument 505 /error.php
BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
BrowserMatch "MS FrontPage" redirect-carefully
BrowserMatch "^WebDrive" redirect-carefully
BrowserMatch "^WebDAVFS/1.[01234]" redirect-carefully
BrowserMatch "^gnome-vfs/1.0" redirect-carefully
BrowserMatch "^XML Spy" redirect-carefully
BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully
BrowserMatch " Konqueror/4" redirect-carefully
Timeout 60
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5
UseCanonicalName Off
AccessFileName .htaccess
ServerTokens Full
ServerSignature Off
HostnameLookups Off
RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500' > /etc/httpd/conf/httpd.conf
mkdir /srv/http/core
mkdir /etc/httpd/conf/davlock
chown http:http /etc/httpd/conf/davlock
systemctl enable smbd.service httpd.service

Regarding SMB, 4 shares with no password are created. Read-only attributes are automatically removed from any file or folder copied to the SMB server. Regarding the HTTP server, access to the root folder is denied, except for the files index.php, error.php, favicon.ico and robots.txt, and the folders core and cloud. Inside the core directory or any of its subdirectories, any index files named index.html or index.php are automatically interpreted. WebDAV is automatically enabled for any directories inside cloud with names beginning with h-, ending with -end, and with at least 1 character in the middle. Even though the WebDAV folders are not protected by any password, this mechanism based on folder names with a random component is perfectly fine for temporary file transfers from and to the home server.

Lastly, the power consumption of this system, including the power adapter, stabilizes at 12.9W after the boot process is finished. This value drops to 11.2W everytime the HDDs switch to a low power state after a few minutes of inactivity. When the system is powered off but still listening for Wake-on-LAN packets, the power consumption drops to 2.4W.

Sources:
Building a new fanless and silent server and NAS
Round-up of 74 laptop power adapters: original or universal?

Advertisements