We are all living in a technological wasteland.


Slitaz project – Part 6 – Load balancer

This last part will focus on the loadbalancers. These loadbalancers will balance the load over our four webnodes. Because I couldn’t get lvs working for heartbeat, I’ve created a simple python script which takes over the virtual IP. Basically the same functionality, only no pain in the ass with missing dependencies for compiling an open-source package.

Let’s start by prepping ‘loadbalancer1’, I will use IP to manage incoming virtual connections. And IP for loadbalancer1 and IP for loadbalancer 2.

/home/base/ip.sh loadbalancer1 192.168.1 201 1

Now before we can use HAProxy, we must disable port 80, which is default still open on the LighTTPD servers. Just edit ‘lighttpd.conf’ and change the default port to 81 (our admin instance).

nano /etc/lighttpd/lighttpd.conf
# Port, default for HTTP traffic is 80.
server.port = 81

Now we can start with HAProxy, grab the toolchain. As we need to compile.

tazpkg get-install slitaz-toolchain
tazpkg get-install python
tazpkg get-install fcron

It is possible that you recieve following error:

Installation of : fcron
Copying fcron...                                                     [ OK ]
Extracting fcron...                                                  [ OK ]
Extracting the pseudo fs... (lzma)                                   [ OK ]
Installing fcron... cp: can't create '/etc/init.d': File exists
                                                                     [ Failed ]
Removing all tmp files...                                            [ OK ]
fcron (3.0.4) is installed.

This is because the service file is called ‘init.d’ in the package, and not ‘fcron’.Which tries to install the startup folder. I provided a renamed copy of this on this site. If you wish to do it manually, unextract the fcron tazpkg. It contains a small lzma filesystem in which you will see the ‘init.d’ file.
Grabbing it from this site:

wget http://enira.net/wp-content/uploads/2012/07/fcron.txt -O /etc/init.d/fcron

Allow execute:

chmod +x /etc/init.d/fcron

Now let’s cleanup again:

tazpkg clean-cache

And let’s also grab our sources and make the application. I found that pcre is already installed so I can use the ‘USE_PCRE=1’ flag.

cd /home/base
wget http://haproxy.1wt.eu/download/1.4/src/haproxy-1.4.21.tar.gz
tar xzvf /home/base/haproxy-1.4.21.tar.gz
cd /home/base/haproxy-1.4.21
make TARGET=linux26 USE_PCRE=1 ARCH=i386
make install

And a little bit of cleaning.

cd /
rm -rf /home/base/haproxy-1.4.210
rm /home/base/haproxy-1.4.21.tar.gz

Now it’s time to make our configuration file. I will place this in ‘/etc/haproxy/haproxy.conf’.

mkdir /etc/haproxy
nano /etc/haproxy/haproxy.conf

So now this is the configuration file for haproxy. I defined my gluster nodes and mysql servers too as a backend machine. This is easy so I can get a quick view of the ‘slitaz farm’ health on ‘’ or ‘’.

        maxconn 4096
	pidfile /var/run/haproxy.pid
        mode http
        timeout connect 5000ms
        timeout client 50000ms
        timeout server 50000ms
frontend http
        bind *:80
	balance leastconn 
        default_backend webnodes
backend loadbalancers
        stats enable
        server loadbalancer1 check
        server loadbalancer2 check
backend webnodes
	stats enable
	stats auth slitaz:slitaz
        stats uri /stats
      	option httpclose
      	option forwardfor
	server webnode1 weight 1 maxconn 512 check
	server webnode2 weight 1 maxconn 512 check
	server webnode3 weight 1 maxconn 512 check 
	server webnode3 weight 1 maxconn 512 check 
backend storage
        stats enable
	server glusternode1 check
	server glusternode2 check
	server glusternode3 check
	server glusternode4 check
	server glusterclient check
backend mysql
        stats enable
	server mysqlmaster check
	server mysqlslave check

Anyway now this is over, it’s time to make a service script.

nano /etc/init.d/haproxy
# /etc/init.d/haproxy: Start, stop and restart haproxy loadbalancer on SliTaz,
# at boot time or with the command line. Daemons options are configured
# with /etc/daemons.conf
. /etc/init.d/rc.functions
. /etc/daemons.conf
DESC="load balancer"
case "$1" in
    if active_pidfile $PIDFILE haproxy ; then
      echo "$NAME already running."
      exit 1
    echo -n "Starting $DESC: $NAME... "
    if ! active_pidfile $PIDFILE haproxy ; then
      echo "$NAME is not running."
      exit 1
    echo -n "Stopping $DESC: $NAME... "
    kill `cat $PIDFILE`
    rm $PIDFILE
    if ! active_pidfile $PIDFILE haproxy ; then
      echo "$NAME is not running."
      exit 1
    echo -n "Restarting $DESC: $NAME... "
    kill `cat $PIDFILE`
    rm $PIDFILE
    sleep 2
    echo ""
    echo -e "\033[1mUsage:\033[0m /etc/init.d/`basename $0` [start|stop|restart]"
    echo ""
    exit 1
exit 0

Add rights to it:

chmod +x /etc/init.d/haproxy

Now let’s edit the deamon config file:

nano /etc/daemons.conf

And add the line:

# HAproxy options.
HAPROXY_OPTIONS="-f /etc/haproxy/haproxy.conf"

And edit our start up rcS file.

nano /etc/rcS.conf

Also add the haproxy and crontabs to the services:

RUN_DAEMONS="dbus hald slim firewall dropbear lighttpd haproxy fcron"

Now let’s add the heartbeat service. For this I created a small script with python (thats why you need to install python at the beginning of this post).

nano /home/base/heartbeat.py
#! /usr/bin/python
import socket
import fcntl
import struct
import array
import os
import time
import datetime
MASK = ""
VIRTUAL_IFACE = "eth0:0"
def all_interfaces():
    max_possible = 128  # arbitrary. raise if needed.
    bytes = max_possible * 32
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    names = array.array('B', '\0' * bytes)
    outbytes = struct.unpack('iL', fcntl.ioctl(
        0x8912,  # SIOCGIFCONF
        struct.pack('iL', bytes, names.buffer_info()[0])
    namestr = names.tostring()
    return [namestr[i:i+32].split('\0', 1)[0] for i in range(0, outbytes, 32)]
def get_ip_address(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(
        0x8915,  # SIOCGIFADDR
        struct.pack('256s', ifname[:15])
t0 = datetime.datetime.now()
for num in range(LOOP_EXECUTE):
        interfaces = all_interfaces()
        virtual = False
        for interface in interfaces:
                ip = get_ip_address(interface)
                if interface == VIRTUAL_IFACE:
                        # we found a virtual interface
                        virtual = True
        # Ping and see if the virtual works
        response = os.system("ping -c 1 -W " + str(LOOP_PING) + " " + VIRTUAL)
        if response == 0:
                print "Virtual responding... done"
                print "Virtual not responding .. binding"
                os.system("ifconfig " + VIRTUAL_IFACE + " " + VIRTUAL + " netmask " + MASK + " up")
        print "Execution: " + str(datetime.datetime.now() - t0) +"s"

Add the script to the crontab:

fcrontab -u root -e

press ‘i’ and add:

@ 1 /usr/bin/python /home/base/heartbeat.py >> /dev/null

Quit by pressing: ‘:’, ‘w’, ‘q’

To view your cron jobs type:

fcrontab -u root -l

Now shutdown the server and copy the loadbalancer1. This will function as loadbalancer2:

/home/base/ip.sh loadbalancer2 192.168.1 202 1

Start loadbalancer1 again and you should now be balancing connections.

You should see HAProxy stats at loadbalancer1 (username: slitaz, password:slitaz) or loadbalancer2 (username: slitaz, password:slitaz)


(As you can see from this stats page example glusterclient and loadbalancer1 is down. Easy no?)

Now you can connect to the virtual IP too, it will redirect to one of our four nodes:

Now it’s time to test the loadbalancer. Find the loadbalancer which has ‘eth0:0’ (our virtual interface).

root@loadbalancer1:~# ifconfig
eth0      Link encap:Ethernet  HWaddr 00:0C:29:0E:AC:A0
          inet addr:  Bcast:  Mask:
          RX packets:2144 errors:0 dropped:0 overruns:0 frame:0
          TX packets:2937 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:150148 (146.6 KiB)  TX bytes:201556 (196.8 KiB)
          Interrupt:19 Base address:0x2000
eth0:0    Link encap:Ethernet  HWaddr 00:0C:29:0E:AC:A0
          inet addr:  Bcast:  Mask:
          Interrupt:19 Base address:0x2000
lo        Link encap:Local Loopback
          inet addr:  Mask:
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:383 errors:0 dropped:0 overruns:0 frame:0
          TX packets:383 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:21900 (21.3 KiB)  TX bytes:21900 (21.3 KiB)

Once you found it, shut it down or reboot it. (In my case loadbalancer1)

C:\Users\Enira>ping -t
Pinging with 32 bytes of data:
Reply from bytes=32 time=492ms TTL=64
Reply from bytes=32 time

As you can see the timeouts occur when I rebooted the machine. And an ifconfig on loadbalancer2 clearly shows that the has taken over the virtual eth0:0 interface:

root@loadbalancer2:~# ifconfig
eth0      Link encap:Ethernet  HWaddr 00:0C:29:DB:4B:CF
          inet addr:  Bcast:  Mask:
          RX packets:6551 errors:0 dropped:0 overruns:0 frame:0
          TX packets:9197 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:457143 (446.4 KiB)  TX bytes:641346 (626.3 KiB)
          Interrupt:19 Base address:0x2000
eth0:0    Link encap:Ethernet  HWaddr 00:0C:29:DB:4B:CF
          inet addr:  Bcast:  Mask:
          Interrupt:19 Base address:0x2000
lo        Link encap:Local Loopback
          inet addr:  Mask:
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:1119 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1119 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:61932 (60.4 KiB)  TX bytes:61932 (60.4 KiB)

That’s it, for now. And the VMWare images: loadbalancers.7z (67.1 MB)

No Comments |

Slitaz project – Part 5 – Web cluster nodes

So now we have our file storage and our database. Time to start on the front-end layer: the web clusters. These web clusters will be running LighTTPD which we previously installed.

For our nodes I will use the following IP scheme:


We start by preparing webnode1, which is a copy of our base image we made in part 1.

/home/base/ip.sh webnode1 192.168.1 211 1

Install GlusterFS on this webnode, we need it for accessing the data cluster. I am not going to explain this anymore. (For more info see: Slitaz project – Part 2 – Cluster storage nodes (GlusterFS))

tazpkg get-install flex 
tazpkg get-install python
tazpkg get-install readline-dev
tazpkg get-install mpc-library
tazpkg get-install elfutils
tazpkg get-install openssl-dev
tazpkg get-install slitaz-toolchain
tazpkg clean-cache
cd /home/base
wget http://download.gluster.org/pub/gluster/glusterfs/3.3/3.3.0/glusterfs-3.3.0.tar.gz
tar xzvf /home/base/glusterfs-3.3.0.tar.gz
cd /home/base/glusterfs-3.3.0
make install
cd /
rm -rf /home/base/glusterfs-3.3.0
rm /home/base/glusterfs-3.3.0.tar.gz

Let’s create a mount point on ‘/var/domains/web’ and mount it. This will be the directory on which the cluster is mounted, and it will be the virtual domain directory too.

mkdir /var/domains/web

Now add the glusterfs cluster to the startup script.

nano /etc/init.d/local.sh
echo "Starting network storage... "
/usr/local/sbin/glusterfs -s --volfile-id slitaz-volume /var/domains/web

Once this is done, reboot the server to see if the file system mounts. After this it’s time to install the mysql dependencies for connecting with the database. I want database support for my webserver.

tazpkg get-install php-mysql
tazpkg get-install php-mysqli 
tazpkg clean-cache

Now lets create a new virtual host on port 80.

nano /etc/lighttpd/vhosts.conf
$SERVER["socket"] == ":80" {
server.document-root = "/var/domains/web"
server.errorlog = "/var/domains/web-error.log"

Almost done. This is a little test script I’ve made to test the functionality with the backend servers. Just put it on the cluster and each node will show it’s own name and if he has connection with the database. This will be the temporary index page.

nano /var/domains/web/index.php
echo "<h1>Welcome,</h1><br>";
echo "You are now connected with server: ".exec('hostname');
echo "@".$_SERVER['SERVER_ADDR']."<br>";
echo "Connection with the database is: ";
$link = mysql_connect("","web","web");
if (!$link) {
    die("<font color=\"#FF0000\">inactive</font>");
echo "<font color=\"00FF00\">active</font>";

Now copy 3 times and change the IP of each node to reflect configuration discussed at the beginning of the post. (Tip: start with the last machine and work up to the first to avoid IP conflicts with

/home/base/ip.sh webnode4 192.168.1 214 1
/home/base/ip.sh webnode3 192.168.1 213 1
/home/base/ip.sh webnode2 192.168.1 212 1

Voila, all servers responding as they should be.

And as usual, the vmware images: webnodes.7z (159 MB)

Note: this file doesn’t contains the test php script. As this is generated on the clusters. You will need to recreate this file yourself!

No Comments |

Slitaz project – Part 4 – Mysql replication

So this post will focus on creating a mysql master server and a slave replicating this master. Mysql replication is a good way to have realtime backups.

First let’s start with the master server. I will use the IP address 192.168.1 231 for the master and 192.168.1 232 for the slave.
Create a copy of our base and add a 1GB IDE disk drive to this. This disk will be where our database will be written to. (Still using the 512MB main disk seems wrong for me.)

Fire up our script, and reboot (as usual)

/home/base/ip.sh mysqlmaster 192.168.1 231 1

So now let’s add our disk. I noticed that in the starup script, Slitaz uses ‘/var/lib/mysql’ a lot. To avoid any problems later on, I will just mount the disk to the place where the mysql database is kept.

fdisk /dev/hdb

Press: o, n, p, 1, enter, enter, w

mkfs.ext2 -b 4096 /dev/hdb1
mkdir /var/lib/mysql
nano /etc/fstab
dev/hdb1	/var/lib/mysql	ext2	defaults	0	0

Now our storage is prepped, it’s time to install the mysql server. On the master server I will install the package ‘php-mysqli’ too because it is required for phpmyadmin. (Note: also agree to any additional required packages)

tazpkg get-install mysql
tazpkg get-install php-mysqli 
tazpkg clean-cache

Now let’s add it as a service (easy peasy stuff, you should be quite familiar with this by now.)

nano /etc/rcS.conf
RUN_DAEMONS="dbus hald slim firewall dropbear lighttpd mysql"

For our convenience, the default Slitaz installation comes with a configuration for machines with a low amount of memory. So I will be deleting the default configuration and using this configuration instead.

rm /etc/mysql/my.cnf
mv /etc/mysql/my-small.cnf /etc/mysql/my.cnf

Now before we can start mysql, the config file needs a little bit of tweaking. The ‘bind-address’ setting is used to allow external machines to make a connection. This is needed because we want our webnodes to connect to this database. Also the setting ‘log-bin’ needs to be enabled. This allows our master mysql server to keep logs for our slave.

nano /etc/mysql/my.cnf
bind-address =

Now reboot the server. This will cause Slitaz/MySQL to generate the needed files for the MySQL database. These are generated the first time the service is started.

Now let’s login to our newly created server. Normally the password is left empty (just press ENTER).

mysql -u root -p

Now this server needs a few extra accounts: One account for our slave server which is located at, and should be restricted to that IP. One account for phpMyAdmin (called myadmin here). One account to distribute to our web servers so they can connect to the database (Optional: restricted to this subnet).

GRANT ALL ON *.* TO slave@'' IDENTIFIED BY 'slave';
GRANT ALL ON *.* TO myadmin@'localhost' IDENTIFIED BY 'myadmin';

So now as promised, the installation of phpMyAdmin. I like this little piece of software, and because there is already a web server installed it’s easy to include. So just download it and unpack it to the admin domain.

cd /home/base
wget http://downloads.sourceforge.net/project/phpmyadmin/phpMyAdmin/3.5.1/phpMyAdmin-3.5.1-all-languages.tar.gz
tar xzvf /home/base/phpMyAdmin-3.5.1-all-languages.tar.gz
mkdir /var/domains/admin/phpMyAdmin
mv /home/base/phpMyAdmin-3.5.1-all-languages/* /var/domains/admin/phpMyAdmin
rm -rf /home/base/phpMyAdmin-3.5.1-all-languages
rm /home/base/phpMyAdmin-3.5.1-all-languages.tar.gz

So now let’s configure this instance. A configuration example can be found as ‘config.sample.inc.php’. We will use this to configure our phpMyAdmin.

mkdir /var/domains/admin/phpMyAdmin/config
cp /var/domains/admin/phpMyAdmin/config.sample.inc.php /var/domains/admin/phpMyAdmin/config/config.inc.php

Just edit the newly created config file and change the blowfisch secret. (Else phpMyAdmin will complain.)

nano /var/domains/admin/phpMyAdmin/config/config.inc.php
$cfg['blowfish_secret'] = 'slitazsecret';

Done, easy no? Now you can use the link ‘‘ to access phpMyAdmin. Use the username/password combination: myadmin/myadmin.

Part one of our master server is done. Time to work on our slave. This slave will replicate all changes made in the master database. This is a great backup solution. If our master server fails the slave can be reconfigured to a master server. And bring the systems up and running again in no time.

Like with the master, we will continue from our base system and also add a 1GB IDE disk. I will be using the ip for the slave.

/home/base/ip.sh mysqlslave 192.168.1 232 1
fdisk /dev/hdb

Press: o, n, p, 1, enter, enter, w

Also this disk needs to be mounted on ‘/var/lib/mysql’ like the master.

mkfs.ext2 -b 4096 /dev/hdb1
mkdir /var/lib/mysql
nano /etc/fstab
dev/hdb1	/var/lib/mysql	ext2	defaults	0	0

On our slave I will not install phpMyAdmin. (Installing this is optional, install instructions are described in the part of the mysqlmaster.)

tazpkg get-install mysql
tazpkg clean-cache
nano /etc/rcS.conf
RUN_DAEMONS="dbus hald slim firewall dropbear lighttpd mysql"

Now let’s use our configuration file for small memory servers.

rm /etc/mysql/my.cnf
mv /etc/mysql/my-small.cnf /etc/mysql/my.cnf 
nano /etc/mysql/my.cnf

Off course, this file also needs some changes. These include adding the slave options. The ‘server-id’ must be different and the server instance must know how to connect to the master server.

bind-address =
server-id = 2

Now let’s reboot this server too and let it generate all needed files.

Now the difficult part: creating a data snapshot. This is done to make the servers synchronize. First the master tables have to be locked, a data dump has to be made. Then this data dump needs to be uploaded to the slave. The slave needs to be started and all tables will need to be unlocked on the master database.

This requires two putty sessions to each machine. One on the master to lock the database and one to dump the database. One on the slave to stop the slave instance (and restart it) and one to restore the backup to the slave.


mysql -u root -p
flush tables with read lock;


mysqldump --all-databases --master-data > /var/domains/admin/dbdump.db

Now on our slave we need to reset the state of our slave to accept the data dump.

mysql -u root -p
stop slave;
reset slave;

Now let’s download the dump on on mysqlslave and dump it into the database.

wget -O /home/base/dbdump.db
mysql -u root -p &lt; /home/base/dbdump.db

Now start our slave again in session1 (which is still connected to the mysql database.)

slave start;

Now unlock our tables again in the master.

unlock tables;

And delete the database dumps on our slave server.

rm /home/base/dbdump.db

And on our master server.

rm /var/domains/admin/dbdump.db

All done, our tables should now perfectly synchronize. Open a MySQL Workbench on both databases and watch them synchronize! (I am not going to explain this program to you right now. Look it up if you don’t know how to use it.)


And here are the files (contains mysqlmaster and mysqlslave): mysql.7z (20.7 MB)

No Comments |

Boosting your WiFi signal with DD-WRT

So, recently I bought myself a new tablet PC (Samsung Galaxy Tab2 10.1) and what I noticed was that my WiFi signal was too weak for this tiny device to connect. Downloading a 700MB movie from my NAS just kept getting interrupted due to a weak WiFi signal. I just spent € 330 on something and I want it to work.

So I brought in the big guns. I collected every piece of hardware I’ve ever bought and installed it on various locations in the house:

– Cisco E4200 router (main router) – desk
– Linksys WRT150N router – garage
– SiteCom WL341 router – garage
– Linksys WRE54G range expander – attic

And I used the same SSID’s for each router. This got the signal peaking but I encountered two huge problems:

a) The SiteCom router kept resetting/shitting it’s DHCP configuration shredding my IP range to pieces. SiteCom uses 192.168.0.x and my DHCP is configured for 192.168.1.x causing devices connected to that router being assigned a 192.168.0.x IP which made it impossible for them to connect.
b) I installed WPA protection on the routers (because the WRE54G was not able to use WPA2) but the Linksys 150N WPA settings were different from the other causing problems.

4 devices, a good WiFi coverage but still no stable WiFi. Not cool.


So I’ve cut out the Linksys and the Sitecom router which where causing a lot of problems and kept only the repeater. Still no good reception. Anyway at this point I remembered a friend of mine using DD-WRT. So I just gave it a go… and results where pretty awesome.

The Linksys router seemed to be compatible and I’ve flashed it to DD-WRT. It only took me one setting to boost my WiFi connection throughout the entire house: ‘TX Power’.

I’ve noticed the default was set to 71 mW. I quickly upped the TX power to 251 mW (the maximum) and voila. WiFi was stable and reachable everywhere in the house. Pretty damn impressive/awesome result.

I really recommend this firmware to anyone who has a few spare routers.


Anyway now I’m going to see if I can make my SiteCom router accept dd-wrt. Might brick it, but I don’t care that much about this useless piece of junk anyway. But first back to Slitaz.

No Comments |