Rocket.Chat is a free/open source software for team collaboration. It is a full featured platform and an ideal alternative to Slack, for organizations that are dedicated to the Free Software philosophy.

In this guide we will demonstrate how you can setup Rocket.Chat for your organization.


  • A Debian stretch VM or server.
  • A FQDN pointing to the system’s IP. We will be using throughout this guide.

Installation of

Install the Snappy package manager

Snappy is not installed on Debian by default, so we need to install it:

# apt install snapd ca-certificates

Install Rocket.Chat

# snap install rocketchat-server

Check its status:

# systemctl status snap.rocketchat-server.rocketchat-server.service
● snap.rocketchat-server.rocketchat-server.service - Service for snap application rocketchat-server.rocketchat-server
   Loaded: loaded (/etc/systemd/system/snap.rocketchat-server.rocketchat-server.service; enabled; vendor preset: enabled)
   Active: active (running) since Tue 2017-01-03 12:27:50 PST; 12min ago
 Main PID: 24891 (node)
    Tasks: 10 (limit: 4915)
   CGroup: /system.slice/snap.rocketchat-server.rocketchat-server.service
           └─24891 node /snap/rocketchat-server/326/main.js

Jan 03 12:27:50 rocket systemd[1]: Started Service for snap application rocketchat-server.rocketchat-server.

Check its port (default is 3000):

# ss -lnptu | grep 3000
tcp    LISTEN     0      128       *:3000                  *:*                   users:(("node",pid=24891,fd=13))

Looks OK

Configure TLS

Install nginx

The core application does not support TLS so we will be setting up an nginx reverse proxy on top of it.

Install NGINX and certbot from Let’s Encrypt:

# apt -y install nginx python-certbot-nginx

Create the VirtualHost

We need to create this file: /etc/nginx/sites-available/

# Upstreams
upstream backend {

# HTTP Server
server {
    listen 80;

    error_log /var/log/nginx/rocketchat.access.log;

    location / {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forward-Proto http;
        proxy_set_header X-Nginx-Proxy true;

        proxy_redirect off;

Enable the VirtualHost:

cd /etc/nginx/sites-enabled/
ln -s ../sites-available/
systemctl reload nginx

Generate the certificate

certbot --nginx run -d
  • Enter email address:
  • Agree to the ToS
  • Enforce HTTPS: Secure

The VirtualHost file (/etc/nginx/sites-available/ should look like this after the creation of the Let’s Encrypt certificate:

# Upstreams
upstream backend {

server {
    listen 80;

    error_log /var/log/nginx/rocketchat.access.log;

    location / {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forward-Proto http;
        proxy_set_header X-Nginx-Proxy true;

        proxy_redirect off;

    listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/; # managed by Certbot
ssl_session_cache shared:le_nginx_SSL:1m; # managed by Certbot
ssl_session_timeout 1440m; # managed by Certbot

ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # managed by Certbot
ssl_prefer_server_ciphers on; # managed by Certbot


    if ($scheme != "https") {
        return 301 https://$host$request_uri;
    } # managed by Certbot

Now visit the website to test it: (it should redirect you to

Creating an admin account

Register a new account. You will get this warning:

WARNING: the setting site URL is configured to http://localhost and you are accessing from do you want to change to

You should ofcourse answer ‘Yes’.

This first user created is an admin user. You can set global preferences from Now users can visit the website and register with it. You may wish to Allow Notifications when you are prompted by your browser on your first visit to the site. Rocket.Chat supports many other authentication backends, including LDAP which is described in the next step.

Besides the web service you can also download native applications for Linux, Windows, Mac OS X, Android and iOS.

Configure LDAP

This is an optional step, but recommended if your organization has an LDAP or Active Directory setup. In this example we are using the Fusiondirectory setup from our previous guide.

Create a service account for, using the DSA module of Fusiondirectory:

  • Username: cn=rocketchat,ou=dsa,dc=example,dc=com
  • Password: MySecretCombination

Now go to using an admin account and set these:

  • Enable: True
  • Login Fallback: True
  • Host:
  • Port: 389
  • Encryption: StartTLS
  • CA Cert: Paste the contents of your internal ROOT CA certificate ( for example)
  • Reject Unauthorized: True
  • Domain Base: ou=people,dc=example,dc=com
  • Use Custom Domain Search: False
  • Domain Search User: cn=rocketchat,ou=dsa,example,dc=com
  • Domain Search Password: MySecretCombination
  • Domain Search User ID: uid
  • Domain Search Object Class: person
  • Domain Search Object Category: Leave Empty
  • Username Field: Leave Empty

Leave the default settings for the rest and press the SAVE CHANGES button

You can use the TEST CONNECTION button to test the connection.

You can now try to login using your LDAP username and password.


Less than a year ago I was attracted by the value for money offer of OnePlus 2 and became a proud owner. Being paranoid about Google tracking, I disabled most Google apps. Alas, some apps were impossible to disable. I assumed that this was caused by their dependencies with other core applications. Google play services was one them, but I never created an account with Google and never synced anything with them.

Time went by and it happened that data over mobile was accidentally enabled. And then I noticed from the mobile data traffic statistics, that Google Play services was creating traffic even without a Google account! Why does this happens its beyond my perception, but anyone is allowed to guess based on recent history. There is an option to disable background traffic on the stock Android ROM (OxygenOS) but that works only when data over mobile is enabled. With Wi-Fi enabled, Google Play services keeps on sending suspicious traffic, back to mother Google.

So I decided to look for alternatives to replace OxygenOS with a Google-free Android ROM. These are the options I have investigated:

  • Replicant: This seems to be the more privacy respecting Android MOD. No support for OnePlus 2, alas!
  • AOKP: This is an interesting MOD with lots of features. There are recent nightly builds for OnePlus 2. I tried to install it my Phone but gave an error when I tried to sideload it.
  • CyanogenMOD: A popular Android MOD that was recently discontinued. A fork by the name LineageOS is taking over. No image downloads yet.
    UPDATE (2-Jan-2016): There are some experimental LineageOS images here.
  • Paranoid Android: Another successful Android MOD with close ties to OnePlus. It boasts some interesting features. Officially supports all OnePlus models except the latest OnePlus 3T. I tried the OnePlus 2 image but the phone stack to the OnePlus logo boot screen.
  • Exodus: This is a minimalistic Android MOD. It is based on AOSP and is free from Google Apps. This is the only MOD I managed to get it working on my OnePlus 2.

So I decided to go with Exodus. This guide describes the procedure and preparations I followed in order to flash the latest Exodus nightly build for OnePlus 2.

DISCLAIMER: This guide could renter your device a luxurious brick! Backup everything before you continue. The author of this guide will not be liable for any damages you may cause on your device or any data lost. Proceed at your own risk!

Now we got that out of the way, let’s continue.


  • A PC. In this guide we are using Debian/Ubuntu as the PC’s Operating System but this can work with other Operating Systems, with minor adaptations.
  • An OnePlus 2 smartphone. It could possibly be used for other devices too, but I have only tested this on OnePlus 2.
  • The Android Debug Bridge (ADB). This is part of the Android SDK. On Debian/Ubuntu you can install it with apt install android-tools-adb.
  • A Type-C USB cable to connect the phone to your PC.

Make your device detectable in Linux

There is some process we need to follow so that the OnePlus 2 device is detectable by ADB

Enable Usb Debugging

To Enable USB Debugging we need to first enable the Developer Options:

  • Go into Settings
  • Dive into the About phone option
  • Tap 7 times on the Build number option
  • Go back and tap on Developer Options
  • Enable USB debugging and OEM unlock

Enable detection of device under Linux

First ensure that the device is connected:

# lsusb
 Bus 003 Device 039: ID 2a70:f003  

The device ID for OnePlus 2 is 0x2a70. Set this in ~/.android/adb_usb.ini:

# echo "0x2a70" >> ~/.android/adb_usb.ini

Download the udev rules files (Thanks Nicolas Bernaerts):

# wget --header='Accept-Encoding:none' -O /etc/udev/rules.d/51-android.rules
# chmod a+r /etc/udev/rules.d/51-android.rules
# wget --header='Accept-Encoding:none' -O /etc/udev/rules.d/69-mtp.rules
# chmod a+r /etc/udev/rules.d/69-mtp.rules

Restart the udev and ADB services:

# systemctl restart udev
# adb kill-server
# adb start-server

NOTE: make sure USB Debugging is enabled otherwise you will still not be able to see the device!

Verify that the device is present:

# adb devices 
List of devices attached 
da0afea7        unauthorized

Seems OK.

Backup your data and stock image

Since we are not using Google’s services we will need to manually backup all important data such as:

  • Export contacts on a .vcf file.
  • Save Pictures and Videos from the phone on your PC
  • Backup every other Applacation data which is important to you.

You can also backup your entire system with ADB:

# adb backup -f oneplus2.bck -apk -shared -all

This will take some time depending on the size of your data.

You can later restore your system back to normal, using this command:

# adb restore oneplus2.bck

Prepare the recovery image

Download Prepare the First Aid kit

This is a bundle that includes all the files needed to bring life to a bricked OnePlus 2 device. It includes a recovery image which we will use to install Exodus (or any other image you wish) on the device.

# wget -O ''
# unzip

All the necessary files are in the newly created, Firstaid directory.

Download TWRP Custom recovery

The recovery image that comes with Firstaid is somewhat outdated. We will download a more recent version of it and replace it in the Firstaid directory. You can download the more recent TWRP image from here. Do not use wget or other command line tools, just a normal browser to download it.

NOTE: There are more recent versions than 3.0.2-0 like 3.0.2-1 and 3.0.2-2. You can try those if you feel lucky, but be warned! Those versions did not work on my phone. You can see all the past and resent images here.

Verify the downloaded image:

# wget -O twrp-public.asc
# gpg --import twrp-public.asc
# wget
# gpg --verify twrp-3.0.2-0-oneplus2.img.asc twrp-3.0.2-0-oneplus2.img

If you get Good signature from "TeamWin <>" that means the image is correct. Now replace the TWRP image that comes with Firstaid with this one:

# cp twrp-3.0.2-0-oneplus2.img Firstaid/twrp.img

Flash the recovery image

Reboot to fastboot mode:

# adb reboot-bootloader

Alternatively you can poweroff the OnePlus 2 and press the Volume UP + Power buttons simultaneously.

Verify the presence of the device:

# fastboot devices
da0afea7               fastboot

Unlock the phone:

fastboot oem unlock

Flash Firstaid with the recent TWRP recovery image:

# cd Firstaid
# ./

Now unplug the phone from the PC, poweroff and the press the Volume DOWN + Power buttons simultaneously. This will bring your phone into TWRP recovery.

Flashing the Exodus image

Download Exodus image and verify

Download the latest Exodus image for OnePlus 2 here:

# wget
# wget 

Verify that the download is correct:

# cat ; md5sum
35dcf9ea73648682a36e673f5ed8f0eb  /android/exodus-6.0/out/target/product/oneplus2/

Seems OK

Plug the phone back to the PC and ensure that it is detectable by ADB:

# adb devices 
List of devices attached 
da0afea7        device

Flash the Exodus image

Follow these steps:

  • Wipe old data: Select Wipe and then Swipe to Factory Reset. You may need to format the system if the previous system was encrypted.
  • Enter the Sideload mode: From the TWRP start menu select Advanced then ADB Sideload and then Swipe to Start Sideload
  • From the PC’s CLI run the following command:

    # adb sideload

Wait and then reboot into the new Exodus system when done.

Optional steps

Install F-Droid:

By default Exodus has a minimal set of apps. Since we are not using Google Apps we will need to install F-Droid:

# wget
# adb install FDroid.apk

Lock your Phone

Setup a PIN or Pattern to lock the screen of your phone when not in use: Settings -> Security -> Screen Lock. Avoid fingerprint as it can be easily bypassed.

Encrypt phone

Encrypting your phone will protect your data if it gets stolen or confiscated. These are the steps Settings -> Security -> Encrypt phone. Your phone will need to be plugged to charger and charged to 80% or above, otherwise the system will refuse to start the encryption process.

Restoring the Stock OxygenOS System

If you decide that you don’t like Exodus or any other MOD that you have installed, you can restore your phone back to the stock OxygenOS. These instructions can also be used to restore your phone’s functionality after you have accidentally bricked it.

Download necessary images

Download the stock OxygenOS 3.0.2 image from here. Verify the download with:

# echo 46b1fde116275d83d05c2dd89422069f ; md5sum

Download the upgrade patch for Oxygen 3.1.0 from here. Verify the download with:

# echo 9cfa9a2a4c7fada6f9db79ea660251d0 ; md5sum 

Optionally you can download the SuperSU image if you would like your OxygenOS rooted:

# wget -O ''

Flash Recover image

First we need to restore the recovery ROM from Firstaid:

# cd Firstaid
# ./

Flash the Oxygen Images.

Before we install the OxygenOS image it is recommended to wipe the phone: From the TWRP menu select Wipe and then Swipe to factory reset. If the system was previously encrypted you will need to use TWRP to format it before the wipe.

Then we need to set the device into Sideload mode: Select Advanced -> ADB Sideload -> Swipe to Start Sideload.

First install the OxygenOS 3.0.2 image:

adb sideload

Then re-enable ADB Sideload and load the Oxygen 3.2.0 patch:

adb sideload

Optionally you can also load the SuperSU application as well

adb sideload

Finally reboot into the new system and enjoy your freshly formatted phone.


Most registrars they provide a DNS service when you purchase a domain name. But having your own DNS servers means more control to you. And if you are an aspiring sysadmin, you will find it fun and educational. We will be using BIND 9 which is, by far the most popular DNS implementation.


We will need two systems (VMs or containers) preferably on different geographic locations and different providers. One will be the master and the other system, the slave. This guide works for recent Debian or Ubuntu systems.

Some assumptions:

  • Master DNS:
    • Hostname:
    • IP:
  • Slave DNS:
    • Hostname:
    • IP:
  • Webserver:
    • Hostname: ( is an alias)
    • IP:
  • Main mailserver:
    • Hostname: ({mail,smtp,pop,imap,webmail} are aliases)
    • IP:
  • Backup mailserver:
    • Hostname:
    • IP:


Setup the /etc/hosts file

On master’s /etc/hosts: ns1

On slave’s /etc/hosts: ns2

Installing BIND

NOTE: all commands must be applied to both master and slave unless otherwise stated

apt-get -y install bind9 bind9utils

Allow port 53:

ufw allow 53

Configure the global options

Make the following changes in the /etc/bind/named.conf.options of both servers:

--- /etc/bind/named.conf.options        2016-12-12 14:44:57.163515708 -0500
+++ /etc/bind/    2016-12-12 14:52:29.749268250 -0500
@@ -1,5 +1,7 @@
 options {
        directory "/var/cache/bind";
+       recursion no;
+       allow-transfer { none; };

        // If there is a firewall between you and nameservers you want
        // to talk to, you may need to fix the firewall to allow multiple

Configure the local options

On master’s /etc/bind/named.conf.local:

--- /etc/bind/named.conf.local  2016-12-12 20:06:27.000000000 +0000
+++ /etc/bind/      2016-12-12 20:07:03.000000000 +0000
@@ -6,3 +6,8 @@
 // organization
 //include "/etc/bind/zones.rfc1918";

+zone "" {
+    type master;
+    file "/etc/bind/";
+    allow-transfer {; };

On slave’s /etc/bind/named.conf.local:

--- /etc/bind/named.conf.local  2016-11-01 13:02:24.000000000 -0400
+++ /etc/bind/      2016-12-12 15:09:47.445235343 -0500
@@ -6,3 +6,8 @@
 // organization
 //include "/etc/bind/zones.rfc1918";

+zone "" {
+    type slave;
+    file "";
+    masters {; };

Create the zone file

On master server create the zone file (/etc/bind/

$TTL 3600
@    IN    SOA (
                                            180 )

; NS Records
@       300    IN      NS    
@       300    IN      NS    

; MX Records
@       300    IN      MX      10
@       300    IN      MX      20

; Address records
@       300    IN      A     
ns1     300    IN      A     
ns2     300    IN      A     
mx1     300    IN      A     
mx1     300    IN      A     

; Alias (Canonical Name) records
www     300    IN      CNAME 
mail    300    IN      CNAME 
smtp    300    IN      CNAME 
imap    300    IN      CNAME 
pop     300    IN      CNAME 
webmail 300    IN      CNAME 

; TXT records
@       300    IN      TXT             "v=spf1 a mx ?all"

Verify the global configuration

Run the named-checkconf command on both servers. If you get any errors you should fix them before proceeding.

Verify the zone configuration

Run the following command on the master server:

named-checkzone /etc/bind/ 
zone loaded serial 2016121201

If you get ‘OK’ then your setup is correct, otherwise you should fix it before proceeding.

Restart bind and test your servers

systemctl restart bind9.service

Now test if your servers resolve your records.

The master:

dig @
;; ANSWER SECTION:   300 IN  CNAME    300 IN  A

The slave:

dig @
;; ANSWER SECTION:   300 IN  CNAME    300 IN  A

If you get any errors you can check your syslog file (/var/log/syslog).


After you have tested that everything is OK, it is time to tell your registrar about the new servers. This is called setting the glue records and you should consult the documentation of your registrar on how to do that. Ask support if you have any trouble.


In this guide we will show how you can remotely decrypt a headless Debian or Ubuntu Linux system, that has been encrypted with LUKS.


  • A LUKS encrypted Debian jessie or Ubuntu xenial system
  • Keyboard and monitor for the initial system setup
  • Allow SSH root access on the decrypted system using public key authentication
  • Use a different port for ssh (assuming port 4422) on the decrypted system

    NOTE: using a different port than the standard SSH port (22) serves a double purpose. For once, you will not received the scary WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! message every time you will try to remotely unlock the system and as an additional bonus you will get less SSH attacks on the active system.

Installing dropbear

Dropbear is a lightweight SSH server especially suitable for initial ramdisk (initrd) environments and other lightweight systems.

Install dropbear:

# apt -y install dropbear

Setup public key authentication for dropbear

Create the homedir for the root user and the SSH configuration directory:

# mkdir -p /etc/initramfs-tools/root/.ssh

Append your client SSH pubkey to authorized_keys:

# cat ~/.ssh/ | ssh -p 4422 root@encrypted-system "cat >> /etc/initramfs-tools/root/.ssh/authorized_keys"

Setup a static IP for the unlock environment

This step is optional but highly recommended if you are setting up a static, permanent service. If you skip this step DHCP will kick in, provided you have a DHCP Server in your environment.

Run this command to update the /etc/initramfs-tools/initramfs.conf configuration file:

echo IP= >> /etc/initramfs-tools/initramfs.conf

Explanation of the different fields:

NOTE: there are two successive colons (::) after the host_ip.

Setup the unlock script

Copy the following text in /etc/initramfs-tools/hooks/

# By Stinky Parkia


prereqs() {
    echo "$PREREQ"

case "$1" in
    exit 0

. "${CONFDIR}/initramfs.conf"
. /usr/share/initramfs-tools/hook-functions

if [ "${DROPBEAR}" != "n" ] && [ -r "/etc/crypttab" ] ; then
    cat > "${DESTDIR}/bin/unlock" << EOF
if PATH=/lib/unlock:/bin:/sbin /scripts/local-top/cryptroot; then
    kill \`ps | grep cryptroot | grep -v "grep" | awk '{print \$1}'\`
    # following line kill the remote shell right after the passphrase has
    # been entered.
    kill -9 \`ps | grep "\-sh" | grep -v "grep" | awk '{print \$1}'\`
    exit 0
exit 1

    chmod 755 "${DESTDIR}/bin/unlock"

    mkdir -p "${DESTDIR}/lib/unlock"
    cat > "${DESTDIR}/lib/unlock/plymouth" << EOF
[ "\$1" == "--ping" ] && exit 1
/bin/plymouth "\$@"

    chmod 755 "${DESTDIR}/lib/unlock/plymouth"

    echo To unlock root-partition run "unlock" >> ${DESTDIR}/etc/motd

Make the script executable:

# chmod +x /etc/initramfs-tools/hooks/

Apply the configuration

Apply the changes in the initial ramdisk:

# update-initramfs -u

Reboot the system:

# reboot

Remotely unlock the system

From your client, SSH into the initial ramdisk:

ssh root@encrypted-system 

If everything is correct you will be greeted by this MOTD:

To unlock root-partition run unlock

BusyBox v1.22.1 (Ubuntu 1:1.22.0-15ubuntu1) built-in shell (ash)
Enter 'help' for a list of built-in commands.

Unlock the system and boot into it:

# unlock
Please unlock disk sda3_crypt: 

You will get the following message and you will exit the remote shell if successful:

cryptsetup: sda3_crypt set up successfully
Connection to closed.

You can now login to the active Linux system using the alternative port 4422:

ssh -p 4422 root@encrypted-system

If you can login successfully to your system you can remove the keyboard and monitor and hide your system somewhere where the Sun does not shine :).

Thanks to Stinky Parkia for the excellent guide and the brilliant unlock script.


This guide is about setting up a Postfix/Dovecot system using LDAP/Fusiondirectoory as a backend.


Install Plugins

  • Install the Mail plugin:

    apt -y install fusiondirectory-plugin-mail fusiondirectory-plugin-mail-schema
    fusiondirectory-insert-schema -i /etc/ldap/schema/fusiondirectory/mail-fd.schema
    fusiondirectory-insert-schema -i /etc/ldap/schema/fusiondirectory/mail-fd-conf.schema
  • Install the Alias plugin:

    apt -y install fusiondirectory-plugin-alias fusiondirectory-plugin-alias-schema
    fusiondirectory-insert-schema -i /etc/ldap/schema/fusiondirectory/alias-fd-conf.schema
    fusiondirectory-insert-schema -i /etc/ldap/schema/fusiondirectory/alias-fd.schema
  • Install the Postfix plugin:

    apt -y install fusiondirectory-plugin-postfix fusiondirectory-plugin-postfix-schema
    fusiondirectory-insert-schema -i /etc/ldap/schema/fusiondirectory/postfix-fd.schema

Setup mail services:

  • Enter the server configuration (Systems plugin)

  • From the ‘Services’ tab create a ‘Postfix (SMTP)’ and an ‘IMAP/POP3 generic’ service

  • Add mail capability to all normal users:

    • Click the ‘Mail’ tab of a user and then press ‘Add Mail settings’

    • Fill in the ‘Primary Address. field and select as the server.
  • Add All necessary distribution lists and redirections from ‘Aliases’

Setup postfix

  • Create a service account for postfix using the ‘DSA’ plugin in *FusionDirectory’. It should look like this:

    dn: cn=postfix,ou=dsa,dc=example,dc=com
    cn: postfix
    userPassword:: yeduyt2732tet87eoiewoi32t4873t4387f7gf47gf49i6=
    structuralObjectClass: organizationalRole
    entryUUID: 280427ce-9a54-1035-8e48-bf1fd814366b
    creatorsName: cn=admin,dc=example,dc=com
    createTimestamp: 20160419082627Z
    objectClass: organizationalRole
    objectClass: top
    objectClass: simpleSecurityObject
    entryCSN: 20160419082628.006263Z#000000#000#000000
    modifiersName: cn=admin,dc=example,dc=com
    modifyTimestamp: 20160419082628Z
  • Install postfix:

    apt -y install postfix postfix-pcre postfix-ldap

    When you are prompted about “General type of mail configuration:” select “No configuration”

  • Prepare the file:

    cat > /etc/postfix/ << EOF
    inet_interfaces = all
    inet_protocols = all
    smtpd_banner = $myhostname ESMTP $mail_name
    myhostname =
    append_dot_mydomain = no
    mynetworks =
    local_transport = local
    alias_maps = hash:/etc/aliases
    alias_database = hash:/etc/aliases
    mydomain =
    mydestination =
    virtual_mailbox_domains = hash:/etc/postfix/virtual_domains
    virtual_mailbox_maps = proxy:ldap:/etc/postfix/
    virtual_alias_maps = proxy:ldap:/etc/postfix/
    smtpd_tls_security_level = may
    smtpd_tls_auth_only = yes
    smtpd_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
    smtpd_tls_cert_file = /etc/ssl/certs/
    smtpd_tls_key_file = /etc/ssl/private/
    tls_random_source = dev:/dev/urandom
    smtpd_tls_loglevel = 0
    smtpd_client_new_tls_session_rate_limit = 10
    smtpd_tls_session_cache_database = btree:/etc/postfix/smtpd_session_cache
    smtpd_tls_exclude_ciphers =
    smtpd_tls_dh512_param_file = ${config_directory}/certs/dh_512.pem
    smtpd_tls_dh1024_param_file = ${config_directory}/certs/dh_1024.pem
    postscreen_greet_action = enforce
    smtpd_recipient_restrictions =
        check_policy_service unix:private/policy-spf
        check_sender_ns_access cidr:/etc/postfix/drop.cidr
        check_sender_mx_access cidr:/etc/postfix/drop.cidr
    smtpd_data_restrictions = reject_multi_recipient_bounce
    smtpd_sender_restrictions =
    smtpd_helo_restrictions =
        check_helo_access pcre:/etc/postfix/identitycheck.pcre
    disable_vrfy_command = yes
    smtpd_helo_required = yes
    smtpd_delay_reject = no
    smtpd_client_restrictions = check_client_access cidr:/etc/postfix/drop.cidr
    message_size_limit = 51200000
  • Prepare the rest of the configuration files:

    • Prepare the virtual domains file:

      cat > /etc/postfix/virtual_domains << EOF
       # Domain                Anything
    • Prepare the virtual recipients file:

      cat > /etc/postfix/ << EOF
      bind = yes
      bind_dn = cn=postfix,ou=dsa,dc=example,dc=com
      bind_pw = NotTheRealPassword
      server_host = ldap://
      search_base = ou=people,dc=example,dc=com
      domain =
      query_filter = (mail=%s)
      result_attribute = mail
    • Prepare the virtual aliases file::

      cat > /etc/postfix/ << EOF
      bind = yes
      bind_dn = cn=postfix,ou=dsa,dc=example,dc=com
      bind_pw = NotTheRealPass
      server_host = ldap://
      search_base = ou=alias,dc=example,dc=com
      domain =
      query_filter = (mail=%s)
      result_attribute = gosaMailAlternateAddress, gosaMailForwardingAddress
    • Prepare the identity check file:

      cat > /etc/postfix/identitycheck.pcre << EOF
      # Identity (RegEx)              Action
      /^(mail\.example\.com)$/       REJECT Hostname Abuse: $1
      /^(1\.2\.3\.4)$/                REJECT Hostname Abuse: $1
      /^(\[1\.2\.3\.4\])$/            REJECT Hostname Abuse: $1
    • Prepare the blacklist file:

      cat > /etc/postfix/drop.cidr << EOF
      # IP/CIDR                       Action
                         REJECT Blacklisted
  • Generate the virtual domains hashmap:

    postmap hash:/etc/postfix/virtual_domains
  • Start postfix:

    systemctl start postfix


    ss -lnptu | grep master
    tcp    LISTEN     0      100    *:25      *:*      users (("master",pid=15539,fd=12))
  • Enable support for smtps (port 465) and submission (port 587):

    Uncomment the following lines from /etc/postfix/

    submission inet n       -       -       -       -       smtpd
    smtps     inet  n       -       -       -       -       smtpd

    Restart postfix:

    systemctl restart postfix


    ss -lnptu | grep master
    tcp    LISTEN     0      100    *:587     *:*      users:(("master",pid=15854,fd=16))
    tcp    LISTEN     0      100    *:465     *:*      users:(("master",pid=15854,fd=19))
    tcp    LISTEN     0      100    *:25      *:*      users:(("master",pid=15854,fd=12))
  • Take precautions for perfect forward secrecy:

    mkdir /etc/postfix/certs
    cd /etc/postfix/certs
    openssl dhparam -2 -out dh_512.pem 512
    openssl dhparam -2 -out dh_1024.pem 1024
    chmod 600 dh_*
  • Lookup test:

    postmap -q ldap:/etc/postfix/
  • Open SMTP, SMTPS ans Submission ports:

    ufw allow 25/tcp
    ufw allow 465/tcp
    ufw allow 587/tcp

Install and configure dovecot

  • Create a service account for dovecot using the ‘DSA’ plugin in *FusionDirectory’. It should look like this:

    dn: cn=dovecot,ou=dsa,dc=example,dc=com
    cn: dovecot
    userPassword:: ljsdewd98dej932j98dxjud8x3jx9843xj8943j438439e3=
    structuralObjectClass: organizationalRole
    entryUUID: 4d0d7174-9a54-1035-8e49-bf1fd814366b
    creatorsName: cn=admin,dc=example,dc=com
    createTimestamp: 20160419082730Z
    objectClass: organizationalRole
    objectClass: top
    objectClass: simpleSecurityObject
    entryCSN: 20160419082730.138012Z#000000#000#000000
    modifiersName: cn=admin,dc=example,dc=com
    modifyTimestamp: 20160419082730Z
  • Install dovecot:

    apt -y install dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-ldap
  • Make the following changes in /etc/dovecot/conf.d/10-ssl.conf:

    ssl = required
    ssl_cert = </etc/ssl/certs/
    ssl_key = </etc/ssl/private/
  • Make the following changes in /etc/dovecot/conf.d/10-auth.conf:

    disable_plaintext_auth = yes
    auth_mechanisms = plain login
    !include auth-ldap.conf.ext
  • Make the following changes in /etc/dovecot/dovecot-ldap.conf.ext:

    uris = ldap://
    dn = cn=dovecot,ou=dsa,dc=example,dc=com
    dnpass = SomePass33
    tls_ca_cert_file = /etc/ssl/certs/ca-certificates.crt
    tls_require_cert = demand
    ldap_version = 3
    base = ou=people,dc=example,dc=com
    user_attrs = =mail=maildir:/srv/vmail/%{ldap:mail}/Maildir
    user_filter = (&(objectClass=gosaMailAccount)(uid=%n))
    pass_attrs = uid=user,userPassword=password
    pass_filter = (&(objectClass=gosaMailAccount)(uid=%n))
    default_pass_scheme = SSHA
  • Make the following changes in /etc/dovecot/conf.d/10-logging.conf:

    log_path = syslog
    syslog_facility = mail
    auth_verbose = yes
    auth_verbose_passwords = no
    auth_debug = no
    auth_debug_passwords = no
    mail_debug = no
    verbose_ssl = no
  • Make the following changes in /etc/dovecot/conf.d/10-mail.conf:

    mail_uid = 5000
    mail_uid = 5000
  • Make the following changes in /etc/dovecot/conf.d/10-master.conf:

    service imap-login {
    inet_listener imap {
    port = 143
    inet_listener imaps {
    port = 993
    ssl = yes
    service pop3-login { inet_listener pop3 { port = 110 } inet_listener pop3s { port = 995 ssl = yes } }
    service auth { unix_listener auth-userdb { mode = 0777 user = dovecot group = dovecot } }
  • Add the vmail user in the system:

    addgroup --system --gid 5000 vmail
    adduser --system --home /srv/vmail --uid 5000 --gid 5000 --disabled-password --disabled-login vmail
  • Restart dovecot:

    systemctl restart dovecot


    netstat -lnptu | grep dovecot
    tcp        0      0   *               LISTEN      20894/dovecot   
    tcp        0      0   *               LISTEN      20894/dovecot   
    tcp        0      0   *               LISTEN      20894/dovecot   
    tcp        0      0   *               LISTEN      20894/dovecot   
    tcp6       0      0 :::993                  :::*                    LISTEN      20894/dovecot   
    tcp6       0      0 :::995                  :::*                    LISTEN      20894/dovecot   
    tcp6       0      0 :::110                  :::*                    LISTEN      20894/dovecot   
    tcp6       0      0 :::143                  :::*                    LISTEN      20894/dovecot  
  • Check if you can login:

    openssl s_client -connect localhost:993
    <output ommitted...>
    a1 LOGIN theo MyNotSoSecretPass
    a3 LOGOUT
    * BYE Logging out
    a2 OK Logout completed.
  • Enable IMAP, IMAPS, POP3 and POP3S ports:

    ufw allow 110/tcp
    ufw allow 143/tcp
    ufw allow 993/tcp
    ufw allow 995/tcp
  • Tell postfix to deliver mail using dovecot:

    • Add the follwing lines at the end of /etc/postfix/

      dovecot   unix  -       n       n       -       -       pipe
        flags=ODRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -e -f ${sender} -d ${recipient}
    • Add these attributes in /etc/postfix/

      virtual_transport = dovecot
      dovecot_destination_recipient_limit = 1
  • Restart postfix and dovecot:

    systemctl restart postfix dovecot

Install SASL for SMTP AUTH

  • Create a service account for saslauthd using the ‘DSA’ plugin in *FusionDirectory’. It should look like this:

    dn: cn=saslauthd,ou=dsa,dc=example,dc=com
    cn: saslauthd
    userPassword:: ejdoedoifj9ewufd9843e9ejfd98je938jcr9843843=
    structuralObjectClass: organizationalRole
    entryUUID: 61143234-9a54-1035-8e4a-bf1fd814366b
    creatorsName: cn=admin,dc=example,dc=com
    createTimestamp: 20160419082803Z
    objectClass: organizationalRole
    objectClass: top
    objectClass: simpleSecurityObject
    entryCSN: 20160419082803.738357Z#000000#000#000000
    modifiersName: cn=admin,dc=example,dc=com
    modifyTimestamp: 20160419082803Z
  • Install SASL:

    apt -y install libsasl2-2 sasl2-bin
  • Create the /etc/postfix/sasl/smtpd.conf:

    cat > /etc/postfix/sasl/smtpd.conf << EOF
    log_level: 3
    pwcheck_method: saslauthd
    mech_list: PLAIN LOGIN
  • Make the following changes in /etc/default/saslauthd:

    OPTIONS="-c -m /var/spool/postfix/var/run/saslauthd"
  • Create the /etc/saslauthd.conf file:

    cat > /etc/saslauthd.conf << EOF
    ldap_servers: ldap://
    ldap_bind_dn: cn=saslauthd,ou=dsa,dc=example,dc=com
    ldap_bind_pw: MySecretPass
    ldap_timeout: 10
    ldap_time_limit: 10
    ldap_scope: sub
    ldap_search_base: ou=people,dc=example,dc=com
    ldap_auth_method: bind
    ldap_filter: (&(uid=%u)(mail=*))
    ldap_debug: 0
    ldap_verbose: off
    ldap_ssl: yes
    ldap_starttls: no
    ldap_referrals: yes
  • Add the postfix user in the sasl group:

    usermod -aG sasl postfix
  • Add these attributes in /etc/postfix/

    smtpd_sasl_auth_enable = yes
    broken_sasl_auth_clients = yes
  • Restart saslauthd and postfix:

    systemctl restart saslauthd postfix
  • Test message delivery using SMTP AUTH:

    First you need to install swaks:

    apt -y install swaks

    Then use swaks to test message delivery:

    swaks --from --to --server --tls --auth plain --auth-user=theo
  • Test if the message has been delivered to inbox:

    First you need to install mutt:

    apt -y install mutt

    Then use mutt to test if the message has been delivered to inbox:

    mutt -f /srv/vmail/

    NOTE: When you are asked to create a ‘mail’ folder just say ‘no’.


LDAP/Fusiondirectory setup

In this guide we will be setting up LDAP (openldap) along with the FusionDirectory web management tool.


  • Install Debian jessie (Ubuntu 16.04 should work too) on your server or VM

  • Setup the DNS records in your DNS servers:           3599    IN      A

    NOTE: replace with you actual internal or external IP

  • Allow ssh and web services on firewall:

    apt -y install ufw
    ufw allow 22/tcp
    ufw allow 80/tcp
    ufw allow 443/tcp
    ufw enable

    NOTE: It may be a good idea to change the default ssh port from 22 to something less predictable

Setup LDAP

  • Setup in /etc/hosts: ldap
  • Install *OpenLDAP and FusionDirectory

    apt -y install slapd
    • Enter and verify the administrator password for slapd.
  • Create An Internal Certificate Authority for Example LTD:

    • First install gnutls-bin:

      apt -y install gnutls-bin
    • Create the key for the internal CA for

      certtool --generate-privkey --outfile
    • Create a certificate for our internal CA:

      certtool --generate-self-signed --load-privkey --outfile
      Generating a self signed certificate...
      Please enter the details of the certificate's distinguished name. Just press enter to ignore a field.
      Common name: Example LTD Internal ROOT CA
      Organizational unit name: IT
      Organization name: Example LTD
      Locality name: Limassol
      State or province name: Limassol
      Country name (2 chars): CY
      Enter the subject's domain component (DC): 
      This field should not be used in new certificates.
      Enter the certificate's serial number in decimal (default: 6295758616856773074): 
      The certificate will expire in (days): 7300

      Activation/Expiration time. The certificate will expire in (days): 7300

      Extensions. Does the certificate belong to an authority? (y/N): y Path length constraint (decimal, -1 for no constraint): -1 Is this a TLS web client certificate? (y/N): Will the certificate be used for IPsec IKE operations? (y/N): Is this a TLS web server certificate? (y/N): Enter a dnsName of the subject of the certificate: Enter a URI of the subject of the certificate: Enter the IP address of the subject of the certificate: Enter the e-mail of the subject of the certificate: Will the certificate be used to sign other certificates? (y/N): y Will the certificate be used to sign CRLs? (y/N): Will the certificate be used to sign code? (y/N): Will the certificate be used to sign OCSP requests? (y/N): Will the certificate be used for time stamping? (y/N): y Enter the URI of the CRL distribution point: X.509 Certificate Information: Version: 3 Serial Number (hex): 575f071b0d5a41d2 Validity: Not Before: Mon Jun 13 19:19:27 UTC 2016 Not After: Sun Jun 08 19:20:00 UTC 2036 Subject: CN=Example LTD Internal ROOT CA,OU=IT,O=Example LTD,L=Limassol,ST=Limassol,C=CY, Subject Public Key Algorithm: RSA Algorithm Security Level: Medium (2048 bits) Modulus (bits 2048): 00:c0:75:c8:02:05:d0:0c:67:af:ac:0c:80:53:bf:cd a3:80:76:cf:3e:14:19:99:5c:24:b4:fc:b0:42:8d:5a 03:5d:04:a5:85:c7:fe:e3:d4:30:6c:4c:26:90:76:c5 3e:a0:dc:a7:53:a7:eb:13:60:78:44:b3:0a:b2:77:0c 46:19:96:ea:d2:46:82:9c:11:2c:a5:e2:a1:57:38:f4 8e:4d:74:4f:f9:41:dd:11:f4:c2:f5:9f:b7:9a:93:7d a7:f8:f3:dd:2e:08:6a:25:75:79:f3:63:e5:09:1f:bd 6a:38:45:85:f0:63:54:c0:08:68:41:15:66:a4:e3:84 49:7e:e5:c5:c7:6c:d3:c7:be:d5:5a:df:1a:1d:55:f8 35:73:bb:e3:ea:f7:66:af:d9:09:72:ca:17:5f:80:09 99:6a:49:e3:8b:f2:72:56:ac:f8:ba:60:49:d5:80:2a 07:e6:17:88:86:e4:3c:89:cd:af:2b:66:a1:af:53:f4 66:21:30:a3:22:af:a9:11:6e:98:e0:f7:6d:ef:8a:32 e9:0b:a4:82:7b:7b:db:2d:90:8e:bd:e4:54:04:a4:52 e8:cf:f6:2e:9b:97:46:ab:cb:38:06:23:33:db:42:0c 25:41:5a:d7:02:15:07:c6:e8:86:0b:a6:d7:7d:81:16 bd Exponent (bits 24): 01:00:01 Extensions: Basic Constraints (critical): Certificate Authority (CA): TRUE Key Purpose (not critical): Time stamping. Key Usage (critical): Certificate signing. Subject Key Identifier (not critical): 7a596f6dea4080e89c9e78a698d7126cd63dafa7 Other Information: Public Key ID: 7a596f6dea4080e89c9e78a698d7126cd63dafa7 Public key's random art: +--[ RSA 2048]----+ | | | . . | | . . . | | o . . | | . .+. S o | | =o..o. + . . | | o.o= .oo . o o | | oo+. .o o o | |o... E+ .o | +-----------------+

      Is the above information ok? (y/N): y

      Signing certificate...
    • Add the Example LTD Internal ROOT CA as trusted in *ca-certificates:

      mkdir /usr/share/ca-certificates/extra
      cp /usr/share/ca-certificates/extra
      dpkg-reconfigure ca-certificates

      Add the extra/ CA as a trusted CA.

  • Configure slapd:

    dpkg-reconfigure slapd
    • Omit OpenLDAP server configuration? No
    • DNS domain name:
    • Organization name: Example LTD
    • Administrator password: ***
    • Verify password: *****
    • Database backend to use: MDB
    • Do you want the database to be removed when slapd is purged? No
    • Move old database? Yes
    • Allow LDAPv2 protocol? No
  • Configure TLS on LDAP:

    • Create a key for

      certtool --generate-privkey --outfile
      Generating a 2048 bit RSA private key...
    • Create a key for

      certtool --generate-certificate --load-privkey --outfile --load-ca-certificate --load-ca-privkey
      Generating a signed certificate...
      Please enter the details of the certificate's distinguished name. Just press enter to ignore a field.
      Common name:
      Organizational unit name: IT
      Organization name: Example LTD
      Locality name: Limassol
      State or province name: Limassol
      Country name (2 chars): CY
      Enter the subject's domain component (DC): 
      This field should not be used in new certificates.
      Enter the certificate's serial number in decimal (default: 6295762607454361711):

      Activation/Expiration time. The certificate will expire in (days):

      Extensions. Does the certificate belong to an authority? (y/N): Is this a TLS web client certificate? (y/N): Will the certificate be used for IPsec IKE operations? (y/N): Is this a TLS web server certificate? (y/N): Enter a dnsName of the subject of the certificate: Enter a URI of the subject of the certificate: Enter the IP address of the subject of the certificate: Enter the e-mail of the subject of the certificate: Will the certificate be used for signing (required for TLS)? (Y/n): Will the certificate be used for encryption (not required for TLS)? (Y/n): X.509 Certificate Information: Version: 3 Serial Number (hex): 575f0abc2f81186f Validity: Not Before: Mon Jun 13 19:35:45 UTC 2016 Not After: Thu Jun 11 19:36:29 UTC 2026 Subject:,OU=IT,O=Example LTD,L=Limassol,ST=Limassol,C=CY, Subject Public Key Algorithm: RSA Algorithm Security Level: Medium (2048 bits) Modulus (bits 2048): 00:d0:15:8e:02:90:5f:4a:9f:90:ea:1e:35:e6:4b:eb a9:8c:e5:bf:68:ec:83:0e:49:5b:d1:f0:08:4b:ac:b0 31:d2:e0:a7:eb:18:d3:ee:b8:38:b7:c4:0a:cc:97:cc b6:ac:2d:29:c8:a8:c4:7c:cc:f1:36:5a:e9:6b:52:f5 1e:e5:4f:90:67:34:1f:8c:a8:17:72:ee:40:87:ba:ae 8b:f8:4f:f8:be:51:ee:ea:d5:e4:17:63:79:22:41:c0 19:43:33:55:bb:46:80:5c:b8:16:18:fa:fb:17:58:c2 ed:d2:14:10:3b:57:5d:de:7f:29:ab:66:c2:81:87:05 f7:b7:27:78:a9:c0:8e:4f:1c:3f:66:6f:dd:43:26:9f 84:59:fb:c7:21:3c:62:4f:8d:4a:25:ab:7e:f0:5f:7e df:97:f7:79:f8:c7:2d:c8:5a:7a:de:ea:5b:c7:bd:e9 12:17:56:d3:47:ff:eb:fa:b5:6f:d9:56:8f:c7:e8:7a 46:92:75:cc:ff:de:0e:88:49:7d:d7:dd:6e:8d:3f:57 fa:0a:7a:3b:80:ec:0e:10:dd:70:d5:9a:8d:91:ce:72 44:06:21:d2:9d:e9:b8:91:13:68:4c:fc:e2:bb:4d:a8 97:ed:e9:a4:98:5d:e7:c0:ef:3e:9d:30:28:de:bd:10 01 Exponent (bits 24): 01:00:01 Extensions: Basic Constraints (critical): Certificate Authority (CA): FALSE Key Usage (critical): Digital signature. Key encipherment. Subject Key Identifier (not critical): 6d8a173de01efa11a892dda76ccd7abc609a2707 Authority Key Identifier (not critical): 7a596f6dea408aa89c9e78a698d7126cd63dafa7 Other Information: Public Key ID: 6d8a173de01efa00a892dda67ccd7abc609a2707 Public key's random art: +--[ RSA 2048]----+ | | | | | . | | . + | | A = | | +Y= . | | oo+kk+ | | iii==o* | | .=B**o. | +-----------------+

      Is the above information ok? (y/N): y

      Signing certificate...
    • Enable LDAPS in /etc/default/slapd:

      SLAPD_SERVICES="ldap:/// ldapi:/// ldaps:///"
    • Copy the certficate and apply permissions

      mkdir /etc/ldap/ssl
      cp /etc/ldap/ssl
      cp /etc/ldap/ssl
      chown -R openldap:openldap /etc/ldap/ssl/
    • Create a olcSSL.ldif file:

      mkdir /etc/ldap/custom_ldifs/
      cd /etc/ldap/custom_ldifs/
      cat > olcSSL.ldif << EOF dn: cn=config changetype: modify add: olcTLSCACertificateFile olcTLSCACertificateFile: /etc/ssl/certs/ca-certificates.crt - add: olcTLSCertificateKeyFile olcTLSCertificateKeyFile: /etc/ldap/ssl/ - add: olcTLSCertificateFile olcTLSCertificateFile: /etc/ldap/ssl/ EOF
    • Import the TLS configuration:

      ldapmodify -Y EXTERNAL -H ldapi:/// -f olcSSL.ldif

      Verify with:

      slapcat -n0 | grep -i tls
      olcTLSCACertificateFile: /etc/ssl/certs/ca-certificates.crt
      olcTLSCertificateFile: /etc/ldap/ssl/
      olcTLSCertificateKeyFile: /etc/ldap/ssl/
    • Restart and verify slapd:

      systemctl restart slapd
      netstat -lnptu | grep slapd
      tcp        0      0   *               LISTEN      27665/slapd     
      tcp        0      0   *               LISTEN      27665/slapd     
      tcp6       0      0 :::636                  :::*                    LISTEN      27665/slapd     
      tcp6       0      0 :::389                  :::*                    LISTEN      27665/slapd 

Setup Apache

  • Install Apache with PHP:

    apt -y install apache2 libapache2-mod-php5 php5-ldap php5-mcrypt php5-intl php-pear

Setup Let’s Encrypt:

NOTE: this step is only necessary if you have a public facing service

  • Setup Debian jessie backports:

    cat >> /etc/apt/sources.list << EOF
    # jessie backports
    deb jessie-backports main
    deb-src jessie-backports main
  • Run apt update

  • Install Let’s Encrypt utility, certbot:

    apt -y install python-certbot-apache -t jessie-backports
  • Generate a certificate for all the domain

    certbot run -d

    In the TUI add the email and agree to the ToS. Use 000-default.conf for now.

  • Download and trust all Let’s Encrypt Root and Intermediate CA certificates:

    for i in {1..4}; do wget$i-cross-signed.pem; done
    cp *.pem /usr/share/ca-certificates/extra/
    for f in *.pem; do cp -- "$f" "/usr/share/ca-certificates/extra/${f%.pem}.crt"; done
    dpkg-reconfigure ca-certificates # Select all the newlly added CA certs

Setup FusionDirectory

  • Setup Fusiondirectory Repo:

    gpg --keyserver --recv-key 62B4981F 
    gpg --export -a "Fusiondirectory Archive Manager <>" > FD-archive-key
    apt-key add FD-archive-key
    echo '# fusiondirectory repository' > /etc/apt/sources.list.d/fusiondirectory.list
    echo 'deb jessie main' >> /etc/apt/sources.list.d/fusiondirectory.list
    echo 'deb-src jessie main' >> /etc/apt/sources.list.d/fusiondirectory.list
    apt update
  • Install FusionDirectory:

    apt -y install fusiondirectory fusiondirectory-schema
  • Insert core FusionDirectory schemas into *slapd



    fusiondirectory-insert-schema -l
  • Create a Fusiondirectory Apache vhost (/etc/apache2/sites-available/

    <VirtualHost *:80>
        Redirect "/" ""
        ErrorLog ${APACHE_LOG_DIR}/ldap-error.log
        CustomLog ${APACHE_LOG_DIR}/ldap-access.log combined
    <IfModule mod_ssl.c>
        <VirtualHost *:443>
                DocumentRoot /usr/share/fusiondirectory/html
                ErrorLog ${APACHE_LOG_DIR}/ldap-error.log
                CustomLog ${APACHE_LOG_DIR}/ldap-access.log combined
                SSLEngine on
                SSLCertificateFile      /etc/letsencrypt/live/
                SSLCertificateKeyFile   /etc/letsencrypt/live/
                <FilesMatch "\.(cgi|shtml|phtml|php)$">
                                SSLOptions +StdEnvVars
                <Directory /usr/lib/cgi-bin>
                                SSLOptions +StdEnvVars
                BrowserMatch "MSIE [2-6]" \
                                nokeepalive ssl-unclean-shutdown \
                                downgrade-1.0 force-response-1.0
                BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
                <IfModule mod_php5.c>
                <Location />
                    php_admin_flag engine on
                    php_admin_flag register_globals off
                    php_admin_flag allow_call_time_pass_reference off
                    php_admin_flag expose_php off
                    php_admin_flag zend.ze1_compatibility_mode off
                    php_admin_flag register_long_arrays off
                    php_admin_value upload_tmp_dir /var/spool/fusiondirectory/
                    php_admin_value session.cookie_lifetime 0
                    #Include /etc/fusiondirectory/fusiondirectory.secrets
                <Directory /usr/share/fusiondirectory/html/>
                    Order Allow,Deny
                    # Insert your public IPs here
                    Allow from
                    Allow from
  • Enable mod_ssl, and disable 000-default and default-ssl:

    a2enmod ssl
    a2dissite default-ssl
    a2dissite 000-default
    systemctl restart apache2
  • Setup FusionDirectory:

    • Install optional prerequisities:

      apt -y install php-mdb2
    • Point your Browser to:
    • Create a temporary token for the setup (taken from the first setup webpage):

      echo -n r9l1srnu0rvdeca4k826nq4e05 > /var/cache/fusiondirectory/fusiondirectory.auth 

      Click ‘Next’

    • In the ‘Language setup’ select ‘English’ and press ‘Next’.

    • If everything is ‘OK'(Green) on the ‘Installation check’ click ‘Next’

    • On the ‘LDAP connection setup’:

      • Location name: default
      • Connection URI: ldap://
      • TLS connection: Yes
      • Admin DN: cn=admin(,dc=example,dc=com)
      • Admin password: *****
      • LDAP schema check:
        • Enable schema validation when logging in: Yes
    • Keep defaults in ‘Look and feel’ except ‘Timezone’:

      • Timezone: America/Los_Angeles
    • Keep all the defaults in ‘Password settings’ except this:

      • Password minimum length: 8
    • In the ‘SSL’ field use these:

      • Key path: /etc/ldap/ssl/
      • Certificate path: /etc/ldap/ssl/
      • CA certificate path: /etc/ssl/certs/ca-certificates.crt

      Click ‘Next’ when done.

    • In the ‘LDAP inspection’ page:

      • Press ‘Migrate’ (twice) in the ‘Inspecting object classes in root object’ option

      • Press ‘Create’ in the ‘Checking for super administrator’ option’, fill the fields, and ‘Apply’ when done:

        • User ID: ldapadmin
        • Password: ***
        • Password (again): ***
      • In the ‘Checking for default ACL roles and groups’ field, press ‘Migrate’
    • From the ‘Finish – write the configuration file’, download the configuration file on your PC

    • Copy the configuration file from your PC to

      scp fusiondirectory.conf
    • Apply the correct permissions to the /etc/fusiondirectory/fusiondirectory.conf file:

      fusiondirectory-setup --check-config
      Checking FusionDirectory's config file
      /etc/fusiondirectory/fusiondirectory.conf exists…
      /etc/fusiondirectory/fusiondirectory.conf is not set properly, do you want to fix it ?:  [Yes/No]?
    • Click ‘Next’ when done.
  • Use encrypted passwords in fusiondirectory.conf:

    • Enable the headers module in Apache:

      a2enmod headers
      systemctl restart apache2
    • Encrypt passwords in fusiondirectory.conf:

      fusiondirectory-setup --encrypt-passwords
    • Uncomment the following line in /etc/apache2/sites-enabled/

      Include /etc/fusiondirectory/fusiondirectory.secrets
    • Restart Apache:

      systemctl restart apache2
    • If everything works as expected remove /etc/fusiondirectory/fusiondirectory.conf.orig

      rm /etc/fusiondirectory/fusiondirectory.conf.orig
  • Allow ‘.’ (dot) in usernames:

    • After everything is set, login as ldapadmin
    • Go to ‘Configuration’
    • Press the ‘Edit’ button at the bottom of the page
    • Un-tick the ‘Strict naming policy’ option and save.

Installing essential FusionDirectory plugins

  • Setup LDAP related plugins:

    apt -y install fusiondirectory-plugin-ldapdump fusiondirectory-plugin-ldapmanager
  • Setup the DSA plugin for managing service accounts:

    apt -y install fusiondirectory-plugin-dsa fusiondirectory-plugin-dsa-schema
    fusiondirectory-insert-schema -i /etc/ldap/schema/fusiondirectory/dsa-fd-conf.schema
    • Allow the service accounts to read and write the password. First create the ACL definition:

      cat > /etc/ldap/custom_ldifs/service_accounts_acl.ldif << EOF
      dn: olcDatabase={1}mdb,cn=config
      changetype: modify
      delete: olcAccess
      add: olcAccess
      olcAccess: {0}to dn.subtree="dc=example,dc=com" attrs=userPassword
        by self write
        by dn.base="cn=admin,dc=example,dc=com" write
        by dn.children="ou=dsa,dc=example,dc=com" write
        by anonymous auth
        by * none
      add: olcAccess
      olcAccess: {1}to dn.subtree="ou=people,dc=example,dc=com"
        by self read
        by dn.base="uid=test.user,ou=people,dc=example,dc=com" write
        by dn.base="cn=admin,dc=example,dc=com" write
        by dn.children="ou=dsa,dc=example,dc=com" read
        by anonymous auth
        by * none
      add: olcAccess
      olcAccess: {2}to attrs=userPassword,shadowLastChange
        by self write
        by anonymous auth
        by dn="cn=admin,dc=example,dc=com" write
        by * none
      add: olcAccess
      olcAccess: {3}to dn.subtree="dc=example,dc=com"
        by self read
        by dn.base="cn=admin,dc=example,dc=com" write
        by dn.children="ou=dsa,dc=example,dc=com" write
        by * none
      add: olcAccess
      olcAccess: {4}to dn.base=""
        by * none

      NOTE: Add two spaces after each ‘by‘ in the ldif above or you will spend endless hours in troubleshooting!

    • Apply the ACL

      ldapadd -c -Y EXTERNAL -H ldapi:/// -f /etc/ldap/custom_ldifs/service_accounts_acl.ldif
  • Setup the Systems plugin:

    apt -y install fusiondirectory-plugin-systems fusiondirectory-plugin-systems-schema
    fusiondirectory-insert-schema -i /etc/ldap/schema/fusiondirectory/service-fd.schema
    fusiondirectory-insert-schema -i /etc/ldap/schema/fusiondirectory/systems-fd-conf.schema
    fusiondirectory-insert-schema -i /etc/ldap/schema/fusiondirectory/systems-fd.schema
    • Setup a new server:

      • Name:
      • Description: Communications Server
      • Location: My Datacenter
      • Base: /

      • IP-address:
      • MAC-address: 04:01:05:d6:63:02
    • From the ‘Services’ tab setup an LDAP service on the server

You are finished. You can now start connecting services to your LDAP setup like mail or asterisk.


I have been using Skelleton‘s guide1 to setup opendmarc on some mail server I am building.

My problem is the version of opendmarc that comes with Debian is 1.3.0 and this version has a bug2 which fails to honor the IgnoreAuthenticatedClients directive.

This is an attempt to build3 the newest version, 1.3.1, for Debian jessie.

Prepare the environment

  • Install all necessary packages:

    $ sudo apt -y install pbuilder debootstrap devscripts packaging-dev debian-keyring
  • Prepare a Debian jessie build environment:

    $ sudo pbuilder create --debootstrapopts --variant=buildd --mirror --distribution jessie --architecture amd64 --components main --debbuildopts -mJohn Doe \<\>

Prepare the Debian environment for opendmarc 1.3.1

  • Download and extract the package:

    $ wget
    $ tar xvzf opendmarc-1.3.1.tar.gz
    $ cd opendmarc-1.3.1/
  • Prepare for Debian packaging:

    $ DEBFULLNAME="John Doe" DEBEMAIL="" dh_make -s -y --createorig
    • Rename the debian folder:

      $ mv debian debian.orig
  • Shamelessly copy *debian/** from the original:

    $ cd /tmp/
    $ apt-get source opendmarc
    $ cd opendmarc-1.3.1+dfsg/
    $ cp -a debian/ ~/opendmarc-1.3.1
  • Optional steps:

    • Change the Author name to yours in debian/control

    • Restore the debian/changelog file:

      $ cp debian.orig/changelog debian/
    • Get rid of the debian.orig folder:

      $ mv debian.orig/ ..
    • Edit the debian/changelog file with dch -e:

      opendmarc (1.3.1-1) unstable; urgency=medium
        * Initial release: To fix the IgnoreAuthenticatedClients issue:
       -- John Doe <> Fri, 29 Apr 2016 13:43:22 +0300

Build opendmarc 1.3.1

  • Run pdebuild:

    $ pdebuild
  • You cab find the resultant debs under /var/cache/pbuilder/result/:

    $ ls -la /var/cache/pbuilder/result/
    total 868
    drwxr-xr-x 2 root      root        4096 Απρ  29 13:54 .
    drwxr-xr-x 8 root      root        4096 Απρ  29 12:56 ..
    -rw-r--r-- 1 theodotos theodotos  38534 Απρ  29 13:54 libopendmarc2_1.3.1-1_amd64.deb
    -rw-r--r-- 1 theodotos theodotos  64210 Απρ  29 13:54 libopendmarc-dev_1.3.1-1_amd64.deb
    -rw-r--r-- 1 theodotos theodotos   2348 Απρ  29 13:54 opendmarc_1.3.1-1_amd64.changes
    -rw-r--r-- 1 theodotos theodotos  75890 Απρ  29 13:54 opendmarc_1.3.1-1_amd64.deb
    -rw-rw-r-- 1 theodotos theodotos    846 Απρ  29 13:54 opendmarc_1.3.1-1.dsc
    -rw-r--r-- 1 theodotos theodotos 663859 Απρ  29 13:54 opendmarc_1.3.1-1.tar.gz
    -rw-r--r-- 1 theodotos theodotos  17136 Απρ  29 13:54 rddmarc_1.3.1-1_all.deb

You can now copy the debs over your mail server and test them.

Update: I did this before I had discovered that opendmarc 1.3.1 is in Debian jessie backports4. But an interesting drill nevertheless.


These are the instructions for installing an ORCID5 authentication node. We will be using the simple-orcid-auth-node6 developed by the ORCID organization.


  • An Ubuntu 16.04 server machine but works on 14.04x with some minor changes.
  • A FQDN, let’s say
  • Server IP is in our case.
  • Create an orcid user: sudo useradd -r -m -d /var/www/html/orcid orcid.
  • For Ubuntu 14.04 it is better to use /var/www/orcid instead of /var/www/html/orcid.
  • Also use service <servicename> restart on 14.04.x instead of systemctl restart <service>.

Installing simple-orcid-auth-node

  • Install necessary packages (as a privileged user):

    $ sudo apt -y install nginx nodejs npm

    NOTE: If you are using Ubuntu 14.04.x do not install the node package. This package is completely unrelated with nodejs.7

  • Download and extract simple-orcid-auth-node (as the orcid user):

    sudo su - orcid
    tar xvzf master.tar.gz
  • Install the application:

    $ cd simple-orcid-auth-node-master/
    $ npm install
  • Test run the application (as the orcid user):

    $ nodejs client-app.js
    server started on 8000

    Looks OK. Now point your Hit CTRL^C and move on.

    NOTE: If you prefer using the legacy node client-app.js invocation, you need to install the nodejs-legacy package as well.

Setting ORCID as an autostart service

  • Autostart using systemd8 (Ubuntu 16.04):

    • Create the /etc/systemd/system/orcid.service service definition (as the root user):

      $ cat > /etc/systemd/system/orcid.service << EOF
      ExecStart=/usr/bin/nodejs /var/www/html/orcid/simple-orcid-auth-node-master/client-app.js
      [Install] EOF
    • Reload systemd and start the service:

      $ sudo systemctl daemon-reload
      $ sudo systemctl start orcid.service
    • Verify that the service is started:

      $ sudo systemctl status orcid.service
      ● orcid.service
      Loaded: loaded (/etc/systemd/system/orcid.service; disabled; vendor preset: enabled)
      Active: active (running) since Wed 2016-04-27 09:00:16 UTC; 37s ago
      Main PID: 11141 (nodejs)
      Tasks: 5 (limit: 512)
      Memory: 24.1M
      CPU: 268ms
      CGroup: /system.slice/orcid.service
         └─11141 /usr/bin/nodejs /var/www/html/orcid/simple-orcid-auth-node-master/client-app.js
      Apr 27 09:00:16 orcid systemd[1]: Started orcid.service. Apr 27 09:00:16 orcid orcid[11141]: server started on 8000
  • Autostart using sysv-init (Ubuntu 14.04.x):

    • Prepare a sysv-init startup script or use mine for convinience:

      $ cd /etc/init.d
      $ wget
      $ chmod +x orcid
      $ update-rc.d orcid enable
      $ update-rc.d orcid defaults

    Now orcid should be able to autostart after a reboot.

Setting up nginx

  • Prepare this configuration:

    $ cat > /etc/nginx/sites-available/orcid << EOF
    server {
        listen 80;     listen [::]:80 ipv6only=on;
        access_log /var/log/nginx/orcid.access.log;     error_log /var/log/nginx/orcid.error.log;
        location / {         proxy_pass http://localhost:8000/;         proxy_set_header Host \$host;         proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;     } } EOF
  • Enable the orcid site:

    $ cd /etc/nginx/sites-enabled/
    $ sudo ln -s /etc/nginx/sites-available/orcid
  • Uncomment the following line in /etc/nginx/nginx.conf9:

        server_names_hash_bucket_size 64;
  • Restart nginx:

    $ sudo systemctl restart nginx.service
  • Verify nginx with sudo systemctl status nginx.service

Now you can visit the site and test your setup

Going to production

The default simple-orcid-auth-node is using the sandbox ORCID service which is ideal for testing. This is how the configuration file (helpers/config.js) looks like:

module.exports = config = {
  // Config for OAuth2 
  CLIENT_SECRET: '0eafb938-020e-45a6-a148-3c222171d9d8',
  CODE_CALLBACK_URI: 'http://localhost:8000/authorization-code-callback',
  // General server config
  PORT: '8000',
  SERVER_IP: '',

This setup will not work in production. You have to modify the CLIENT_ID and CLIENT_SECRET variables with your own credentials and change the AUTHORIZE_URI and TOKEN_EXCHANGE_URI to point to the production ORCID services:

module.exports = config = {
  // Config for OAuth2 
  CLIENT_SECRET: '56d4eb21-6622-8483-3422-f53f3fs53sfs35f',
  CODE_CALLBACK_URI: 'http://localhost:8000/authorization-code-callback',
  // General server config
  PORT: '8000',
  SERVER_IP: '',

Restart nginx and orcid when done:

$ sudo systemctl restart nginx.service orcid.service


This article is about setting up you own ebook library with support for the OPDS catalog format . The COPS ebook catalog can read a Calibre library and expose it as a website. It is developed on PHP.


  • Prepare a Linux system. In this guide we are using Ubuntu 14.04.4.
  • Have a DNS A record pointing to the IP of your server.

Install necessary packages

$  sudo apt-get -y samba nginx php5-fpm php5-gd php5-sqlite php5-json php5-intl git

Setup a SAMBA share

Samba is needed for sharing the Calibre library directory with the library administrator. Alternatively you could use NFS or even OwnCloud.


It is a security risk to expose Samba on a public server. Restrict it through firewall or use OwnCloud instead.

  • Tweak the Samba configuration file (/etc/samba/smb.conf):

    #  unix password sync = yes
       unix password sync = no
    #  pam password change = yes
       pam password change = no
  • Add a Samba share for calibre (/etc/samba/smb.conf):

    path = /srv/calibre
    valid users = calibre
    write list = calibre
    read only = no
  • Restart Samba services:

    $ sudo service smbd restart ; sudo service nmbd restart
  • Add the calibre user:

    $ useradd -m -d /srv/calibre -s /usr/sbin/nologin calibre
    $ smbpasswd -a calibre

Setup Calibre

  • Now you should setup Calibre on your PC. On Debian/Ubuntu:

    $ sudo apt-get -y install calibre

    Windows users can download it from here:

  • Configure Calibre to use the calibre share as its catalog:

    • You can “mount” the calibre share on Linux or “map” the share on Windows.
    • Create an ebook Directory under the calibre share.
    • Create a new Calibre library inside the ebook directory. From the Calibre menu:
      • Callibre Library –> Switch/create library -> Create an empty Library at the new location and fill the path in the “New Location” text field.
    • If you get an error about “Corrupted database” just click ‘Yes” to rebuilt it.
    • Start adding books


  • Download the software:

    $ mkdir /var/www
    $ cd /var/www
    $ git clone
  • Setup COPS:

    Under the /var/www/cops/ directory, copy the config_default.php.example to config_default.php:

    $ cp config_local.php.example config_local.php

    Make the following changes in config_default.php:

        if (!isset($config))
            $config = array();
         * The directory containing calibre's metadata.db file, with sub-directories
         * containing all the formats.
         * BEWARE : it has to end with a /
        $config['calibre_directory'] = '/srv/calibre/ebooks/';
         * Catalog's title
        $config['cops_title_default'] = 'My Ebook Portal';
        $config['calibre_internal_directory'] = '/ebooks/';
        $config['cops_full_url'] = '';
        $config['cops_x_accel_redirect'] = 'X-Accel-Redirect';
         * use URL rewriting for downloading of ebook in HTML catalog
         * See README for more information
         *  1 : enable
         *  0 : disable
        $config['cops_use_url_rewriting'] = '1';

Setup nginx

  • Create an /etc/nginx/sites-available/

    server {
        listen 80 default_server;
        listen [::]:80 default_server ipv6only=on;
        access_log  /var/log/nginx/cops.access.log;
        error_log /var/log/nginx/cops.error.log;
        root   /var/www/cops;
        #index feed.php;
        index index.php;
        #Useful only for Kobo reader
        location /download/ {
              rewrite ^/download/(\d+)/(\d+)/.*\.(.*)$ /fetch.php?data=$1&db=$2&type=$3 last;
              rewrite ^/download/(\d+)/.*\.(.*)$ /fetch.php?data=$1&type=$2 last;
            #Can break loading the images - if you don't see anything, comment
            location ~ ^/images.*\.(gif|png|ico|jpg)$ {
                    expires 31d;
            #Can also break loading the images, comment if it happens
            location ~ .(js|css|eot|svg|woff|ttf)$ {
                    expires 31d;
        #Not necessarily correct, it depends on distro.
        location ~ \.php$ {
           try_files $uri =404;
           include /etc/nginx/fastcgi_params;
           fastcgi_param   SCRIPT_FILENAME  $document_root$fastcgi_script_name;
           fastcgi_pass    unix:/run/php5-fpm.sock;
        location /ebooks {
            root /srv/calibre;


    The feed.php setting was redirecting me to an XML site with this error: This XML file does not appear to have any style information associated with it. The document tree is shown below. So I am using index.php instead, as the index file.

  • Enable the site and disable the default:

    $ cd /etc/nginx/sites-enabled/
    $ sudo ln -s /etc/nginx/sites-available/
    $ sudo unlink default
  • Restart nginx and php5-fpm:

    $ sudo service php5-fpm restart ; sudo service nginx restart
  • Change permissions to let nginx write to the library:

    $ usermod -a -G calibre www-data
    $ chmod -R g+w /srv/calibre/ebooks/

Now you can navigate to and enjoy your newly created ebook library!


This guide describes how to upgrade your XstreamTec HTPC appliance from XBMC to KODI or re-install the system, in case of system corruption.

XstreamTec does not appear to have an official website but I have contacted them via Amazon and they promptly replied with instructions.


  • An XstreamTec HTPC media player.
  • A Linux system with an SD card slot.
  • A Windows PC or VM (optional).
  • An empty SD card (4GB minimum).

Install the recovery firmware

  1. Download the android recovery sd card image (use Google Chrome or Chromium):!wExHTJgC!XPuoFyhF_S-roTEhsMhQ8BLrfH4R5tXhp2jwaLF_o1M

    • Convert the image to raw format:

      If you extract the downloaded file (MATRICOM_MX2_115_FULL_AUG_09_2013.rar) you will get the image file (MATRICOM_MX2_115_FULL_AUG_09_2013.imgc). Alas this file has a peculiar format (.imgc) which is some kind of compressed raw image. I couldn’t figure out how to convert this to a raw (suitable for dd) image on Linux. To convert this to raw you need a Windows only utility called HDDRawCopy. So you will need a Windows system (WINE does not work for this) and use HDDRawCopy to convert the .imgc file to Raw/dd format.

      If you do not have a Windows machine, you can download the image I converted already, in .bz2 format from here: MATRICOM_MX2_115_FULL_AUG_09_2013.dd.bz2. Just extract it like this to get the raw image:

    $ cd ~/Downloads
    $ bzip2 -d MATRICOM_MX2_115_FULL_AUG_09_2013.dd.bz2
    • Prepare the SD card:

      Make sure you don’t have any useful data on the SD card!

      First verify that the SD card is inserted:

      $ cat /proc/partitions 
      major minor  #blocks  name
        8        0  488386584 sda
        8        1     524288 sda1
        8        2     249856 sda2
        8        3  487610368 sda3
       11        0    1048575 sr0
      252        0  487608320 dm-0
      252        1  483524608 dm-1
      252        2    4067328 dm-2
      179        0    7761920 mmcblk0
      179        1      71680 mmcblk0p1
      179        2     124928 mmcblk0p2
      179        3    7559168 mmcblk0p3

      Unmount all partitions on the SD card:

      $ sudo umount /dev/mmcblk0p*

      Now use fdisk and delete all partitions from the SD card:

      $ sudo fdisk /dev/mmcblk0
    • Dump the image on the SD card:

      After preparing the SD card we need to dump the raw image on it:

       $ sudo dd if=MATRICOM_MX2_115_FULL_AUG_09_2013.dd of=/dev/mmcblk0

      Be very careful with dd! If you specify the wrong device on the of= parameter you may destroy useful data on other devices, even you main hard disk!

Boot the recovery image

Now we need to go though these steps to load the recovery image:

  1. Power off the XstreamTec appliance.

  2. Insert the SD card, in the SD slot of the XstreamTec.

  3. Press the reset button. This is somewhat tricky. The reset button is inside the AV port of the XstreamTec so you will need a toothpick to press it.

  4. Power on the appliance, while keeping the reset button pressed. The system will enter the recovery installation procedure. Release the reset button when the recovery starts.

  5. Follow the on-screen instructions to load the Android recovery image. Then reboot into android and see if it boots correctly.

Install the newer version of the Android system

Now we need to install a more recent version of Android on the XstreamTec.

  1. Download the newer Android firmware:

    $ cd ~/Downloads
    $ wget
  2. Prepare the SD card:

    • Insert the SD card in your PC and check if it is mounted:

      $ df -hT | grep mmc
      /dev/mmcblk0p1              vfat      3,7G  100M  3,6G   3% /media/user/0E99-207A
    • Delete all previous files from the SD card:

      $ cd /media/user/0E99-207A
      $ rm -fr * 

      Once again make sure you don’t have any data you need on the SD card.

  3. Load the firmware on the SD card.

    Unzip the contents of the downloaded zip file ( on the SD card:

    $ cd /media/user/0E99-207A
    $ unzip ~/Downloads/

Boot the new Android firmware

Go through these steps agaon to load the new Android firmware:

  1. Power off the XstreamTec appliance.

  2. Insert the SD card in the SD slot of the XstreamTec.

  3. Press the reset button. Repeat the toothpick procedure as previously.

  4. Power on the appliance while keeping the reset button pressed. The system will enter the new Android firmware installation procedure. Release the reset button when the recovery starts.

  5. Follow the on-screen instructions to load the new Android firmware. Then reboot into the new Android and see if it boots correctly.

One would be tempted to keep the Android system and use XBMC or install Kodi on it. This way you can have Android and XBMC/Kodi on your XstreamTec appliance. Alas the XBMC/Kodi experience for Android is not as good as the one on OpenELEC. Trust me, if you need the full Kodi experience you need to install OpenELEC.

Install OpenELEC on the XstreamTec HTPC media player

  1. Download the OpenELEC firmware:

    $ cd ~/Downloads
    $ wget

    Update: There is a newer version at github.

  2. Prepare the SD card:

    • Insert the SD card in your PC and check if it is mounted:

      $ df -hT | grep mmc
      /dev/mmcblk0p1              vfat      3,7G  100M  3,6G   3% /media/user/0E99-207A
    • Delete all previous files from the SD card:

      $ cd /media/user/0E99-207A
      $ rm -fr * 
  3. Load the OpenELEC firmware on the SD card.

    Unzip the contents of the downloaded zip file ( on the SD card:

    $ cd /media/user/0E99-207A
    $ unzip ~/Downloads/

Boot the OpenELEC firmware

Once again repeat these steps to load the OpenELEC firmware:

  1. Power off the XstreamTec appliance.

  2. Insert the SD card in the SD slot of the XstreamTec.

  3. Press the reset button. Repeat the toothpick procedure as previously.

  4. Power on the appliance while keeping the reset button pressed. The system will enter the OpenELEC installation procedure. Release the reset button when the recovery starts.

  5. Follow the on-screen instructions to load the OpenELEC firmware. Then reboot into your freshly installed system and see if it works properly.

Enjoy your Kodi experience!