


Hardware setup:

The hardware is the following:
– board (APU) Intel DN2800MT
– RAM: 2 x 2 Go PC8500 DDR3 SODIMM
– Secondary ethernet: ST1000SMPEX (Mini PCI-E)
– Wifi: TP-Link TL-WDN4800 (PCI-E)
+ a laptop adapter (16V, 4A)
+ a small case




Software setup:

Picking softwares:


– OpenSSH as secure shell, for the administrator
– any dhcpd server to provide IPs on the fly
– Bind to act as DNS cache and manage the domain
– transmission-daemon plus my script to provide a networked BitTorrent client
– minidlna to make files available to non computer networked devices

Start with Debian netinst base install:







Setting up basic functionalities/networking after reboot:

First, we’ll install some useful utilities:

apt-get install lm-sensors hddtemp cpufrequtils debfoster etckeeper localepurge
ethtool emacs23-nox ntp wget




01:00.0 Ethernet controller: Intel Corporation 82574L Gigabit Network Connection


We’ll use hostapd to provide Wifi access.

apt-get install hostapd




## base

## wifi mode

## access with WPA PSK


touch /etc/hostapd/hostapd.deny


editing /etc/network/interface:

# internet
auto eth0 iface
allow-hotplug eth0
iface eth0 inet dhcp

# intranet (wired)
auto eth1 iface
eth1 inet static 

# intranet (wireless) 
auto wlan1 iface
wlan1 inet static


apt-get install isc-dhcp-server

In /etc/default/isc-dhcp-server:

INTERFACES="eth1 wlan1"

In /etc/dhcp/dhcpd.conf:

option domain-name "mynetworkname.ici";
option domain-name-servers;
option routers;

log-facility local7;

# wired
subnet netmask {

# wireless
subnet netmask {
option routers;



prepend domain-name-servers;
supersede domain-name "mynetworkname.ici";

We obviously need ip forwarding, editing /etc/sysctl.conf:


and also immediately doing a:


We also need iptables

apt-get install iptables-persistent
/etc/init.d/iptables-persistent save


ifup eth1
ifup wlan1
invoke-rc.d hostapd restart
invoke-rc.d isc-dhcp-server restart


Provide local (dynamic) domain name server:

apt-get install bind9

Set up forwarders with your ISP’s DNS (as in /etc/resolv.conf) in /etc/bind/named.conf.options. Don’t bother doing that, /etc/bind/named.conf.options will be automatically generated by a script installed at the latest step. Instead, remove it so the script will make sure it is set proper at its first run:

rm -f /etc/bind/named.conf.options

You need to create zones (named as you like) in /etc/bin/named.conf.local:

zone "mynetworkname.ici" {
type master;
notify no;
file "/etc/bind/db.mynetworkname.ici";
allow-update { key dhcpupdate; };

zone "" {
type master;
notify no;
file "/etc/bind/db.10.0.0";
allow-update { key dhcpupdate; };
cd /etc/bind && cp db.local db.mynetworkname.ici


$TTL    64800
@           IN      SOA      gate.mynetworkname.ici. root.mynetworkname.ici. (
2         ; Serial
604800         ; Refresh
86400         ; Retry
2419200         ; Expire
604800 )       ; Negative Cache TTL

IN      NS      nano.mynetworkname.ici.
mynetworkname.ici.                     IN      A
mynetworkname.ici.    IN    MX         10
nano        IN    A
gate            IN      CNAME   nano
cp db.255 db.10.0


; BIND reverse data file
@       IN    SOA    nano.mynetworkname.ici. root.mynetworkname.ici. (
1                     ; Serial
604800         ; Refresh
8600               ; Retry
2419200               ; Expire
604800 ) ; Negative Cache TTL         NS  nano.mynetworkname.ici.
1.0                        PTR nano.mynetworkname.ici.

Now we add support for dynamic updates:

cd /etc/dhcp


key dhcpupdate {
algorithm hmac-md5;



ddns-domainname "mynetworkname.ici";
ddns-rev-domainname "";
ddns-update-style interim;
ignore client-updates;
update-static-leases on;

key dhcpupdate {
algorithm hmac-md5;
zone mynetworkname.ici. {
key dhcpupdate;
zone {
key dhcpupdate;


chmod o-r /etc/bind/named.conf.local
chmod o-r /etc/dhcp/dhcpd.conf

invoke-rc.d isc-dhcp-server restart
invoke-rc.d bind9 restart

Put user data in place:


mkdir /srv/home /srv/common

We then add default dirs:



mkdir /etc/skel/samba

Make it accessible over Samba:


apt-get install samba libpam-smbpass


interfaces = eth1 wlan1
bind interfaces only = yes
security = user
invalid users = root
unix password sync = yes
pam password change = yes
map to guest = bad user
# discard filename mangling backward compatibility, see
mangle case = no
mangled names = no

comment = Données protégées
path = /srv/home/%S/samba
writable = yes

comment = Commun
path = /srv/common
browseable = yes
public = yes
force group = users
force user = nobody
guest ok = yes
writable = yes

comment = clef USB, etc
path = /media
browseable = yes
public = yes
force group = users
force user = nobody
guest ok = yes
writable = yes



@include common-password

Make it accessible with UPnP-AV/DLNA:

apt-get install minidlna



Once set up, we regenerate the database properly:

rm -f /var/lib/minidlna/files.db
invoke-rc.d minidlna restart

We add relevant iptables rules where SRC is the IP of your dlna client (you may want to alter this, for instance by using –source-range IP-IP instead of –src IP):

apt-get install iptables-persistent
iptables -A INPUT -i eth0 --src SRC -p udp --dport 1900 -j ACCEPT
iptables -A INPUT -i eth0 --src SRC -p tcp --dport 8200 -j ACCEPT
/etc/init.d/iptables-persistent save

Provide torrent client:

apt-get install transmission-daemon libtimedate-perl
invoke-rc.d transmission-daemon stop

mkdir /home/torrent
usermod -d /home/torrent Debian-transmission

cd /usr/local/bin && wget && chmod +x
cd /etc/cron.d && wget
cd /etc/cron.weekly && wget

Edit /etc/cron.d/torrent (uncomment, check pathes – you may want to add ~/watch/ instead of ~/watch if symlinks are involveed, etc).

Edit /etc/transmission-daemon/settings.json

"alt-speed-down": 120,
"alt-speed-enabled": false,
"alt-speed-up": 1,
"blocklist-enabled": true,
"message-level": 0,
"port-forwarding-enabled": true,
"rpc-authentication-required": false,
invoke-rc.d transmission-daemon start

And log rotation /etc/logrotate.d/torrent:

/srv/common/torrents/log {
rotate 2
su debian-transmission users

Provide basic info and management:

The following will provides reminders of upgrades to be performed.

apt-get install libapt-pkg-perl
cd /etc/cron.daily && wget && chmod +x apt-warn
phpsysinfo : basic system infos

phpsysinfo : basic system infos


cd /etc/init.d && wget && chmod +x php-fcgi && update-rc.d php-fcgi defaults
wget -O /usr/bin/ && wget -O /etc/init.d/perl-fcgi && chmod +x /usr/bin/ /etc/init.d/perl-fcgi && update-rc.d perl-fcgi defaults

mkdir /srv/www



root /srv/www;
index index.html index.htm index.php;
autoindex on;
server_name localhost nano nano.mynetworkname.ici;

# restrict to local wired network
deny all;

# pass the  scripts to FastCGI server listening on
fastcgi_index index.php;
include fastcgi_params;
location /sysadmin/ {
fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_na\
include fastcgi_params;


cgi.fix_pathinfo = 0;


define('PSI_BYTE_FORMAT', 'auto_binary');
define('PSI_SENSOR_PROGRAM', 'LMSensors');
define('PSI_HDD_TEMP', 'tcp');
define('PSI_SHOW_MOUNT_OPTION', false);
define('PSI_SHOW_NETWORK_INFOS', true);
sysadmin : admin unix/samba passwords and watch wifi connections

sysadmin : admin unix/samba passwords and watch wifi connections

Follows the specific sysadmin web interface:

cd /srv/www
mkdir sysadmin

cd /srv/www/sysadmin && wget
cd /usr/local/bin && wget
chgrp www-data /srv/www/sysadmin/
chmod +x /srv/www/sysadmin/ /usr/local/bin/
chmod o-rwx /srv/www/sysadmin/ /usr/local/bin/
mysql -e "CREATE DATABASE sysadmin"


my $db_password = "kdkadkda";


my $db_password = "kdkadkda";


invoke-rc.d nginx restart
invoke-rc.d php-fcgi restart
invoke-rc.d perl-fcgi restart

Both http://nano/sysinfo and http://nano/sysadmin should work. The sysadmin script allows to change, on-the-fly UNIX passwords, by sending random ones by mail. It means that anyone within the intranet could sniff them out. That obviously won’t do if your legit users aren’t trustworthy.


Create backup system:



mkfs.ext4 -L wd2Tdebian64bak /dev/sda7
mkdir /mnt/sysclone

Add /etc/cron.weekly/backup-system (based on


## system cloning
ignore="dev lost+found media proc run sys tmp srv"

case $orig in

# then proceed

# easy reminder of the last cloning run
date > /etc/.lastclone

# mount clone system
mount -L $dest $mount

# set up ignore list
for dir in $ignore; do
touch /$dir.ignore

# do copy
for dir in /*; do
if [ -d $dir ]; then
if [ ! -e $dir.ignore ]; then
# update if not set to be ignored
# otherwise just make sure the directory actually exists
rm $dir.ignore

# update filesystem data


# (sleep to avoid weird timeout after rsync)
sleep 10s

# then cleanup
umount $mount
fsck -a LABEL=$dest > /dev/null

## EOF

Final tuning: set mails, restrict SSH access, etc:


dpkg-reconfigure exim4-config


To achieve this easily, will plug OpenSSH into xinetd.


invoke-rc.d ssh stop
touch /etc/ssh/sshd_not_to_be_run


PermitRootLogin no
X11Forwarding no
AllowGroups staff
PasswordAuthentication no

We add the relevant user to the group:

adduser thisguy staff

Then we set up xinetd to run it:

apt-get install xinetd

Edit /etc/xinetd.d/ssh_intranet:

# should exists

# only from local wired network
service ssh
socket_type     = stream
protocol        = tcp
wait            = no
user        = root
bind            =
only_from    =
server          = /usr/sbin/sshd
server_args     = -i -o PasswordAuthentication=yes
log_on_success  = HOST USERID

# from local wireless network
service ssh
socket_type     = stream
protocol        = tcp
wait            = no
user        = root
bind            =
only_from       =
server          = /usr/sbin/sshd
server_args     = -i
log_on_success  = HOST USERID


This set up only access for intranet interfaces (eth1 and wlan1 if you named them as recommended in this page). Internet interface IP is obtained with DHCP so it would be a pain in the ass to keep it up to date, especially if we’re behind a dynamic IP. However, xinetd does not allow to set interface by device name but wants an IP. So we need to script this. And, at the same time, we’ll deal with Bind DNS forwarders so it does proper caching. So we’ll add /etc/dhcp/dhclient-exit-hooks.d/xinetd-bind:


# SSH over xinetd requires the IP to be hardcoded
if [ -n "$new_ip_address" ]; then 

    # change only if we have a new ip and if this one mismatch the old
    if [ "$new_ip_address" != "$old_ip_address" ] || 
         [ ! -e $XINETD_CONFFILE ]; then

        echo "# DO NOT EDIT, automatically generated by $0
# (IP changed from $old_ip_address to $new_ip_address)
# `date`
service ssh
  socket_type     = stream
  protocol        = tcp
  wait            = no
  user            = root
  bind            = $new_ip_address
  server          = /usr/sbin/sshd
  server_args     = -i
  cps             = 30 10
  per_source      = 5
  log_on_success  = HOST USERID


        # now reload xinetd
        invoke-rc.d xinetd restart >/dev/null 2>&1

# Bind DNS cache need forwarders similar to the content of resolv.conf
if [ -n "$new_domain_name_servers" ]; then
    # change only if we have DNS
    if [ "$new_domain_name_servers" != "$old_domain_name_servers" ] ||
        [ ! -e $XINETD_CONFFILE ]; then

         echo "// DO NOT EDIT, automatically generated by $0
// (IPs changed from $old_domain_name_servers to $new_domain_name_servers) 
// `date`
options {
        directory \"/var/cache/bind\";

        // ports to talk.  See

        // Uncomment the following block, and insert the addresses replacing 
        // the all-0's placeholder.

        forward first;
        forwarders {" > $BIND_CONFFILE

        # add valid forwarders
        for server in $new_domain_name_servers; do
            # (verbose) skip local ips
            if [ ! -n "`ifconfig | grep ":$server "`" ]; then 
                echo "                $server;" >> $BIND_CONFFILE
                echo "                //SKIP THIS LOCAL IP! $server;" >> $BIND_CONFFILE


        echo "        };

        auth-nxdomain no;    # conform to RFC1035
        listen-on-v6 { any; };

       # now reload bind
       # (this may be useles because another script may do that already)
       invoke-rc.d bind9 restart >/dev/null 2>&1

It should modify conffiles and restart daemons only if there is an actual change. You can test that it works properly doing:

ifdown eth0 && ifup eth0

Then you can make a few SSH login test and see results in /var/log/auth.log.


/etc/init.d/iptables-persistent save


Update 1: Yeah, just published and already patched. Ahem. I noticed that, on reboot, sometimes hostapd is not working as expected. Users can connect but never get an IP. The LSB  init script of hostapd looks odd to me, since it actually makes it starting before dhcpd. I modified /etc/init.d/hostapd so isc-dhcp-server $network gets in Required-Start and then ran rc-update.d hostapd.

Update 2: /media was configured to be served over Samba but no automount was set for USB mass storage devices. Here it is, (not thoroughly tested as I don’t use such devices much), edit /etc/udev/rules.d/80-removable-usb.rules:

ACTION=="add", SUBSYSTEMS=="usb", KERNEL=="sd*", ENV{ID_FS_TYPE}!="", SYMLINK+="usb%k"
ACTION=="add", SUBSYSTEMS=="usb", KERNEL=="sd*", ENV{ID_FS_TYPE}!="", RUN+="/bin/mkdir /media/usb%k"
ACTION=="add", SUBSYSTEMS=="usb", KERNEL=="sd*", ENV{ID_FS_TYPE}=="vfat|ntfs", ENV{mount_extra_options}="dmask=0000,fmask=0111,"
ACTION=="add", SUBSYSTEMS=="usb", KERNEL=="sd*", ENV{ID_FS_TYPE}!="", RUN+="/bin/mount -t auto -s -o $env{mount_extra_options}noatime,nodiratime,noexec,nodev /dev/usb%k /media/usb%k", OPTIONS="last_rule"
ACTION=="remove", SUBSYSTEMS=="usb", KERNEL=="sd*", ENV{ID_FS_TYPE}!="", RUN+="/bin/umount /media/usb%k"
ACTION=="remove", SUBSYSTEMS=="usb", KERNEL=="sd*", ENV{ID_FS_TYPE}!="", RUN+="/bin/rmdir /media/usb%k", OPTIONS="last_rule"

Update 3: I added /srv to the list of directories to be ignored by the backup script, as it contains data.

Update 4: Now /etc/xinet.d/ssh is split between ssh_intranet and ssh_internet, the later being generated by a script in /etc/dhcp/dhclient-exit-hooks.d/. This avoids us to hardcode IPs by hand. Still, it implies hardcoding IP in conffiles, so it must be kept in mind when doing major software upgrade that may imply conffile syntax change, etc.

Update 5: I noticed auto eth0 was missing in /etc/network/interfaces. I added it (and maybe Update 1 was related to that).

Update 6: I added sample firewall rules for minidlna.

Update 7: In case you have no static IP from your ISP, you may want to create a free account on no-ip and install a client:

apt-get install ddclient

And configure /etc/ddclient.conf

invoke-rc.d ddclient restart

Update 8: Now debian packages are provided, notably for torrents over SAMBA management.

Update 9: Use usual listen statement in /etc/nginx/site-available/default

Update 10: Deactivate Samba backward compatibility filename mangling

Reminder, needs to be changed checked whenever the server is relocated:


We avoided hardcoding IPs but it was not always possible. Yes we did. However, in case of an ISP/main network change, which usually implies IP changes, make sure the following are properly updated by the dhclient:

/etc/bind/named.conf.option: ISP DNS IPs as in /etc/resolv.conf
/etc/xinetd.d/ssh_internet: internet IP as provided by ifconfig

