ATTENTION: CifarelliWiki is not now, nor was it ever, intended to be a public wiki.

New tvpc

From CifarelliWiki
Jump to: navigation, search

The distribution is Archlinux x86_64


ASUS E-45M1-M Pro E-450 A50M R (Hudson M1 APU, includes ATI HD 6320 graphics) UEFI MB
2 Seagate ST31000524AS 1T, SATA 6 32M as a Raid 1 array
G.Skill 8GB (2 x 4GB) DDR3 240 pin
300W PS

Disk setup

First, we want to make GPT partitions, so we use gdisk (which is like the old fdisk, but it is GPT compatible). So we make 3 partitions on each disk (sda and sdb):

partition 1: type ef00, 6GB (2048 - 12584959)
partition 2: type 8200, 8GB (12584960 - 29362175)
partition 3: type fd00, 917.5GB (29362176 - 1953525134)

create a VFAT filesystem on the 1st partition:

# mkfs.vfat -F32 /dev/sda1
# mkfs.vfat -F32 /dev/sdb1

(we only need one, but we're building a poor man's mirror for this partition.)

and swap on the 2nd:

# mkswap /dev/sda2
# mkswap /dev/sdb2

and a raid disk out of the 3rd partition:

# mdadm /dev/md0 --create --level=1 --raid-devices=2 /dev/sda3 /dev/sdb3

let it build and the make a volume group on it:

# vgchange -ay
# pvcreate /dev/md0
# vgcreate vg0 /dev/md0
# lvcreate /dev/vg0 -L 20G -n root
# lvcreate /dev/vg0 -L 20G -n var
# lvcreate /dev/vg0 -L 20G -n boot
# lvcreate /dev/vg0 -L 825G -n home
# mkfs -t ext2 /dev/vg0/boot
# mkfs -t ext4 /dev/vg0/root
# mkfs -t ext4 /dev/vg0/var
# mkfs -t ext4 /dev/vg0/home

Mountpoints as follows:

/dev/vg0/root /
/dev/vg0/boot /boot
/dev/sda2     /boot/efi
/dev/sdb2     /boot/efi2
/dev/vg0/var  /var
/dev/vg0/home /home

and follow the Arch install directions [1] or [2]

don't forget to add the mdadm and lvm2 hooks in mkinitcpio in /etc/mkinitcpio.conf

HOOKS="base udev autodetect pata scsi sata mdadm lvm2 filesystems usbinput fsck"

UPDATE: you need the mdadm_udev hook instead of the deprecated mdadm hook as of Feb '13. The hook "block" replaces pata, scsi, sata and keyboard replaces usbinput. Also add the dm_mod module to the MODULES list:

HOOKS="base udev autodetect modconf block mdadm_udev lvm2 filesystems keyboard fsck"


# mkinitcpio -p linux

(note that the install cd includes gdisk, but you will need to install it separately after the install.)

UPDATE: I added an opt partition, also of size 20G.

UEFI Setup

This was the thing that took the longest. At this time (Nov 2012) we are making the transition from the old BIOS/MBR motherboards/partitions to the newer UEFI/GPT MB/Partitions.

But, in the end it was mostly just following these instructions [3] using EFISTUB and rEFInd.

But modified to copy kernels to /boot/efi2 as well as /boot/efi

UPDATE: Jan 2014 /dev/sda failed (of course), and when I was replacing it I somehow messed it up (I think by using the -w flag on efibootmgr).

So I switched to gummiboot, using /dev/sdb1 as the efi partition. /dev/sda1 exists, but the boot nvram entry now points to /dev/sdb1 instead.

Couple of things:

- Don't forget that the disks need to be partitioned as GPT disks use gdisk for this. (parted, gparted, gptfdisk, (maybe) fdisk with GPT support are other options, but gdisk works).

- Don't use efibootmgr -w to "write a unique signature" on your new disk. If you get this error, there is probably something else wrong.

- I booted into an arch install for rescue, but for some reason efibootmgr below wouldn't work properly within the chroot. It could be because the arch install in the chroot was newer, and some incompatible shlib may have been picked up. But worse was it caused dump-* files to be created in /sys/firmware/efi/efivars, resulting in "no room on device" or similar error I cant remember now when creating the boot entry in nvram. Needed to not only delete the dump-* files, but also reboot the rescue with kernel parameter efi_no_storage_paranoia to get the boot entry created.

If a disk fails, you need to rebuild the array /dev/md0 and may have to reinstall the bootloader. Well, it seems to me you always have to do something with the bootloader, but damned if I can predict it.

Setup the partitions

Create FAT32 UEFI System Partitions on /dev/sdb1 as above.
Mount the UEFI System Partitions at /boot/efi. [and /dev/sda1 on /boot/efi2 to save the latest kernel in case a disk crashes]
Create /boot/efi/EFI/arch/ directory.
Copy /boot/vmlinuz-linux to /boot/efi/EFI/arch/vmlinuz-arch.efi (and /boot/efi2/EFI/arch/vmlinuz-arch.efi). 
   The .efi file extension is very important as some UEFI firmwares refuse to launch a file without the .efi file extension.
Copy /boot/initramfs-linux.img to /boot/efi/EFI/arch/initramfs-arch.img.
Copy /boot/initramfs-linux-fallback.img to /boot/efi/EFI/arch/initramfs-arch-fallback.img.
   A new feature to be introduced in kernel 3.7 is the ability to store the kernel boot parameters in a file.
   [begin: unnecessary, but no harm.  only needed for refind]
   I did this even though the kernel I'm on is only 3.6.6.
   So, create /boot/efi/EFI/arch/linux.conf with the kernel parameters to be passed to the kernel. 
   This file should consist of only one line and simply contains all the kernel parameters to be used by the EFISTUB loader to the kernel:

   root=PARTUUID=31be0116-401c-4499-96c0-7433afd9a9be ro rootfstype=ext4 add_efi_memmap initrd=\EFI\arch\initramfs-arch.img
   [end: unnecessary]

Kernel copy service

Since the kernel and initramfs will be placed in /boot everytime they're upgraded, we add a copy service to systemd (systemd has the ability to monitor files and execute scripts when they change).

create /etc/systemd/system/efistub_copy.path

Description=Copy EFISTUB Kernel and Initramfs to UEFISYS Partition



and /etc/systemd/system/efistub_copy.service

Description=Copy EFISTUB Kernel and Initramfs to UEFISYS Partition

ExecStart=/bin/cp -f /boot/vmlinuz-linux /boot/efi/EFI/arch/vmlinuz-arch.efi
ExecStart=/bin/cp -f /boot/initramfs-linux.img /boot/efi/EFI/arch/initramfs-arch.img
ExecStart=/bin/cp -f /boot/initramfs-linux-fallback.img /boot/efi/EFI/arch/initramfs-arch-fallback.img
ExecStart=/bin/cp -f /boot/vmlinuz-linux /boot/efi2/EFI/arch/vmlinuz-arch.efi
ExecStart=/bin/cp -f /boot/initramfs-linux.img /boot/efi2/EFI/arch/initramfs-arch.img
ExecStart=/bin/cp -f /boot/initramfs-linux-fallback.img /boot/efi2/EFI/arch/initramfs-arch-fallback.img

The path service needs to be enabled and started - it's the actual monitor.

# systemctl enable efistub_copy.path
# systemctl start efistub_copy.path

The copy service is static; it will be called by the path service, so it does not need to be enabled/started.

Booting EFISTUB with gummiboot

Install gummiboot and create a boot entry in the nvram:

# pacman -Sy gummiboot
# gummiboot --path=/boot/efi install

to display the efi system's view of gummiboot's install:

# gummiboot --path=/boot/efi

will display:

Boot Loader Binaries:
          ESP: /dev/disk/by-partuuid/bb38ac70-1730-41c1-aad5-355b6288a299
         File: └─/EFI/gummiboot/gummibootx64.efi (gummiboot 31)
         File: └─/EFI/Boot/bootx64.efi (gummiboot 31)

Boot Loader Entries in EFI Variables:
        Title: Linux Boot Manager
           ID: 0x0000
       Status: active, boot-order
    Partition: /dev/disk/by-partuuid/bb38ac70-1730-41c1-aad5-355b6288a299
         File: └─/EFI/gummiboot/gummibootx64.efi

To view the nvram:

# modprobe efivars
# efibootmgr -v

will display:

BootCurrent: 0000
Timeout: 1 seconds
BootOrder: 0000,0005
Boot0000* Linux Boot Manager    HD(1,800,bff800,bb38ac70-1730-41c1-aad5-355b6288a299)File(\EFI\gummiboot\gummibootx64.efi)
Boot0005* Hard Drive    BIOS(2,0,00)SATA: ST31000524AS            .

Note that the uuid in the Linux Boot Manager entry is the partition uuid (the one displayed by partx).

Check the man page on efibootmgr for how to manipulate the nvram boot entries.

Now configure gummiboot:

1. edit /boot/efi/loader/loader.conf

#timeout 3
default arch*

(yes I've commented out the timeout; I'm only using the default entry)

2. edit or create /boot/efi/loader/entries/arch.conf

title Arch Linux
efi /EFI/arch/vmlinuz-arch.efi
options initrd=/EFI/arch/initramfs-arch.img ro root=UUID=31be0116-401c-4499-96c0-7433afd9a9be rootfstype=ext4 add_efi_memmap

Note that the UUID listed in the options is not the partition uuid (the one from partx) but rather the one generated by genfstab. In my case (LVM) that should be obvious, I think.

To display both UUIDs, use blkid:

# blkid
/dev/sdb1: UUID="5885-A37A" TYPE="vfat" PARTUUID="bb38ac70-1730-41c1-aad5-355b6288a299"
/dev/sdb2: UUID="5a47cb61-c9fe-4d9b-a023-51fa2e4d6b8c" TYPE="swap" PARTUUID="42f54815-bf32-4e54-ab37-4c64fdbcf68c"
/dev/sdb3: UUID="7773f1ad-724e-380e-be26-e23d9c3c6710" UUID_SUB="c91517c3-2e3f-5d91-b814-3d08be39d6bf" LABEL="archiso:0" TYPE="linux_raid_member" PARTUUID="1a77ba1f-8088-4626-8897-c6a6425b0424"
/dev/sda1: UUID="B8D7-B197" TYPE="vfat" PARTUUID="a9b4d71e-8b65-4b9a-a721-46222658ab68"
/dev/sda2: UUID="f84116cb-eb0e-4a20-9686-1229a6357bab" TYPE="swap" PARTUUID="086c52c1-8ab4-4414-b36a-1c3b39007cfb"
/dev/sda3: UUID="7773f1ad-724e-380e-be26-e23d9c3c6710" UUID_SUB="1328c0c8-363d-2ee4-9ec4-1627694fcee0" LABEL="archiso:0" TYPE="linux_raid_member" PARTUUID="30f3324e-0543-48fc-aaca-659695413ed1"
/dev/md0: UUID="ZM6x42-fHmt-tDaN-Dfqc-9K5i-4eWh-HL68VU" TYPE="LVM2_member"
/dev/mapper/vg0-root: UUID="31be0116-401c-4499-96c0-7433afd9a9be" TYPE="ext4"
/dev/mapper/vg0-boot: UUID="32b0e434-38c3-4f0b-92b7-fa390953d9ec" TYPE="ext2"
/dev/mapper/vg0-var: UUID="3693fd50-2c30-4e24-9492-c2dde4939c99" TYPE="ext4"
/dev/mapper/vg0-home: UUID="fd2557be-5567-464e-a7fb-dba9b4944318" TYPE="ext4"

Now create a path monitor and install service for gummiboot. This is necessary because gummiboot assumes by default that the EFI partition is mounted at /boot, and we are mounting it at /boot/efi. So when an upgrade occurs, the gummiboot install fails.


Description=Reinstall gummiboot on upgrade to UEFISYS Partition




Description=Install gummiboot bootloader to UEFISYS Partition on upgrade

ExecStart=/usr/bin/gummiboot --path=/boot/efi install

Enable the path service as before:

# systemctl enable gummiboot_install.path
# systemctl start gummiboot_install.path

Booting EFISTUB with rEFInd

** this section no longer necessary, but of no real harm.  now using gummiboot **

Now setup for booting EFISTUB using rEFInd. This part got a little tricky.

EFI, unlike MBR, allows you to boot directly a number of OSs, so in that respect it is like a bootloader. rEFInd is a boot loader, so it's like you install it as an EFI "loader", and it then allows you to load any number of other kernels. So I guess it's just more mature as an EFI loader at this time than egrub or elilo.

It took a little trial and error, but apparently what it does is scan for all loadable efi images in the efi partition you created before. So (if you allow it), it also adds itself and any other kernels it finds. Following the instructions, I modified the config file (EFI/refind/refind.conf) to explicitly include the kernels, which (I think) added them again. The instructions said to modify this file "accordingly, it is well documented", and it gave examples of adding entries, so really a little more explanation would have been good.

(Note, everything done below is also done with /boot/efi2)

install refind:

# pacman refind-efi
# mkdir /boot/efi/EFI/refind
# cp /usr/lib/refind/refindx64.efi /boot/efi/EFI/refind/refindx64.efi
# cp /usr/lib/refind/config/refind.conf /boot/efi/EFI/refind/refind.conf
# cp -r /usr/share/refind/icons /boot/efi/EFI/refind/icons

now create /boot/EFI/arch/refind_linux.conf

"Boot with defaults" "root=PARTUUID=3518bb68-d01e-45c9-b973-0b5d918aae96 ro rootfstype=ext4 add_efi_memmap"
"Boot to Terminal"   "root=PARTUUID=3518bb68-d01e-45c9-b973-0b5d918aae96 ro rootfstype=ext4 add_efi_memmap"

It seems like refind scans for this file and adds entries for each one, but it doesnt seem to find icons for it, and noe that I have done this I'm not sure I'm really using this file.

Now I edited EFI/refind/refind.conf and made the following changes:


timeout 5
icons_dir \EFI\icons
dont_scan_dirs EFI/boot,EFI/arch,EFI/refind

(actually, I ended up removing the EFI/boot directory, which was supposed to be some kind of failsafe)

Add these lines at the end:

menuentry "Arch Linux" {
        icon EFI/icons/os_linux.icns
        loader \EFI\arch\vmlinuz-arch.efi
        initrd \EFI\arch\initramfs-arch.img
        options "ro root=UUID=31be0116-401c-4499-96c0-7433afd9a9be rootfstype=ext4 add_efi_memmap initrd=\EFI\arch\initramfs-arch.img"

menuentry "Arch Linux Fallback" {
        icon EFI/icons/os_linux.icns
        loader \EFI\arch\vmlinuz-arch.efi
        initrd \EFI\arch\initramfs-arch-fallback.img
        options "ro root=UUID=31be0116-401c-4499-96c0-7433afd9a9be rootfstype=ext4 add_efi_memmap initrd=\EFI\arch\initramfs-arch-fallback.img"

Now execute this:

# modprobe efivars
# efibootmgr -c -g -d /dev/sdX -p Y -w -L "rEFInd" -l '\EFI\refind\refindx64.efi'

Truth be told, I did something a bit more roundabout - I think what I've listed here is sufficient. In reality though I executed the efibootmgr line without the 'dont_scan' option in the config file, didnt like how the boot screen looked, and then did it again with the dont scan, which made multiple entries in EFI (I may have done it more than twice), so I deleted as many as I could but it wouldnt remove all of them, so then I added it the way I wanted and set the bootorder to 0001,0000. That resulted in a pretty decent boot screen (although the text annoyingly says "Boot Arch Linux from" and I cant figure out where to set "from").

Also create a service for when refind is updated:


Description=Copy rEFInd bootloader to UEFISYS Partition




Description=Copy rEFInd bootloader to UEFISYS Partition

ExecStart=/bin/cp -f /usr/share/refind/refind_x64.efi /boot/efi/EFI/refind/refindx64.efi
ExecStart=/bin/cp -f /usr/share/refind/refind_x64.efi /boot/efi2/EFI/refind/refindx64.efi
** end unnecessary **

Booting with GRUB

After the second Seagate drive failed, I couldn't get gummiboot to work (ARGH!!)

So converted to grub, which now supports UEFI much better.


# pacman grub dosfstools efibootmgr

Mount in /boot/efi:

# mount /dev/sda1 /boot

Execute grub-install:

# grub-install  --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=grub --recheck --debug

Create the config:

# grub-mkconfig -o /boot/grub/grub.cfg

Reboot and you are back to grub.

UPDATE: After installing a new video card (XFX HD 5450) I had to change the kernel command parameters. Honestly I'm not convinced this was necessary, but as with many things related to graphics, it didn't *seem* to work at first, but works after doing this. The way it works makes me suspicious that this is what fixed it. Anyway, to add to the kernel command line parameters, modify /etc/default/grub:




GRUB_CMDLINE_LINUX_DEFAULT="quiet video=HDMI-A-1:640x480@60"

As an aside, I also had to select the proper device using pavcontrol.

If a disk fails

2 failed disks; 3 different boot methods. Frustrating, but we've learn a few things:

(I have to stop buying Seagate drives. Went to a WD Red for the last update.)

  1. Use smartctl -i /dev/sda to find the serial number, if you have identical disks.
  2. Print this page please before upgrading.
  3. Boot a rescue arch image to partition the disk, if adding the new disk causes UEFI to loose the prior boot disk (which it has 2x now)
  4. To boot from a UEFI shell (v1 or v2):
Shell> fs0:
 fs0:> cd \EFI\ARCH
 fs0:> vmlinuz-arch.efi initrd=/EFI/ARCH/initramfs-arch.img root=UUID=31be0116-401c-4499-96c0-7433afd9a9be rootfstype=ext4 add_efi_memmap

As mentioned before, the UUID is the lv /dev/vg0/root.


eth0: Just plug in the cable. Dhcpcd is already running for all wired interfaces in Arch.

Wireless: Of course, more complicated, but getting better.

I'm using an Intel Centrino Advanced-N 6205 PCIe 1x card. Includes the half height bracket and an external antenna for signal strength. The card was detected without any trouble, the firmware and iwlwifi driver loaded as well.

Need to install iw and wpa_supplicant:

# pacman -Sy iw wpa_supplicant

Setup wpa_supplicant:

# cd /etc/wpa_supplicant
# cp ./wpa_supplicant.conf ./wpa_supplicant.conf.reference
# wpa_passphrase paulc_ap4 '<wireless password>' > ./wpa_supplicant.conf

Edit wpa_supplicant.conf and add lines to make it look like this:

        proto=WPA RSN
        key_mgmt=WPA-PSK WPA-EAP
        #psk="<wireless password>" <-- obviously you dont need to keep this
        psk=<psk generated by wpa_passphrase>

Honestly I don't know how much of this we need. But it was taken from the wpa_supplicant.conf.reference. Note that RSN means "Robust Security Network" and is synonomous with WPA2.

change permissions to 0640:

# chmod 0640 ./wpa_supplicant.conf

Now create a system service /etc/systemd/system/network-wireless@.service:

Description=Wireless network connectivity (%i)


ExecStart=/usr/bin/ip link set dev %i up
ExecStart=/usr/bin/wpa_supplicant -B -i %i -c /etc/wpa_supplicant/wpa_supplicant.conf
ExecStart=/usr/bin/dhcpcd %i

ExecStop=/usr/bin/ip link set dev %i down


When you want to use wireless,

# systemctl start network-wireless@wlan0

and to use wireless all the time:

# systemctl enable network-wireless@wlan0

[UPDATE] I decided to go with static IPs, which requires a few different things:

First, you need your own resolv.conf. The only necessary entry is the one for your wireless router, but I added OpenDNS and Google servers for reference. Because dhcpcd for eth0 will still overwrite resolv.conf on boot, name this file resolv.conf.head (it will be added by dhcpcd to resolv.conf, at the head):

# OpenDNS nameservers
# Google nameservers

# OpenDNS ipv6 nameservers
nameserver [2620:0:ccc::2]
nameserver [2620:0:ccd::2]                                                                          
# Google ipv6 nameservers
nameserver [2001:4860:4860::8888]
nameserver [2001:4860:4860::8844]

Next, you need a modified /etc/systemd/system/network-wireless@.service:

Description=Wireless network connectivity (%i)


ExecStart=/usr/bin/ip link set dev %i up
ExecStart=/usr/bin/wpa_supplicant -B -i %i -c /etc/wpa_supplicant/wpa_supplicant-%i.conf
#ExecStart=/usr/bin/dhcpcd %i
ExecStart=/usr/bin/ip addr add ${address}/${netmask} broadcast ${broadcast} dev %i
ExecStart=/usr/bin/sh -c 'test -n ${gateway} && /usr/bin/ip route add default via ${gateway}'
ExecStart=/usr/bin/cp /etc/resolv.conf.static /etc/resolv.conf
# Permanent ARP Entries:
# supposed to be the new way, but didn't work for me  
#ExecStart=/usr/bin/ip n add lladdr 6c:88:14:99:18:20 dev %i nud perm  
#ExecStart=/usr/bin/ip n add lladdr 00:13:ef:10:06:be dev %i nud perm  
# beast:
ExecStart=/usr/bin/arp -i %i -s 6c:88:14:99:18:20
# raspberrypi:
ExecStart=/usr/bin/arp -i %i -s 00:13:ef:10:06:be

ExecStop=/usr/bin/ip addr flush dev %i
ExecStop=/usr/bin/ip link set dev %i down


For a reason I was never able to ascertain, sometimes arp doesn't work properly on a wireless connection. This prevents us from finding those hosts, even though we can reach them from other machines. The problem happens on both windows and linux hosts, so I assume it's the wireless router. So here we add static arp entries.

On Kubuntui and Raspbian, add a script /etc/network/if-up.d/static-arp-entries (make it executable, 755)


# tvpc
arp -i wlan0 -s <ip address> <MAC address>

# raspberrypi
arp -i wlan0 -s <ip address> <MAC address>

On Arch, add to network-wireless@.service as above.

On Windows 8.1 (and probably Windows 7), in Powershell running as Administrator:

netsh interface ipv4 delete neighbors 4 ""
netsh interface ipv4 add neighbors 4 "" "aa-bb-cc-dd-ee-ff"

replace the 4 (which is the index of the interface) with the index found when you do an "arp -a". These are permanent (they survive a reboot).



I've been experimenting with powerline networking, now that they are approaching gigabit speeds. I have to say I'm pleasantly surprised.

I bought 4 ZyXEL PAL5215 (600Mbps) and have re-configured this server with a bonded interface, primary eth0, backup wlan0.

In the process I cleaned up the networking using netctl, which allows you to setup multiple profiles and switch between them easily.

setup netctl and bonding:

Disable network-wireless@wlan0, dhcpcd@eth0, and disable-eth0.service.

install netctl and ifenslave

# pacman -Sy netctl ifenslave

setup profiles in /etc/netctl


Description="Bonded interface ethernet to wireless failover"
BindsToInterfaces=('eth0' 'wlan0')
#DNS=('' '' '' '' '' '[2620:0:ccc::2]' '[2620:0:ccd::2]' '[2001:4860:4860::8888]' '[2001:4860:4860::8844]')

/etc/netctl/ethernet-dhcp (not needed, but we started with this):

Description='A basic dhcp ethernet connection'

/etc/netctl/wireless-wpa-config (also not needed...):

Description='A wpa_supplicant configuration file based wireless connection'

Create /etc/modules-load.d/bonding.conf to load the bonding module at boot:


Create /etc/modprobe.d/bonding.conf for the bonding module parameters:

options bonding mode=active-backup miimon=100 primary=eth0 max_bonds=0

activate the 'failover' profile (if switch-to fails try enable):

# netctl switch-to failover

enable wpa_supplicant@wlan0

systemctl enable wpa_supplicant@wlan0

Note that it will look for the file /etc/wpa_supplicant/wpa_supplicant-wlan0.conf (or more generally /etc/wpa_supplicant-interface.conf) to configure the wireless connection. We already created that above - use as is.


At the time of this writing, there is a problem with the systemd dependencies (what else is new...). Create

# cd /etc/systemd/system
# mkdir wpa_supplicant@wlan0.service.d
# cd wpa_supplicant@wlan0.service.d

Create /etc/systemd/system/wpa_supplicant@wlan0.service.d/customdependency.conf


reboot and check:

# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc fq_codel master bond0 state UP mode DEFAULT group default qlen 1000
    link/ether 30:85:a9:3d:c7:5f brd ff:ff:ff:ff:ff:ff
3: wlan0: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP mode DORMANT group default qlen 1000
    link/ether 30:85:a9:3d:c7:5f brd ff:ff:ff:ff:ff:ff
4: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default 
    link/ether 30:85:a9:3d:c7:5f brd ff:ff:ff:ff:ff:ff


# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v3.7.1 (April 27, 2011)

Bonding Mode: fault-tolerance (active-backup)
Primary Slave: eth0 (primary_reselect always)
Currently Active Slave: eth0
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0

Slave Interface: eth0
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 1
Permanent HW addr: 30:85:a9:3d:c7:5f
Slave queue ID: 0

Slave Interface: wlan0
MII Status: up
Speed: Unknown
Duplex: Unknown
Link Failure Count: 0
Permanent HW addr: 6c:88:14:97:04:fc
Slave queue ID: 0

and try unplugging the ethernet cable. It will seemlessly failover to wireless - all connections will remain active!

UPDATE: After putting in the netcfg profiles, I could no longer reach the server from the internal network. Not sure of the cause, but it's extremely inconvenient so I went to a straight ethernet config without netcfg (which also didnt switch reliably - insisting on stay with failover after a reboot, despite the switch-to and disable/enables I did). Probably I did something wrong with netctl, but not bothering at this time to figure it out.


 systemctl disable netctl-ifplugd@eth0
 systemctl enable dhcpcd@eth0

Also, remove /usr/lib/dhcpcd/dhcpcd-hooks/35-localroutes or comment out

route del default eth0

When did I put that in? Why didn't I document it in these pages?


To run a proper IPv6 network, you need a route advertising daemon. This is fairly straightforward to set up. Install

  1. pacman -Sy radvd

then edit /etc/radvd.conf

interface eth0
	AdvSendAdvert on;
	# Note: {Min,Max}RtrAdvInterval cannot be obtained with radvdump
	MinRtrAdvInterval 3;
	MaxRtrAdvInterval 10;
	AdvReachableTime 0;
	AdvRetransTimer 0;
	AdvCurHopLimit 64;
	AdvDefaultLifetime 30;
	AdvHomeAgentFlag off;
	AdvDefaultPreference medium;
	AdvSourceLLAddress on;
	AdvOtherConfigFlag on;
	AdvManagedFlag on;

	prefix fdee:501:ffff:100::/64
		AdvValidLifetime 86400;
		AdvPreferredLifetime 14400;
		AdvOnLink on;
		AdvAutonomous off;
		AdvRouterAddr on;0
	}; # End of prefix definition

}; # End of interface definition

interface wlan0
	AdvSendAdvert on;
	# Note: {Min,Max}RtrAdvInterval cannot be obtained with radvdump
	MinRtrAdvInterval 3;
	MaxRtrAdvInterval 10;
	AdvReachableTime 0;
	AdvRetransTimer 0;
	AdvCurHopLimit 64;
	AdvDefaultLifetime 30;
	AdvHomeAgentFlag off;
	AdvDefaultPreference medium;
	AdvSourceLLAddress on;
	AdvOtherConfigFlag on;
	AdvManagedFlag on;

	prefix fdee:501:ffff:100::/64
		AdvValidLifetime 86400;
		AdvPreferredLifetime 14400;
		AdvOnLink on;
		AdvAutonomous on;
		AdvRouterAddr on;
	}; # End of prefix definition

}; # End of interface definition

I understand that for MacOS X (at least High Sierra onward) you need AdvManagedFlag on and AdvOtherConfigFlag on.

Enable and start the daemon as usual.

DHCPv6, DNS (and DDNS)

I like to run a dynamic network. At the time of writing (Apr 2018), consumer routers only support IPv6 rudimentary. DHCPv6 is mostly lacking. So the first step was to setup a DHCPv6 server for ULA (fdXX:) and dynamic DNS for transient clients (phones, tablets, virtual machines, etc). Laptops can have static DNS, but its important that they have automatic config of all addresses (since they move between networks often).

Much of this section was based on this: [4] Good background material is also located here: [5]

The ISC DHCP server supports both IPv4 and IPv6 - but you have to run 2 instances. Arch configuration is in /etc/dhcpd.conf and /etc/dhcpd6.conf.

In order to do the dynamic dns stuff, you need to create a key.

# dnssec-keygen -a HMAC-SHA512 -b 512 -n HOST home.

This generates a K*.key and K*.private file. Information in those files will be used in the config files for named and dhcp.

BIND9 (named)

Much of this taken from: [6]

Start by generating the rdnc configuration:

# rdnc-confgen

The first part of the generated content goes into /etc/rndc.conf, and the second part into /etc/named.conf.

# rndc.conf
key "rndc-key" {
        algorithm hmac-sha256;

options {
        default-key "rndc-key";
        default-port 953;
## end first part
// Use with the following in named.conf, adjusting the allow list as needed:
key "rndc-key" {
      algorithm hmac-sha256;

controls {
      inet port 953
              allow {; } keys { "rndc-key"; };

Edit /etc/named.conf. The DYNAMIC_DNS_KEY comes from the K*.private or K*.key files.

options {
    directory "/var/named";
    pid-file "/run/named/";

    dnssec-validation auto;

    // Uncomment these to enable IPv6 connections support
    // IPv4 will still work:
    listen-on-v6 { any; };
    // Add this for no IPv4:
    //  listen-on { none; };
    forwarders {;;; };
    allow-recursion {;; fdee:501:ffff:100::/64; };
    allow-transfer { none; };
    allow-update { none; };

    version none;
    hostname none;
    server-id none;

// The following section defines the parameters needed for dynamic dns

// Use with the following in named.conf, adjusting the allow list as needed:
key "rndc-key" {
      algorithm hmac-sha256;

controls {
      inet port 953
              allow {; } keys { "rndc-key"; };
      algorithm hmac-sha256;


// This is the local zone (pre-configured)
zone "localhost" IN {
    type master;
    file "";

// reverse local zone (pre-configured)
zone "" IN {
    type master;
    file "";

// This is our "home." domain
zone "home" IN {
        type master;
        file "";
        allow-update { key DYNAMIC_DNS_KEY; };

// reverse zone (IPv4)
zone "" IN {
        type master;
        file "";
        allow-update { key DYNAMIC_DNS_KEY; };

// reverse localhost zone (IPv6)
zone "" {
    type master;
    file "";

// reverse home. zone (IPv6)
zone "" {
        type master;
        file "";
        allow-update { key DYNAMIC_DNS_KEY; };

zone "" IN {
    type master;
    file "";

zone "" IN {
    type master;
    file "";

zone "." IN {
    type hint;
    file "root.hint";

And add the zone files,


$TTL 7200	; 2 hours
home			IN SOA	tvpc.home. sysadmin.home. (
				2018040103 ; serial
				28800      ; refresh (8 hours)
				1800       ; retry (30 minutes)
				604800     ; expire (1 week)
				86400      ; minimum (1 day)
			NS	tvpc.home.
			MX	10 tvpc.home.
$ORIGIN home.
acer			A
atticsensor		A
			AAAA	fdee:501:ffff:100::21
... (more hosts)


;       Reverse File for network "" - Internal ONLY
@             IN      SOA       tvpc.home. sysadmin.home. (
                                10             ; Serial
                                8H             ; Refresh
                                2H             ; Retry
                                4W             ; Expire
                                1D )           ; Minimum
              IN      NS        tvpc.home.
103           IN      PTR       tvpc.home.
105	IN	PTR	atticsensor.home.	; MANUAL entry for 'atticsensor' reverse delegation
124	IN	PTR	acer.home.		; MANUAL entry for 'acer' reverse delegation
... (more hosts)


$TTL 86400	; 1 day IN SOA	tvpc.home. sysadmin.home. (
				12         ; serial
				28800      ; refresh (8 hours)
				7200       ; retry (2 hours)
				2419200    ; expire (4 weeks)
				86400      ; minimum (1 day)
			NS	tvpc.home.
1			PTR	tvpc.home.
1			PTR	atticsensor.home.
... (more hosts)


Install dhcp (both the v4 and v6 config and service files will be installed).

edit /etc/dhcpd6.conf. The DYNAMIC_DNS_KEY is the one from the K*.private files above.

# IPv6 address valid lifetime
#  (at the end the address is no longer usable by the client)
#  (set to 30 days, the usual IPv6 default)
default-lease-time 2592000;

# IPv6 address preferred lifetime
#  (at the end the address is deprecated, i.e., the client should use
#   other addresses for new connections)
#  (set to 7 days, the  usual IPv6 default)
preferred-lifetime 604800;

# T1, the delay before Renew
#  (default is 1/2 preferred lifetime)
#  (set to 1 hour)
option dhcp-renewal-time 3600;

# T2, the delay before Rebind (if Renews failed)
#  (default is 3/4 preferred lifetime)
#  (set to 2 hours)
option dhcp-rebinding-time 7200;

# Enable RFC 5007 support (same than for DHCPv4)
allow leasequery;

# Global definitions for name server address(es) and domain search list
option domain-name "home";
ddns-update-style interim;
allow client-updates;
ddns-updates on;

option fdee:501:ffff:100::XX;
option dhcp6.domain-search "home","","";

# The delay before information-request refresh
#  (minimum is 10 minutes, maximum one day, default is to not refresh)
#  (set to 6 hours)
option 21600;

# The path of the lease file
dhcpv6-lease-file-name "/var/db/dhcpd6.leases";

log-facility local7;

   algorithm hmac-sha256;

zone home. {

zone {

host tvpc {
        host-identifier option
               dhcp6.client-id XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX;

        fixed-address6 fdee:501:ffff:100::XX;

host atticsensor {
        host-identifier option
               dhcp6.client-id XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX;
        fixed-address6 fdee:501:ffff:100::XX;

... (more hosts)

# The subnet where the server is attached
#  (i.e., the server has an address in this subnet)
subnet6 fdee:501:ffff:100::/64 {
        # addresses available to clients
        #  (additional clients should get NoAddrsAvail)
        range6 fdee:501:ffff:100::11 fdee:501:ffff:100::81;

        # Use the whole /64 prefix for temporary addresses
        #  (i.e., direct application of RFC 4941)
        range6 fdee:501:ffff:100:: temporary;

        # Some /64 prefixes available for Prefix Delegation (RFC 3633)
        prefix6 fdee:501:ffff:100:: fdee:501:ffff:111:: /64;

        allow unknown-clients;

# A second subnet behind a relay agent
subnet6 fdee:501:ffff:101::/64 {
        range6 fdee:501:ffff:101::10 fdee:501:ffff:101::11;

        # Override of the global definitions,
        # works only when a resource (address or prefix) is assigned
        option fdee:501:ffff:101:200:ff:fe00:3f3e;

# A third subnet behind a relay agent chain
subnet6 fdee:501:ffff:102::/64 {
        range6 fdee:501:ffff:102::10 fdee:501:ffff:102::11;

DHCP (v4)

edit /etc/dhcpd.conf:

# option definitions common to all supported networks...
option domain-name "home";
option domain-name-servers 10.0.1.XX;

default-lease-time 600;
max-lease-time 7200;

# Use this to enable / disable dynamic dns updates globally.
ddns-update-style interim;
allow client-updates;
ddns-updates on;

# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.

# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;

   algorithm hmac-sha256;
   secret "B+gBGXQ/EHEEnTTubx5Knr28ozNVB4eIJrI1zKSRO/Y=";

zone home. {

zone {

# A slightly different configuration for an internal subnet.
subnet netmask {
  option domain-name-servers;
  option domain-name "home";
  option routers;
  option broadcast-address;
  default-lease-time 600;
  max-lease-time 7200;

host router {
  hardware ethernet XX:XX:XX:XX:XX:XX;
  fixed-address 10.0.1.XX;
host hpenvy4500 {
  hardware ethernet XX:XX:XX:XX:XX:XX;
  fixed-address 10.0.1.XX;

... (more hosts)

start and enable the dhcpd6 and dhcpd services.

X Setup

Install these packages:


and for this setup, we will use the ati proprietary drivers:

make sure the dkms service is started

# pacman -Sy dkms
# systemctl enable dkms
# systemctl start dkms
# pacman catalyst-dkms catalyst-utils

and config with

# aticonfig --initial

Oddly enough, that was enough to get it working. Since I never installed xf86-video-ati, no need to blacklist radeon.

Test with startx.

UPDATE: the problem with using catalyst is that it doesn't keep up with Arch's aggressive update schedule. So I had to configure the catalyst and xorg113 repositories in /etc/pacman.conf in order to pick up the latest beta release of the driver (that supports the latest 3.8 kernel). I tried the open source driver and I simply cannot get it to work. Uninstall catalyst-dkms and install catalyst, reinstall catalyst-utils.

UPDATE 2: mesa still needs to be installed, otherwise kwin crashes (and you get no window decorations). Also, uninstall catalyst and install catalyst-hook instead, that way the fglrx module will get rebuilt with every kernel upgrade (much like catalyst-dkms).


Install using kde-meta.

# pacman -Sy kde-meta
# pacman -Sy clementine pavucontrol
# pacman -Sy alsa-tools
# pacman -Sy alsatools
# pacman -Sy alsa-utils
# pacman -Sy net-tools
# pacman -Sy bluedevil
# pacman -Sy flashplayer
# pacman -Sy firefox chromium
# pacman -Sy gstreamer0.10-good-plugins gstreamer0.10-bad-plugins gstreamer0.10-ugly-plugins gstreamer0.10-ffmpeg
# pacman -Sy pulseaudio-alsa
# pacman -Sy gstreamer0.10-pulseaudio
# pacman -Sy pulseaudio paprefs
# pacman -Sy gnome-media
# systemctl enable pulseaudio
# pulseaudio --start
# gconftool-2 -t string --set /system/gstreamer/0.10/default/audiosink pulsesink
# gconftool-2 -t string --set /system/gstreamer/0.10/default/audiosrc pulsesrc
# gconftool-2 -t string --set /system/gstreamer/0.10/default/musicaudiosink pulsesink

At some point I need to figure out why I have to use pavcontrol and/or kde system preferences for every user I create in order for hdmi sound to work (same problem I had with spdif on other systems), but honestly 1 user will be enough for these purposes. It could have something to do with audio group, which I didnt add to the users supplemental groups, but it works now so we'll worry about it later.


The holy grail of sound systems. I have trouble though.

What I'm trying to achieve is whole house audio. Everyone says its possible. Every time I think I have it working, the next reboot it stops and I can't get it back.

As I type this, it's working. I'm on beast, streaming to RTP and enabled speakers on tvpc through hdmi. Sound is great. Here are the settings in paprefs:

On beast (or any client ie the one playing music):
   Network Access tab -> check "Make discoverable PulseAudio network sound devices available locally"
   Network Server tab -> nothing checked
   Multicast/RTP tab -> check "Enable Multicast/RTP sender" & "Create separate audio device for Multicast/RTP"
On tvpc (or any "server", ie the one with speakers):
   Network Access tab -> check "Make discoverable PulseAudio network sound devices available locally" & "Make Apple Airplay Devices available locally"
   Network Server tab -> check "Enable network access to local sound devices", "Allow other machines on the LAN to discover local sound devices" and "Don't require authentication"
   Multicast/RTP tab -> check "Enable Multicast/RTP receiver"
   Simultaneous Output tab -> check "Add virtual output..."

On beast, start pavucontrol, and when the stream is playing, select RTP Multicast on the Playback tab. It works (for now).

On tvpc, make sure that the RTP Multicast playback stream selects "...HMDI..." or "Simultaneous Output ...HDMI..."


# pacman -Sy bluedevil
# systemctl enable bluetooth
# systemctl start bluetooth

UPDATE: bluedevil uses the deprecated bluez4 (bluez version 4.x) - install from the AUR bluedevil-bluez5-git. UPDATE: bluedevil in the main repositories is now 5.x+


Install package rsync

Edit /etc/rsyncd.conf, add:

        path = /home/media/Collection
        comment = Music Collection
        hosts allow =
        read only = no
        list = yes
        uid = media
        gid = users

start/enable the rsyncd service.


install ntp, edit /etc/ntp.conf - comment out the servers and replace with



install ddclient

edit /etc/ddclient/ddclient.conf

## EasyDNS (
##,  \
protocol=easydns,            \
login=paulc,                 \
password=<password>          \

Since it contains a password, set the permissions of this file to 0600 (owner/group can stay as root). and also uncomment

use=web,, web-skip='IP Address'

and set


and enable the service

also, install dnsutils so you can check with nslookup, and postfix so that you have sendmail


install squid

Squid access from outside the network is strictly controlled.

edit /etc/squid/squid.conf to allow access:

comment out:

#acl localnet src    # RFC1918 possible internal network
#acl localnet src # RFC1918 possible internal network


acl localnet src # RFC1918 possible internal network


acl localnet src # RFC1918 possible internal network


http_access deny to_localhost

acl localnet src
acl vacationplace src
http_access allow localnet
http_access allow vacationplace

also change the port for security reasons:

http_port <im-not-telling>

(L)AMP (apache, mysql, php)

Install apache and php (mysql was already installed)

# pacman -S apache php php-apache php-pear

and (perhaps later)

# pear install channel://


Edit /etc/httpd/conf/httpd.conf, change


and /etc/httpd/conf/extra/httpd-default.conf

ServerTokens Prod
ServerSignature Off

Create self-signed certificate

# cd /etc/httpd/conf
# openssl genrsa -des3 -out server.key 2048
# openssl req -new -key server.key -out server.csr
# cp server.key
# openssl rsa -in -out server.key
# openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt

UPDATE: RapidSSL certs are cheap (~$9/yr at this time), so I've upgraded. The process is similar. Generate a certificate signing request using the same private key that you generated above:

# openssl req -new -sha256 -key ./server.key -out

Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:New York
Locality Name (eg, city) []:Bronxville
Organization Name (eg, company) [Internet Widgits Pty Ltd]
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []
Email Address []

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Note that if you want to use the cert for all aliases, make the common name * Otherwise only and will be valid.

Go to and login. Paste the generated CSR and follow the trail of emails and approvals.

Uncomment in /etc/httpd/conf/httpd.conf

Include conf/extra/httpd-ssl.conf

and change /etc/httpd/conf/extra/httpd-ssl.conf


When you get approved for the cert, you will get an email with 2 - your cert and an "intermediate certificate". Save your cert as


In /etc/httpd/conf/extra/httpd-ssl.conf, point

SSLCertificateFile    "/etc/httpd/conf/server-rapidssl.pem"
SSLCertificateKeyFile "/etc/httpd/conf/server.key"

UPDATE: SSLCertificateChainFile is obsolete as of apache 2.4.8. Instead, append the intermediate certificate to the server-rapidssl.crt file.

Don't forget to set permissions safely:

# chmod 0750 /etc/httpd/conf/
# chmod 0640 /etc/httpd/conf/server.key

If you want to allow a user to create their own website in their user directory, create ~/public_html and make sure their home directory is executable (default perms on home dirs are 0700; they need to be 0701 to serve ~user pages).


Edit httpd.conf and add

LoadModule php5_module modules/

and at the end

Include conf/extra/php5_module.conf

Uncomment the following line:

MIMEMagicFile conf/magic

Edit conf/extra/php5_module.conf and add index.phtml to the DirectoryIndex directive:

DirectoryIndex index.php index.phtml index.html

Add this line in /etc/httpd/conf/mime.types:

application/x-httpd-php5		php php5

restart httpd

Test PHP: Create the file test.php in your Apache DocumentRoot directory and inside it put:

<?php phpinfo(); ?>

Check http://localhost/test.php


install tomcat7 and edit /etc/topcat7/tomcat-users.xml
install maven
install apache-ant
install [AUR] glassfish-web-v4 and change the port in /opt/glassfish4-web/glassfish/domain1/config/domain.xml (optional) - 
   this is used if you want to develop in a non-production mode on the server.  
   I've worked on my laptop with both a glassfish server and a tomcat server and installed the resulting wars on the server.
   Consequently the service is not running on the server, to start it:
      # systemctl start glassfish-web

Tomcat will be running on port 8080. Tomcat webapps are in /usr/share/tomcat7 and logs are in /var/log/tomcat7.

You must configure /etc/tomcat7/tomcat-users.xml

  <role rolename="tomcat"/>
  <role rolename="manager-gui"/>
  <role rolename="manager-script"/>
  <role rolename="manager-jmx"/>
  <role rolename="manager-status"/>
  <role rolename="admin-gui"/>
  <role rolename="admin-script"/>
  <user username="paulc" password="CHANGEME" roles="tomcat,manager-gui,manager-script,manager-jmx,manager-status,admin-gui,admin-script"/>

The username is used to install war files with the manager app and can be anything.


Start the mysqld daemon and run the setup script:

# mysql_secure_installation

Restart mysqld and enable for bootup.

Enable networking in /etc/mysql/my.cnf:


Enable autocompletion in my.cnf by changing no-auto-rehash to


Now go back to /etc/php/php.ini and uncomment:

and restart httpd


NOTE: After upgrading mysql run this:

# mysql_upgrade -p -u root

load the mediawiki database

copy the wikidb database from maximus:

# mysqldump --databases wikidb -u root -p > ./wikidb

load it on tvpc:

# mysql -u root -p < ./wikidb

create the wikiuser:

# grant all on wikidb.* to wikiuser@localhost identified by '<password>';
# flush privileges;


Install php-gd and uncomment "" in php.ini, same for php-intl (needs icu, already installed) and php-xcache (here add "") and finally install mediawiki, all available from the official repositories.

Create /etc/webapps/mediawiki/httpd-mediawiki.conf from the provided example apache.example.conf in the same directory. Edit it to remove the open_basedir line, which is already in php.ini.

Add the following lines to /etc/httpd/conf/httpd.conf

LoadModule php5_module modules/
Include conf/extra/php5_module.conf
Include /etc/webapps/mediawiki/httpd-mediawiki.conf

Adjust the open_basedir in /etc/php/php.ini to include the webapps directory (allows update.php to be run from the command line):

open_basedir = /srv/http/:/home/:/tmp/:/usr/share/pear/:/usr/share/webapps/

Adjust permissions in /usr/share/webapps/mediawiki/.htaccess, e.g. to

allow from all

Restart httpd

Open the wiki in a browser and do the initial setup to create /usr/share/webapps/mediawiki/LocalSettings.php.

Edit LocalSettings.php to set the $wgLogo = ""; so that there is no logo.

and, because people can't behave themselves, change the permissions so that only I can create users, and only I can edit.

$wgGroupPermissions['*']['createaccount'] = false;
$wgGroupPermissions['*']['edit'] = false;

and, to make almost all the pages private

$wgGroupPermissions['*']['read'] = false;
$wgWhitelistRead = array( "Main Page", "Server Setup", "New tvpc" );

Finally, enable the syntax highlighting extension (which is distributed with the base package, no additional installation):

wfLoadExtension( 'SyntaxHighlight_GeSHi' );

Don't forget to set the group for LocalSettings.php to http, and set the perms to 0640.

Edit /srv/http/index.html to add a link to mediawiki.

Setup monitoring of the mirror

Edit /etc/mdadm.conf:

PROGRAM /usr/local/bin/

and create /usr/local/bin/

 $emailto1 = '';
 $emailto2 = '';
 $emailto3 = '';
 $whoami = '';
 $hostn = ' (tvpc)';
 use Socket;
 use Sys::Syslog;
 $event1 = "Event: $ARGV[0], Array: $ARGV[1], Component: $ARGV[2]";
 openlog 'diskfailmail', 'pid', 'user';
 syslog 'info', "mdadm event $event1";
 $email1 = "To: $emailto1
 From: $whoami
 Subject: $hostn mdadm event
 $email2 = "To: $emailto2
 From: $whoami
 Subject: $hostn mdadm event
 $email3 = "To: $emailto3
 From: $whoami
 Subject: $hostn mdadm event
 `echo '$email1' |/usr/sbin/sendmail -f $whoami -t`;
 `echo '$email2' |/usr/sbin/sendmail -f $whoami -t`;
 `echo '$email3' |/usr/sbin/sendmail -f $whoami -t`;

and chmod its permissions to rwx for root only.

test the email notification:

# mdadm --monitor --test --scan

Then start and enable the mdadm service


Install apcupsd

(Optional) edit /etc/apcupsd/apcupsd.conf

UPSNAME tvpcups

everything else was already setup by default for a usb style ups (the vast majority of ups's these days).

Start and enable the service. Check the status:

# apcaccess status

Should look something like this:

APC      : 001,034,0864
DATE     : 2012-12-01 12:26:43 -0500
VERSION  : 3.14.10 (13 September 2011) unknown
UPSNAME  : tvpcups
CABLE    : USB Cable
UPSMODE  : Stand Alone
STARTTIME: 2012-12-01 12:24:40 -0500
MODEL    : Back-UPS ES 550G
LINEV    : 123.0 Volts
LOADPCT  :   1.0 Percent Load Capacity
BCHARGE  : 100.0 Percent
TIMELEFT : 355.8 Minutes
MBATTCHG : 5 Percent
MINTIMEL : 3 Minutes
MAXTIME  : 0 Seconds
SENSE    : Medium
LOTRANS  : 092.0 Volts
HITRANS  : 139.0 Volts
ALARMDEL : 30 seconds
BATTV    : 13.6 Volts
LASTXFER : No transfers since turnon
TONBATT  : 0 seconds
CUMONBATT: 0 seconds
STATFLAG : 0x07000008 Status Flag
SERIALNO : 4B1241P34296
BATTDATE : 2012-10-12
NOMINV   : 120 Volts
NOMBATTV :  12.0 Volts
END APC  : 2012-12-01 12:27:31 -0500


To add a new mailbox:

  1. Navigate to and login (the admin account is
  2. if the domain doesn't exist, add it
  3. add the mailbox in the domain
  4. if procmail filtering is desired, add the account to /etc/postfix/transport (spam will automatically be moved to a folder "Junk" if the client creates one)
  5. Edit /etc/fetchmailrc to include the new mailbox

To setup a Thunderbird client:

Use as an IMAP server, Port: 993, Protocol: SSL, Authentication: Normal Password
Use as the outgoing smtp server, Port: 587, Protocol: STARTTLS, Authentication: Normal Password.
Username is your full email address, e.g.

To change your password, logon to webmail ( or and change it there.

The rest of this section tells how it was setup.


(note that you already installed postfix here New tvpc#ddclient)

Edit /etc/postfix/

myhostname =
mydomain =
myorigin = $mydomain
mydestination = localhost
mynetworks_style = subnet
relayhost = []
home_mailbox = Maildir/

The more proper method for smtp is to use a port that simply enforces TLS without any wrapping. The system service for this is "submission" which is standard and uses port 587. Port 465 is for smtps, which is considered legacy, however, my work does something to prevent 587 from working, so we also enable smtps.

For smtps, you need to add these back into /etc/services:

smtps       465/tcp
smtps       465/udp

Uncomment these in /etc/postfix/

smtp     inet  n       -       n       -       -       smtpd
submission     inet  n       -       n       -       -       smtpd
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,permit_mynetworks,check_relay_domains,reject
  -o syslog_name=postfix/submission
smtps     inet  n       -       n       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject

Because our ISP blocks outgoing and incoming port 25, we cannot be a true mail exchanger. Instead we need to use a relay host. This is configured in

relayhost = []:submission
smtp_sasl_auth_enable = yes
smtp_tls_security_level = encrypt
smtp_sasl_tls_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd

and then we need to create the hash /etc/postfix/sasl_passwd and run postmap on it:


save that and:

# chmod 0400 /etc/postfix/sasl_passwd
# postmap /etc/postfix/sasl_passwd

Also append to /etc/postfix/

relay_domains = *
virtual_alias_maps = proxy:mysql:/etc/postfix/
virtual_mailbox_domains = proxy:mysql:/etc/postfix/
virtual_mailbox_maps = proxy:mysql:/etc/postfix/
virtual_mailbox_base = /home/vmail
#virtual_mailbox_limit = 512000000 for my purposes, quotas are just a pain
virtual_mailbox_limit = 0
virtual_minimum_uid = 5000
virtual_transport = virtual
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
local_transport = virtual
local_recipient_maps = $virtual_mailbox_maps
transport_maps = hash:/etc/postfix/transport

smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = /var/run/dovecot/auth-client
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
smtpd_sasl_security_options = noanonymous
smtpd_sasl_tls_security_options = $smtpd_sasl_security_options
smtpd_tls_auth_only = yes
smtpd_tls_cert_file = /etc/ssl/private/server.crt
smtpd_tls_key_file = /etc/ssl/private/server.key
smtpd_sasl_local_domain = $mydomain
broken_sasl_auth_clients = yes
smtpd_tls_loglevel = 1

UPDATE: use the rapidssl cert from apache:

smtpd_tls_cert_file = /etc/http/conf/server-rapidssl.pem
smtpd_tls_key_file = /etc/http/conf/server.key
# again, for me, quotas are just a pain
message_size_limit = 0

Edit /etc/postfix/ as new and add:

user = postfix_user
password = <passwd>
hosts = localhost
dbname = postfix_db
query = SELECT goto FROM alias WHERE address='%s' AND active = true

Edit /etc/postfix/ as new and add:

user = postfix_user
password = <passwd>
hosts = localhost
dbname = postfix_db
query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = false AND active = true

Edit /etc/postfix/ as new and add:

user = postfix_user
password = <passwd>
hosts = localhost
dbname = postfix_db
query = SELECT quota FROM mailbox WHERE username='%s'

Edit /etc/postfix/ as new and add:

user = postfix_user
password = <passwd>
hosts = localhost
dbname = postfix_db
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = true

Also, these files need to be protected because they have passwords in them (so not everyone should be allowed to even read them. They must however, be owned by root (postfix requirement, although only seems to result in a warning). So change group ownership to "postfix" and set the permissions to 0640:

# cd /etc/postfix
# chgrp postfix virtual_*
# chmod 0640 virtual_*

Run postmap on transport to generate its db:

postmap /etc/postfix/transport

We still need the SSL cert and private key:

cd /etc/ssl/certs
openssl req -new -x509 -newkey rsa:1024 -days 365 -keyout server.key -out server.crt
openssl rsa -in server.key -out server.key
chown nobody:nobody server.key server.crt
chmod 400 server.key
chmod 444 server.crt
mv server.key /etc/ssl/private/
mv server.crt /etc/ssl/private/

Enable and start the postfix daemon


Install postfixadmin

Change dir to /etc/webapps/postfixadmin, create httpd-postfixadmin.conf from the apache.conf example provided in that directory.

Edit /etc/httpd/conf/httpd.conf and add

Include /etc/webapps/postfixadmin/httpd-postfixadmin.conf

Edit /etc/webapps/postfixAdmin/

$CONF['configured'] = true;
// correspond to dovecot maildir path /home/vmail/%d/%u 
$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'YES';

$CONF['database_type'] = 'mysql';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'postfix_user';
$CONF['database_password'] = '**changeme**';
$CONF['database_name'] = 'postfix_db';

$CONF['encrypt'] = 'dovecot:SHA512-CRYPT';
$CONF['password_validation'] = array(
#    '/regular expression/' => '$PALANG key (optional: + parameter)',
    '/.{8}/'                => 'password_too_short 8',      # minimum length 8 characters
    '/([a-zA-Z].*){3}/'     => 'password_no_characters 3',  # must contain at least 3 characters
    '/([0-9].*){1}/'        => 'password_no_digits 1',      # must contain at least 1 digits

Replace **changeme** with the real password.

Navigate to and follow the instructions.

We want to secure this directory with an admin password:

# mkdir /usr/share/webapps/secure
# htpasswd -c /usr/share/webapps/secure/.htpasswd paulc
New password:
Re-type new password:
# chown http.http /usr/share/webapps/secure/.htpasswd
# chmod 0640 /usr/share/webapps/secure/.htpasswd

paulc is the admin account in this example.

Edit /usr/share/webapps/postfixadmin/.htaccess and put these contents:

AuthType Basic
AuthName "Restricted Access"
AuthUserFile /usr/share/webapps/secure/.htpasswd
Require user paulc


install dovecot

For security reasons, a new user should be created to store the mails:

groupadd -g 5000 vmail
useradd -u 5000 -g vmail -s /sbin/nologin -d /home/vmail -m vmail

A gid and uid of 5000 is used in both cases so that we do not run into conflicts with regular users. All your mail will then be stored in /home/vmail.

You will need to create an empty database and corresponding user. We will be using PostfixAdmin's tables to fill the database later on. In this article, postfix_user will have read/write access to postfix_db using hunter2 for a password. You are expected to create your database and user yourself as shown in the following code. Make sure to assign proper permissions.

# mysql -u root -p

CREATE SCHEMA `postfix_db` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
CREATE USER 'postfix_user'@'localhost' IDENTIFIED BY 'hunter2';
GRANT ALL ON `postfix_db`.* TO `postfix_user`@`localhost`;

cp /etc/dovecot/dovecot.conf.sample /etc/dovecot/dovecot.conf

In /etc/dovecot/dovecot.conf uncomment/edit:

protocols = imap pop3

Create /etc/dovecot/conf.d/10-mysql-vmail.conf:

auth_mechanisms = plain login
passdb {
    driver = sql
    args = /etc/dovecot/dovecot-sql.conf
userdb sql {
    driver = sql
    args = /etc/dovecot/dovecot-sql.conf

service auth {
    unix_listener auth-client {
        group = postfix
        mode = 0660
        user = postfix
    user = root

mail_home = /home/vmail/%d/%u
mail_location = maildir:~

ssl_cert = </etc/httpd/conf/server-rapidssl.crt
ssl_key = </etc/httpd/conf/server.key

Create /etc/dovecot/dovecot-sql.conf with these contents:

driver = mysql
connect = host=localhost dbname=postfix_db user=postfix_user password=hunter2
# The new name for MD5 is MD5-CRYPT so you might need to change this depending on version
default_pass_scheme = SHA512-CRYPT
# Get the mailbox
user_query = SELECT '/home/vmail/%d/%u' as home, 'maildir:/home/vmail/%d/%u' as mail, 5000 AS uid, 5000 AS gid, concat('dirsize:storage=',  quota) AS quota FROM mailbox WHERE username = '%u' AND active = '1'
# Get the password
password_query = SELECT username as user, password, '/home/vmail/%d/%u' as userdb_home, 'maildir:/home/vmail/%d/%u' as userdb_mail, 5000 as  userdb_uid, 5000 as userdb_gid FROM mailbox WHERE username = '%u' AND active = '1'
# If using client certificates for authentication, comment the above and uncomment the following
#password_query = SELECT null AS password, ‘%u’ AS user

public mailboxes:

To setup public mailboxes, you need to have namespaces. One private namespace must be configured at least. Create /etc/dovecot/conf.d/20-public-mailboxes.conf:

namespace {
        type = private
        separator = /
        prefix =
        #location defaults to mail_location
        inbox = yes

namespace {
        type = public
        separator = /
        prefix = My Company/
        location = maildir:/home/vmail/public
        subscriptions = no

Now create /home/vmail/public, giving ownership to vmail:vmail. Under this directory is where you put your public mailboxes. For example, to create a public mailbox notices, you would create /home/vmail/public/.notices/ -> under here would be cur, tmp, new.

The user subscribes to My Company -> notices

Start and enable dovecot


Install fetchmail

Optional: install tk to use fetchmailconf (tk can be useful elsewhere)

However, I configured manually.

create /etc/fetchmailrc

# This file must be chmod 0600, owner fetchmail 
# Daemon configuration
set daemon        300           # Pool every 5 minutes
set syslog                      # log through syslog facility
set postmaster  paulc
set bouncemail

# Hosts to poll

# Defaults ===============================================================
# Set antispam to -1, since it is far safer to use that together with
# no bouncemail
timeout 300
antispam -1
batchlimit 100

poll protocol POP3 user "paulctst1" there with password "<password>" is "" here options fetchall

and as it says in the comment,

# chown fetchmail /etc/fetchmailrc
# chmod 0600 /etc/fetchmail

Start and enable the fetchmail service.


NOTE: procmail and spamassassin are not required for a working virtual mail setup, so the next 2 sections show how to modify the setup to add these features.

Only paulc (my mail) requires server-side filtering (because no one I would host mail for would know what that is), but who knows, maybe someday others will want it.

Add procmail as a valid transport in /etc/postfix/

procmail unix - n n - - pipe flags=RO user=vmail argv=/usr/bin/procmail -t -m USER=${user} NEXTHOP=${nexthop} EXTENSION=${extension} /etc/postfix/procmailrc.common

Create the script /etc/postfix/procmail.common:

#each user will set his own log file
WS="    "

# All marked spam is forwarded to the spam account
#* ^X-Spam-Status:.*Yes

# Put marked spam in users 'Junk' folder
* ^X-Spam-Status:.*Yes

make this file owned by root:vmail, and set the permissions to 0770 (or 0550 or 0750).

Edit /etc/postfix/transport and add procmail

And run

# postmap /etc/postfix/transport

Create the procmail switch file as /home/vmail/

When moving to a folder in a rule, make sure to include the '.' and end with the '/':

* ^(Subject).*Test

is a rule that will move all mail with a subject ending in "Test" into a subfolder "test".


Install spamassassin

edit /etc/mail/spamassassin/

rewrite_header Subject [SPAM]

and add whitelist_from directives at the end of the file (as from maximus), e.g.:

whitelist_from  *

Create Spamassassin user/group and folder.

groupadd -g 5001 spamd
useradd -u 5001 -g spamd -s /sbin/nologin -d /var/lib/spamassassin -m spamd
chown spamd:spamd /var/lib/spamassassin

update the patterns:

# /usr/bin/vendor_perl/sa-update

Change /etc/conf.d/spamd to:

SPAMD_OPTS="--max-children 25 --username spamd --helper-home-dir -D -x --virtual-config-dir=${SAHOME} -s ${SAHOME}spamd.log --pidfile /var/run/"

Modify /etc/postfix/ to pass all mail through spamassasin:

smtp      inet  n       -       n       -       -       smtpd -o content_filter=spamassassin
spamassassin    unix    -       n       n       -       -       pipe user=spamd argv=/usr/bin/vendor_perl/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}

(add the part in italics)

Enable and start the spamassassin service. (and restart the postfix service)

Add the script /etc/cron.daily/update-spamfilters:

 $emailto1 = '';
 $emailto2 = '';
 $emailto3 = '';
 $whoami = '';
 $hostn = ' (tvpc)';
 use Socket;
 use Sys::Syslog;
 openlog 'spamfilterupdate', 'pid', 'user';
 $date = `date`;
 chomp $date;
 syslog 'info', "spamfilter update for $date";
 $version = `/usr/bin/vendor_perl/sa-update -V`;
 @v = split / /, $version;
 $version = $v[2];
 chomp $version;
 $email1 = "To: $emailto3
 From: $whoami
 Subject: $hostn spamfilters update
 An error occurred for $date. You are still running version $version.
 $ret = `/usr/bin/vendor_perl/sa-update`;
 if ($ret == 0) {
    syslog 'info', "A spamfilter update was available for $date, and was downloaded and installed successfully. You are now running $version.\n";
 elsif ($ret == 1) {
    syslog 'info', "No spamfilter update was available for $date. You are still running $version.\n";
 else {
    syslog 'info', "An error occurred downloading spamfilters for $date. You are still running $version.\n";
    `echo '$email1' |/usr/sbin/sendmail -f $whoami -t`;

Set the permissions to 0744. If you haven't yet, make sure the cronie service is enabled and started. (NOTE that cronie run-parts ignores scripts with '.'s in them by default, so don't add a '.pl' extension.)

RoundCube Webmail

Install roundcubemail, libmcrypt, php-mcrypt, php-imap

cd /etc/webapps/roundcubemail and copy the example apache.conf to httpd-roundcubemail.conf

Edit /etc/webapps/roundcubemail/.htaccess and change the first line to

allow from all

Edit /etc/httpd/conf/httpd.conf and add at the end

Include /etc/webapps/roundcubemail/httpd-roundcubemail.conf

change to /usr/share/webapps/roundcubemail and rename the xintstallerx directory, and change the perms

# cd /usr/share/webapps/roundcubemail
# mv xinstallerx installer
# chmod 0755 installer

create the roundcubemail database and roundcube user

# mysql -u root -p
mysql> create database roundcubemail;
mysql> grant all on roundcubemail.* to roundcube@localhost identified by '<password>';
mysql> flush privileges;

Initialize the database

# mysql -u roundcube -p < SQL/mysql.initial.sql

Navigate over to

  1. set the date.timezone = America/New_York in php.ini
  2. enable extensions,,, and in php.ini
  3. restart httpd
  4. chown http.http /usr/share/webapps/roundcube/temp/
  5. save and in /etc/webapps/roundcubemail/config
  6. set the permissions to 0640 and the group to http for and (again, they contain passwords)

After completing the installation and the final tests please remove the whole installer folder from the document root of the webserver or make sure that enable_installer option in config/ is disabled.

Enable the 'password', 'emoticons', and 'help' plugins: Edit /usr/share/webapps/roundcubemail/config/

// List of active plugins (in plugins/ directory)
$config['plugins'] = array('password', 'emoticons', 'help');

goto /usr/share/webapps/roundcubemail/plugins/password and copy to Edit that file and change:

$config['password_db_dsn'] = 'mysql://postfix_user:<password>@localhost/postfix_db';

where <password> is replaced with the postfix_user password (do not include anglebrackets).


$config['password_algorithm'] = 'dovecot';
$config['password_dovecotpw'] = "/usr/bin/doveadm pw";
$config['password_dovecotpw_method'] = "SHA512-CRYPT";

$config['password_query'] = 'UPDATE mailbox SET password=%P WHERE username=%u LIMIT 1';

(the %P tells the password plugin to encrypt the password with CRYPT_MD5 which is the same as md5crypt which is not a simple MD5 digest).

once again we have a password stored in this file, so make sure to set the group to http and perms to (something like) 0640.

# chgrp http
# chmod 0640

goto /usr/share/webapps/roundcubemail/plugins/help and copy to Edit that file and change:

$rcmail_config['help_source'] = '';

Migration from "maximus"

This will be the general procedure:

  1. create the account on tvpc
  2. comment out the entry in fetchmailrc on maximus
  3. convert the mbox format to maildir format (as root):
# cd /home/Mail/paulc2
# -s /var/spool/mail/paulc2 -d /home/Mail/paulc2/.maildir/   # convert /var/spool/mail/paulc2
# -R -s /home/Mail/paulc2/mail/ -d /home/Mail/paulc2/.maildir/   # convert the folders
# chown -R paulc2.paulc2 .maildir/
  1. gzip up (the .maildir directory)-> move to tvpc
  2. unzip on tvpc into /home/vmail/
  3. move and convert the .procmailrc from maximus:/home/Mail/paulc2 to tvpc:/home/vmail/
  4. verify imap access to <account> on tvpc
  5. copy login credentials to tvpc fetchmailrc
  6. restart fetchmail on tvpc

Lirc (iMon RM100, a.k.a Antec Veris Multi-Station Basic IR Receiver)

First of all, the remote that comes with this thing is crap, and ultimately we want to use the Harmony remote anyway, so configure that one. It will tell you to set it up as an MCE remote. Good luck doing that because devinput just pretty much does what it wants. Loading the rc_imon_mce module without the rc_imon_pad module just hangs the computer. You can load it in addition though.

After much trial and error, I've configured the lirc to just use the kernel modules that are standard in the kernel. This means setting it up as a devinput device.

I installed lirc and lirc-utils, although after reading through more of the documentation I think only lirc-utils are necessary.

First, the kernel pretty much correctly identifies the iMon and loads the correct modules. Trying to load anything else brought me nothing but heartache, including no change, no response, and in one case crashing the machine. So the next step was to configure Lirc to use the imon device created by the kernel:

Identify the usb device (we only have 1 device, but just for completeness):

# lsusb
Bus 009 Device 002: ID 15c2:0043 SoundGraph Inc.

Note the 15c2:0043. Now look for the usb device file:

# ls -al /dev/input/by-id/
total 0
drwxr-xr-x 2 root root 100 Feb 23 14:52 .
drwxr-xr-x 4 root root 360 Feb 24 22:13 ..
lrwxrwxrwx 1 root root   9 Feb 23 09:21 usb-15c2_0043-event-if00 -> ../event4
lrwxrwxrwx 1 root root   9 Feb 23 09:21 usb-15c2_0043-event-mouse -> ../event3
lrwxrwxrwx 1 root root   9 Feb 23 09:21 usb-15c2_0043-mouse -> ../mouse0

usb-15c2_0043-event-if00 is what we are looking for - the target of the link can and will change from boot to boot. I tried the online instructions for the mouse device, but there was no measurable effect that I could see.

Edit /etc/conf.d/lirc.conf

# Parameters for lirc daemon


As of Feb 24, 2013 there is a bug in the unit file for lirc, so you have to edit it to use these parameters.

# cd /etc/systemd/system/
# vi lirc.service

[Service] section should look something like this:

ExecStartPre=/usr/bin/ln -sf /run/lirc/lircd /dev/lircd
ExecStart=/usr/sbin/lircd --pidfile=/run/lirc/  --device=${LIRC_DEVICE} --driver=${LIRC_DRIVER}

Don't forget to reload the daemon:

# systemctl --system daemon-reload

Now we need to add the lircd.conf file in /etc/lirc

# wget;a=blob_plain;f=remotes/devinput/lircd.conf.devinput;hb=HEAD
# cp lircd.conf.devinput lircd.conf

Now we need to edit this file for our purposes. Comment out:

##          KEY_KP0                  0x0052
##          KEY_KP1                  0x004F
##          KEY_KP2                  0x0050
##          KEY_KP3                  0x0051
##          KEY_KP4                  0x004B
##          KEY_KP5                  0x004C
##          KEY_KP6                  0x004D
##          KEY_KP7                  0x0047
##          KEY_KP8                  0x0048
##          KEY_KP9                  0x0049

and add:

##          KEY_NUMERIC_0            0x0200
##          KEY_NUMERIC_1            0x0201
##          KEY_NUMERIC_2            0x0202
##          KEY_NUMERIC_3            0x0203
##          KEY_NUMERIC_4            0x0204
##          KEY_NUMERIC_5            0x0205
##          KEY_NUMERIC_6            0x0206
##          KEY_NUMERIC_7            0x0207
##          KEY_NUMERIC_8            0x0208
##          KEY_NUMERIC_9            0x0209
          KEY_KP0            0x0200
          KEY_KP1            0x0201
          KEY_KP2            0x0202
          KEY_KP3            0x0203
          KEY_KP4            0x0204
          KEY_KP5            0x0205
          KEY_KP6            0x0206
          KEY_KP7            0x0207
          KEY_KP8            0x0208
          KEY_KP9            0x0209

The "KEY_NUMERIC_" ones are there for completeness - by default those are what are returned. In the next step however they are not useful.

Save the file.

At this point I tried to create /etc/lirc/lircrc and/or /home/media/.lircrc and they had no effect. I could get irexec to work on the command line, but I then resorted to configuring keys in the KDE Input Devices gui of System Settings.

1. Add qdbus commands for clementine to play, pause, stop, next, prev.
2. Add keyboard commands equating Kp0 to a keyboard 0, Kp1 to 1, Kp2 to 2, ... etc

Don't forget to start the lircd daemon and enable the service for reboot:

# systemctl start lirc
# systemcrl enable lirc.service


This only loosely belongs here (I do want to print from the server) but I keep forgetting the details so it's best to put them somewhere.

I have an old linksys psu4 printserver connected to an old HP LaserJet 1200 - both extremely adequate for the job. As time goes by they get less easy to support because I guess the computing world is passing them by, but they are simple and all I need, so I don't really want to replace them.

The printserver is configured with a static IP (the only one on my network?) - - and the most reliable way to configure it is as an ipp or http printer. The devices would be:



For all versions of Windows up to Windows 8, the LaserJet 1200 driver is available.

For Windows 8, LaserJet 1200 is not supported by default. You have 2 options. Go to the as-always-obtuse HP website and after obtaining your PhD in unhelpful you can download the HP Universal PCL6 driver, which probably wouldn't work anyway since I'm pretty sure the 1200 is a PCL5 device - install it and follow the instructions, which will leave you with an unzipped directory and the new driver but will ultimately walk you through adding the printer in the same way that failed and caused you to seek out the printer driver from their website in the first place. Or (after more spelunking through their website) you might stumble across this tidbit - add the printer as you were doing before but when you get to the part where you can't find the printer, click the "Windows Update" button. Your computer will probably appear to hang, but just before you give up and decide to hold down the power button, it will awaken and a whole bunch of old printers will be available for use, including the HP 1200 (and the Photosmart 7760 and a bunch of others).

For Linux it's always available and given that they still support LaserJets from the 1980s I don't see it going away anytime soon.

For the Mac, presently the LaserJet 1200 is still supported as of Lion, but as Apple is trying their best to be as evil as Microsoft, it's only a matter of time before it disappears. I suspect that following the instructions for the HP Photosmart 7760 on Mac OSX will give you the 1200 as well (feel free to follow the instructions as described above at the HP website, which will in all likelihood result in similar fruitless results).


Install package nfs-utils

create /etc/exports


NOTE that "insecure" is necessary for the avahi service definition - without it you must specify an avahi port below 1024.

start and enable nfs-server

if you add or change shares, reload with

# exportfs -rav

Start & enable rpcbind and nfs-server


Install package samba

Copy /etc/samba/smb.conf.default /etc/samba/smb.conf

Change the following:

Under the section "[global]"

workgroup = WORKGROUP
server string = PCifarelli Samba Server
hosts allow = 192.168.4. 127.
load printers = yes
passdb backend = tdbsam
interfaces =
domain master = yes
preferred master = yes
wins support = yes
wins proxy = yes


under the section "[printers]"

browseable = yes
guest ok = yes

uncomment the section "[tmp]"

Add the section:

   path = /home/media/Collection
   public = yes
   only guest = yes
   writable = yes
   printable = no

Enable and start the services:

systemctl enable smbd
systemctl enable nmbd
systemctl start smbd
systemctl start nmbd

add user:

(Note: this adds a user if the user has a normal unix/linux account)

pdbedit -a -u paulc
pdbedit -a -u media

Avahi (Zeroconf)

By this point avahi is installed. Also install nss-mdns and append mdns4_minimal to the hosts line in /etc/nsswitch.conf.

Add the nfs share for the music collection - /etc/avahi/services/nfs_MusicCollection.service

 <?xml version="1.0" standalone='no'?>
 <!DOCTYPE service-group SYSTEM "avahi-service.dtd">
   <name replace-wildcards="yes">NFS Music Share on %h</name>

and the printer - /etc/avahi/services/hp1200.service

 <?xml version="1.0" standalone='no'?>
 <!DOCTYPE service-group SYSTEM "avahi-service.dtd">
     <txt-record>note=HP Laserjet 1200</txt-record>
     <txt-record>product=virtual Printer</txt-record>

and the Samba Shares -


 <?xml version="1.0" standalone='no'?>
 <!DOCTYPE service-group SYSTEM "avahi-service.dtd">
    <name replace-wildcards="yes">Samba Shares on %h</name>

and /etc/avahi/services/smb_for_lion.service

 <?xml version="1.0" standalone='no'?>
 <!DOCTYPE service-group SYSTEM "avahi-service.dtd">
    <name replace-wildcards="yes">Samba Shares (for Lion) on %h</name>

For convenience, add the status hosts to /etc/avahi/hosts router.local beast.local tvpc.local paulcomp.local

enable and start avahi-daemon.

Firewall (iptables script)

I had hopes that I wouldn't need a firewall, except for the one in my router, but it turns out there are people trying to hack my server even though it's only marginally public, so I at least need a basic way of blocking malicious IPs.

The script's simple but a bit long, listed below. You also need a systemd service file:


Description=the firewall

ExecStart=-/root/ start
ExecStop=-/root/ stop
ExecReload=-/root/ reload


Don't forget to reload and enable,start the service:

# systemctl --system daemon-reload
# systemctl enable firewall
# systemctl start firewall

Move this script? Here's the script (/root/

 # - IPTables Firewall script
 # Author: Paul Cifarelli, originally adopted from Oskar Andreasson <blueflux at koffein dot net>
 # (c) of, use at your own risk, do whatever you please with
 # it as long as you don't distribute it without due credits to
 # add some ports to open here:
 @tcp_ports_to_open = (
 # block some assholes here:
 @assholes_to_block = (
 use Cwd 'abs_path';
 $this_script = abs_path($0);
 use Sys::Syslog;
 openlog '', 'pid', 'user';
 $str = "firewall script: " . "ARGVc=" . $#ARGV;
 for ($i=0; $i<=$#ARGV; $i++)
    $str .= " ARGV" . "$i" . "=" . $ARGV[$i];
 syslog 'info', $str;
 # your LAN's IP range and localhost IP. /24 means to only use the first 24
 # bits of the 32 bit IP adress. the same as netmask
 if ($#ARGV >= 0 && ($ARGV[0] eq "-r" or $ARGV[0] eq "--reload" or $ARGV[0] eq "reload" or $ARGV[0] eq "restart"))
    `$this_script stop`;
    `$this_script start`;
 if ($#ARGV >= 0 && ($ARGV[0] eq "-x" or $ARGV[0] eq "--clear" or $ARGV[0] eq "clear" or $ARGV[0] eq "stop"))
    `$IPTABLES -F`;
    `$IPTABLES -t nat -F OUTPUT`;
    `$IPTABLES -X check_asshole`;
    `$IPTABLES -X assholes`;
    `$IPTABLES -X welcome`;
    `$IPTABLES -X check_syn`;
    `$IPTABLES -X udpincoming_packets`;
    `$IPTABLES -X tcp_packets`;
    `$IPTABLES -X icmp_packets`;
 if ($#ARGV >= 0 && ($ARGV[0] ne "enable" and $ARGV[0] ne "start" and $ARGV[0]) )
    print "Usage:\nfirewall [-x|--clear|clear]\n   -x|--clear|clear\tclear rules\n\n";
 # Load all required IPTables modules
 # Adds some iptables targets like LOG, REJECT and MASQUARADE.
 `/sbin/modprobe ipt_LOG`;
 `/sbin/modprobe ipt_REJECT`;
 `/sbin/modprobe ipt_MASQUERADE`;
 `/sbin/modprobe ipt_REDIRECT`;
 # Support for owner matching
 `/sbin/modprobe ipt_owner`;
 # multiport
 `/sbin/modprobe ipt_multiport`;
 # Support for connection tracking of FTP and IRC.
 `/sbin/modprobe ip_conntrack_ftp`;
 `/sbin/modprobe ip_nat_ftp`;
 `/sbin/modprobe ip_conntrack_irc`;
 #CRITICAL:  Enable IP forwarding since it is disabled by default.
 `echo "1" > /proc/sys/net/ipv4/ip_forward`;
 # Dynamic IP users:
 #   If you get your IP address dynamically from SLIP, PPP, or DHCP, enable this
 #       option.  This enables dynamic-ip address hacking in IP MASQ, making the connection
 #       with Diald and similar programs much easier.
 `echo "1" > /proc/sys/net/ipv4/ip_dynaddr`;
 # set default policies for the INPUT, FORWARD and OUTPUT chains
 # Create separate chains for ICMP, TCP and UDP to traverse
 `$IPTABLES -N icmp_packets`;
 `$IPTABLES -N tcp_packets`;
 `$IPTABLES -N udpincoming_packets`;
 # ICMP rules
 `$IPTABLES -A icmp_packets -p ICMP -s 0/0 --icmp-type 0 -j ACCEPT`;
 `$IPTABLES -A icmp_packets -p ICMP -s 0/0 --icmp-type 3 -j ACCEPT`;
 `$IPTABLES -A icmp_packets -p ICMP -s 0/0 --icmp-type 5 -j ACCEPT`;
 `$IPTABLES -A icmp_packets -p ICMP -s 0/0 --icmp-type 11 -j ACCEPT`;
 # TCP rules
 # the allowed chain for TCP connections
 # The "welcome" chain is a final check for non-syn TCP packets.
 # We allow all packets that are part of an established connection or related to a connection
 # the rest we drop
 `$IPTABLES -N welcome`;
 `$IPTABLES -A welcome -p TCP -m state --state ESTABLISHED,RELATED -j ACCEPT`;
 `$IPTABLES -A welcome -m limit --limit 3/minute --limit-burst 3 -j LOG --log-prefix "IPT packet died on welcome: "`;
 `$IPTABLES -A welcome -p TCP -j DROP`;
 `$IPTABLES -N check_asshole`;
 `$IPTABLES -N assholes`;
 # The "check_syn" chain is where we test for acceptable incoming connection requsts
 `$IPTABLES -N check_syn`;
 while ($port = pop @tcp_ports_to_open)
    `$IPTABLES -A check_syn -p TCP -s 0/0 --dport $port -j check_asshole`;
 # need this to make ftp work - accept all syns received for a "related" port
 # conntrack_ftp intercepts the ftp PORT command and adds the port to the connection track list so that the outbound
 # (passive) and inbound (active) data connection can be made
 `$IPTABLES -A check_syn -p TCP -m state --state RELATED -j check_asshole`;
 `$IPTABLES -A check_syn -m limit --limit 3/minute --limit-burst 3 -j LOG --log-prefix "IPT check_syn packet died: "`;
 `$IPTABLES -A check_syn -p TCP -s 0/0 -j DROP`;
 # dont let these morons in ever: (last updated 7/3/2013)
 while ($ass = pop @assholes_to_block)
   `$IPTABLES -A check_asshole -p TCP -s $ass/32 -j assholes`;
 `$IPTABLES -A check_asshole -p TCP -j ACCEPT`; # not an asshole
 # the "assholes" chain is where we put those who are banned
 `$IPTABLES -A assholes -m limit --limit 3/minute --limit-burst 3 -j LOG --log-prefix "asshole denied: "`;
 `$IPTABLES -A assholes -p TCP -s 0/0 -j DROP`;
 #here we route the packets to the appropriate TCP chains:
 `$IPTABLES -A tcp_packets -p TCP -s 0/0 --syn -j check_syn`;
 `$IPTABLES -A tcp_packets -p TCP -s 0/0 -j welcome`;
 # UDP ports
 # accept all UDP
 `$IPTABLES -A udpincoming_packets -p UDP -j ACCEPT`;
 # INPUT chain
 # establish the basic INPUT chain and filter the packets onto the correct
 # chains.
 # route the packets to the appropriate chains
 `$IPTABLES -A INPUT -p ICMP -i $LAN_IFACE -j icmp_packets`;
 `$IPTABLES -A INPUT -p TCP -i $LAN_IFACE -j tcp_packets`;
 `$IPTABLES -A INPUT -p UDP -i $LAN_IFACE -j udpincoming_packets`;
 #Allow all packets coming from the lan iterface and destined for our broadcast address or lan address.
 #also allow anything destined for the localhost ip
 `$IPTABLES -A INPUT -m limit --limit 3/minute --limit-burst 3 -j LOG --log-prefix "IPT INPUT packet died: "`;
 # OUTPUT chain
 # establish the basic OUTPUT chain and filter them onto the correct chain
 # allow everything that comes from localhost, any of our lan addresses
 `$IPTABLES -A OUTPUT -m limit --limit 3/minute --limit-burst 3 -j LOG --log-prefix "IPT OUTPUT packet died: "`;


mkdir ~paulc/builds/dropbox

download dropbox.tar.gz from the AUR into dropbox


makepkg -s

su and install the pkg file

# pacman -U <packagefile>

next do dropbox-kde-systray-icons with same procedure next do dropbox-cli, same procedure

become root, run the daemon (yes, the daemon, not the cli) at the command line:


you'll get a message saying the computer is not linked to any account, with a url to visit. Cut and paste that url into a browser and type in your password; the daemon will then report that you are successfully linked.

The Dropbox is located at /root/Dropbox (since you are running as root)

Create /etc/systemd/system/dropbox.service:

Description=Dropbox (cloud service)

ExecStart=-/usr/bin/dropbox start
ExecStop=-/usr/bin/dropbox stop
ExecReload=-/usr/bin/dropbox stop;/usr/bin/dropbox start


reload systemd:

# systemctl daemon-reload

enable dropbox:

# systemctl start dropbox
# systemctl enable dropbox


Install mpd.

As user "media", create /home/media/.config/mpd/mpd.conf:

pid_file "~/.config/mpd/"
db_file "/home/media/mpd/mpd.db"
state_file "/home/media/mpd/mpdstate"
log_file "/home/media/mpd/mpd.log"
playlist_directory "/home/media/Playlists"
music_directory "/home/media/Collection"
sticker_file "/home/media/sticker.sql"
audio_output {
        type            "pulse"
        name            "pulse audio"

Also as user "media", create /home/media/mpd

Create an X autostart file (put it in .config/autostart/mpd.desktop):

[Desktop Entry]
Name=Music Player Daemon
Comment=Server for playing audio files

pacmd load-module module-combine sink_name=rtp.hdmi.combined slaves="rtp,alsa_output.pci-0000_00_01.1.hdmi-stereo"
pacmd set-default-sink rtp.hdmi.combined


Build from the AUR, install.

Create an X autostart file (put it in .config/autostart/mpd.desktop):

[Desktop Entry]
Name=Shairport (Airport) Player Daemon
Comment=Server for playing audio files
Exec=/usr/bin/shairport -a basement


# pacman -Sy ypbind-mt yp-tools ypserv

Move the entry for tvpc to be the first entry in /etc/hosts (even before localhost)

# /etc/hosts: static lookup table for host names

#<ip-address>   <>   <hostname>      cifarelli-nis tvpc       localhost.localdomain   localhost
::1             localhost.localdomain   localhost        router      beast

add the domain into /etc/nisdomainname

# NIS domain to be set by domainname.service

set the domainname on the command line

# domainname cifarelli-nis

edit /etc/ypserv.conf, add

10.0.1. :       cifarelli-nis   :       *       : none

edit /var/yp/Makefile (not sure about the publickeys, but make failed without something and that seemed innocuous.

# Should we merge the passwd file with the shadow file ?
# MERGE_PASSWD=true|false

# Should we merge the group file with the gshadow file ?
# MERGE_GROUP=true|false


ALIASES     = /etc/postfix/aliases


PUBLICKEYS  = /etc/ssh/



# cd /var/yp/
# make

(ignore the errors since we havent started the servers yet)

Now, I think this step should be unnecessary, but it helped me find mistakes, and there is no harm:

# /usr/lib/yp/ypinit -m

add raspberrypi to the list of servers when you come to it.

Edit /var/yp/securenets. Comment out



now edit /etc/yp.conf and add:

domain cifarelli-nis server cifarelli-nis

test with:

# yptest

Ignore the yp_match error - it just means the 'nobody' user is not being served by NIS.

Now start ypbind and ypserv (in that order) For reasons I have yet to figure out, the default timing with rpcbind, nfs-server, ypbind, ypserv in systemd causes nfs and ypbind to fail. So I cheated for now and setup an rc.local.start and rc.local.stop with these scripts:


Description=replicate old rc.local behavior




Then enable rc-local.service

and add these 2 scripts: /etc/rc.local.start:

systemctl start ypbind
systemctl start ypserv

and /etc/rc.local.stop:

systemctl stop ypserv
systemctl stop ypbind

and make rc.local.start and rc.local.stop executable.

Setup the clients

Log onto the raspberrypi, as root.

# apt-get install nis

when prompted, answer cifarelli-nis for the nis domain

add to the end of /etc/passwd:


add to the end of /etc/group:


add to the end of /etc/shadow:


enable rpcbind and nis:

# update-rc.d rpcbind enable
# update-rc.d nis enable

Edit /etc/ypserv.securenets. Comment out



edit /etc/default/nis. change



# /usr/lib/yp/ypinit -s nis-master

start rpcbind and nis:

# /etc/init.d/rpcbind start
# /etc/init.d/nis start


OwnCloud is like running your own Dropbox. The setup is relatively easy.

Install owncloud as normal from the official repositories.

copy the example config file:

# cd /etc/webapps/owncloud
# cp apache.example.conf httpd-owncloud.conf

edit /etc/httpd/conf to include /etc/webapps/owncloud/httpd-owncloud.conf:

# OwnCloud
Include /etc/webapps/owncloud/httpd-owncloud.conf

make sure these required extensions are uncommented in /etc/php/php.ini:

These should already be installed; install if not: php-intl, php-mcrypt

and uncomment the following extensions if not already:

If not installed, install exiv2 and enable

If not installed, install php-xcache and enable it in either php.ini or /etc/php/conf.d/xcache.ini. (mine was already installed and enabled in php.ini, commented out in xcache.ini, but other parameters were set in xcache.ini).

I use mysql of course, so these were already enabled:


Note that of this writing mysqli.o was not supported by owncloud; fortunately mysql.o was already the one in use on my server.



and set the ownership for all to http:http. Add the media account to the http group, and add the http account to the media group. This will be where data is kept.

Copy the .htaccess files:

# cp /usr/share/webapps/owncloud/.htaccess /home/media/owncloud
# cp /usr/share/webapps/owncloud/data/.htaccess /home/media/owncloud/data

Set permissions with this script:


find ${ocpath}/ -type f -print0 | xargs -0 chmod 0640
find ${ocpath}/ -type d -print0 | xargs -0 chmod 0750

chown -R root:${htuser} ${ocpath}/
chown -R ${htuser}:${htuser} ${ocpath}/apps/
chown -R ${htuser}:${htuser} ${ocpath}/config/
chown -R ${htuser}:${htuser} ${ocpath}/data/

chown root:${htuser} ${ocpath}/.htaccess
chown root:${htuser} ${ocpath}/data/.htaccess

chmod 0644 ${ocpath}/.htaccess
chmod 0644 ${ocpath}/data/.htaccess

Restart apache. Then navigate to This is in a 'first run' mode. Set the data directory to /home/media/owncloud/data and create an admin account. Login and create your users.

Setting up clients



Download the desktop app from Nothing to it; point it to the server at

Lightning is the Calendar app for Thunderbird. Install it from Tools -> Addons -> Get AddOns -> Lightning.

Enable multi-calendar support. Go to Tools -> Options -> Advanced -> General (tab) -> Config Editor. Find Double click until it shows true. Then 'x-out' as they say. Now go to File -> New -> Calendar. Select 'On the network'. Select 'CalDAV' and enter as the location.


Download the app from, and point it to your server.

iCal is the OS X Calendar App. To configure it for owncloud's calendar functions,

  1. In iCal open Settings, click on Account
  2. Press the + Button
  3. As Accounttype choose CalDAV
  4. Enter Username and Password
  5. As Server address enter only
  6. Click on Create.



First, download the $0.99 app from Google Play. Enter user name, password, and as the server. You might want to enable Instant Upload.

Next, download the CalDAV-Sync app from Google Play - this one costs a couple of dollars. Add Account, then enter user name, password, and

as the location.

Next download the CardDAV-Sync app from Google Play. Add account, then enter user name, password, and

as the server. I couldn't get autoconfigure to do anything. Furthermore, it wouldnt sync from phone to server, so I had to manually upload my contacts. Do this by going to the Contacts App -> Import/export. Export the file, copy it to owncloud, then go to the owncloud website (yours,, and import the vcf file. When you want to create a new contact, you'll be given a choice of accounts, select the CardDAV account and it will sync to all your devices.

Finally, you can download the Tasks app (Marten Gajda). There's nothing really to configure - it requires CalDAV - Sync and apparently uses settings from there.

  1. Go to Settings, tap on Mail, Contacts, Calendars
  2. Tap on Add Account, others
  3. At Calendars Tap on CalDAV Account
  4. Enter Server
  5. Enter Username and Password
  6. tap on next, done


First, install tigervnc. This includes the x0vncserver which will serve the main display :0. This can be started from systemd:


Description=Remote desktop service (VNC)

ExecStart=/usr/bin/sh -c '/usr/bin/x0vncserver -display :0 -rfbport 5900 -passwordfile /home/media/.vnc/passwd &'


Next setup vncserver. Since we autologin, we start vncserver in the .xinitrc in that account. Just before starting the window manager, start vncserver in the background:

 vncserver &
 exec startkde

Make sure there are passwords set so that not anyone on the network can grab a running session:

# vncpasswd -f .vnc/passwd

Now setup the window manager for vnc. The big ones don't seem to like running very well, so I use icewm, which almost seems to have been designed just for vncserver. Edit .vnc/xstartup

 [ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources
 xsetroot -solid black
 vncconfig -iconic &
 icewm-session &

Finally, setup icewm. As a minimum, add konsole to .icewm/menu:

prog xterm xterm xterm
prog konsole konsole konsole


Install (AUR) xrdp.

Edit /etc/xrdp/xrdp.ini, comment out "autorun". Make sure username and password is set to 'ask' for any entries you want to use, especially sesman-any.

# systemctl start xrdp
# systemctl start xrdp-sesman

Edit /etc/xrdb/

after the locale call, add

 if [ -r ~/.vnc/xstartup ]; then
    . ~/.vnc/xstartup
    exit 0

In the accounts that will use it, set up the ~/.vnc and ~/.icewm as in VNC above.

Use Remote Desktop from Windows or rdesktop from linux to connect and create a new session. Select 'sesman-any' initially (or anytime). Most of the time you have to log in twice - the first almost always fails but the second almost always works.


install minidlna

sysctl fs.inotify.max_user_watches=200000

create /etc/sysctl.d/90-inotify.conf:

fs.inotify.max_user_watches = 200000

Edit /usr/lib/systemd/system/minidlna.service:


change the minidlna group to users (is this necessary?):

usermod -g users minidlna

Ok, so something changed and now I can't get this setup to work. So I had to build my own minidlna from the git repository.

Remove the official version:

# pacman -R minidlna

Clone the git repository:

# cd develop/repositories
# git clone minidlna-git
# cd minidlna-git

In minidlna.c, line 607, comment out this:

 if (!path || access(path, F_OK) != 0)
    DPRINTF(E_ERROR, L_GENERAL, "Media directory \"%s\" not accessible [%s]\n",
       ary_options[i].value, strerror(errno));

Now build:

# ./
# ./configure
# make clean; make
# sudo make install

Create the systemd startup file /usr/lib/systemd/system/minidlna.service:

Description=minidlna server

ExecStart=/usr/local/sbin//minidlnad -f /etc/minidlna.conf


Create the config file /etc/minidlna.conf"

# port for HTTP (descriptions, SOAP, media transfer) traffic

# network interfaces to serve, comma delimited

# specify the user account name or uid to run as

# set this to the directory you want scanned.
# * if you want multiple directories, you can have multiple media_dir= lines
# * if you want to restrict a media_dir to specific content types, you
#   can prepend the types, followed by a comma, to the directory:
#   + "A" for audio  (eg. media_dir=A,/home/jmaggard/Music)
#   + "V" for video  (eg. media_dir=V,/home/jmaggard/Videos)
#   + "P" for images (eg. media_dir=P,/home/jmaggard/Pictures)
#   + "PV" for pictures and video (eg. media_dir=PV,/home/jmaggard/digital_camera)

# set this to merge all media_dir base contents into the root container
# note: the default is no

# set this if you want to customize the name that shows up on your clients
#friendly_name=My DLNA Server
friendly_name=Cifarelli DLNA Server

# set this if you would like to specify the directory where you want MiniDLNA to store its database and album art cache

# set this if you would like to specify the directory where you want MiniDLNA to store its log file

# set this to change the verbosity of the information that is logged
# each section can use a different level: off, fatal, error, warn, info, or debug

# this should be a list of file names to check for when searching for album art
# note: names should be delimited with a forward slash ("/")

# set this to no to disable inotify monitoring to automatically discover new files
# note: the default is yes

# set this to yes to enable support for streaming .jpg and .mp3 files to a TiVo supporting HMO

# set this to beacon to use legacy broadcast discovery method
# defauts to bonjour if avahi is available

# set this to strictly adhere to DLNA standards.
# * This will allow server-side downscaling of very large JPEG images,
#   which may hurt JPEG serving performance on (at least) Sony DLNA products.

# default presentation url is http address on port 80

# notify interval in seconds. default is 895 seconds.

# serial and model number the daemon will report to clients
# in its XML description

# specify the path to the MiniSSDPd socket

# use different container as root of the tree
# possible values:
#   + "." - use standard container (this is the default)
#   + "B" - "Browse Directory"
#   + "M" - "Music"
#   + "V" - "Video"
#   + "P" - "Pictures"
#   + Or, you can specify the ObjectID of your desired root container (eg. 1$F for Music/Playlists)
# if you specify "B" and client device is audio-only then "Music/Folders" will be used as root

# always force SortCriteria to this value, regardless of the SortCriteria passed by the client

# maximum number of simultaneous connections
# note: many clients open several simultaneous connections while streaming

# set this to yes to allow symlinks that point outside user-defined media_dirs.

Start and enable:

# systemctl start minidlna
# systemctl enable minidlna

Bubble UPnP

install bubbleupnp

systemctl start bubbleupnp

go to http://tvpc:58050 to complete configuration


follow the instructions on the ArchWiki

install certbot to get a Let's Encrypt cert create the cert

need to set the cert ownership to ldap:ldap

additionally, need acls for the archive and live dirs:

# setfacl -m "u:ldap:rx" /etc/letsencrypt/live
# setfacl -m "u:ldap:rx" /etc/letsencrypt/archive
# setfacl -R -m "u:ldap:rx" /etc/letsencrypt/live/
# setfacl -R -m "u:ldap:rx" /etc/letsencrypt/archive/

You need to download the postfix-book.schema, which is reproduced here:

# $Id$
# State of Mind
# Private Enterprise Number: 29426
# OID prefix:
# Attributes:

attributetype ( NAME 'mailHomeDirectory'
	DESC 'The absolute path to the mail user home directory'
       EQUALITY caseExactIA5Match

attributetype ( NAME 'mailAlias'
       DESC 'RFC822 Mailbox - mail alias'
       EQUALITY caseIgnoreIA5Match
       SUBSTR caseIgnoreIA5SubstringsMatch
       SYNTAX{256} )

attributetype ( NAME 'mailUidNumber'
       DESC 'UID required to access the mailbox'
       EQUALITY integerMatch

attributetype ( NAME 'mailGidNumber'
       DESC 'GID required to access the mailbox'
       EQUALITY integerMatch

attributetype ( NAME 'mailEnabled'
	DESC 'TRUE to enable, FALSE to disable account'
       EQUALITY booleanMatch

attributetype ( NAME 'mailGroupMember'
	DESC 'Name of a mail distribution list'
       EQUALITY caseExactIA5Match
       SYNTAX )

attributetype ( NAME 'mailQuota'
	DESC 'Mail quota limit in kilobytes'
       EQUALITY caseExactIA5Match
       SYNTAX )

attributetype ( NAME 'mailStorageDirectory'
	DESC 'The absolute path to the mail users mailbox'
       EQUALITY caseExactIA5Match

attributetype: ( NAME ( 'mailSieveRuleSource' )
	DESC 'Sun ONE Messaging Server defined attribute'
	SYNTAX  X-ORIGIN 'Sun ONE Messaging Server' )

attributetype ( NAME 'mailForwardingAddress'
        DESC 'Address(es) to forward all incoming messages to.'
        EQUALITY caseIgnoreIA5Match
        SYNTAX{320} )

# Objects:

objectclass ( NAME 'PostfixBookMailAccount'
       SUP top AUXILIARY
	DESC 'Mail account used in Postfix Book'
	MUST ( mail )
       MAY ( mailHomeDirectory $ mailAlias $ mailGroupMember
		$ mailUidNumber $ mailGidNumber $ mailEnabled
		$ mailQuota $mailStorageDirectory $mailSieveRuleSource ) )

objectclass ( NAME 'PostfixBookMailForward'
       SUP top AUXILIARY
	DESC 'Mail forward used in Postfix Book'
	MUST ( mail $ mailAlias )
	MAY ( mailForwardingAddress ))

To add it, you have to fix the permission of the root (admin) cn:

So, edit the file /etc/ldap/slapd.d/cn=config/olcDatabase\=\{0\}config.ldif, find the line:

olcRootDN: cn=root

and change to:

olcRootDN: cn=root,cn=config

Then copy the password added for the rootDN in slapd.conf as

olcRootPW: {SSHA}...