Category Archives: raspberry pi

Secure and extend you Philips Hue bridge with a reverse proxy

Philips Hue bridge

Recently I bought a Hue bridge with two bulbs, it was a specific “cheap” pack around 50€, the bridge itself usually costs that price, so I was quite interested. My idea was just to play with those bulbs and do funny things such as blinking when I get new mail, etc … After messing with it for a while using the Philips HUE app on Android, I wanted to do more so I checked the API. It’s quite well made and allows you to do a lot on your own, though, I had in mind to hide my bridge in my own local network, for security purpose and also to add more functionalities to it, let’s see how to make a hue bridge reverse proxy !


To do that, you need:

  • a router, your own home box is enough
  • a raspberry PI or any computer with Apache and PHP
  • (optional) a USB to ethernet adapter, I bought this cheap one
  • some time to configure it all !

Configure the bridge

Follow the official instructions to install your bridge, you have to connect it to your router, it needs an IP within your local network so we can reach it with an other computer.

Once it’s all set and that it got an IP, open up your web browser and go to the following URL:, obviously set the IP address to the correct one.

Create a new user following the steps on the API documentation. Keep the generated hash around, it’s important to control your bridge.

Stay in your web browser in the debug and do a GET call to http://<ip-address.of.the.bridge>/api/<username>/config, it will look like that:

Get the bridge information

Get the bridge information

Copy the mac field and save it somewhere, it’s important.

Finally, we will configure the bridge to stop DHCP and also to take the IP we want it to get out of the local range.

Still in your browser, do a PUT request to http://<ip-address.of.the.bridge>/api/<username>/config with the following content:

{"ipaddress":"", "dhcp":false, "netmask": "", "gateway": "" }
Do a PUT request to http://<ip-address.of.the.bridge>/api/<username>/config

Once you run it, you should lose the control to the bridge ! No worries, we’ll get it back.

Network adapter

If you bought the network adapter I suggested, it should look like that:

Network adapter in its blister

Network adapter in its blister

SSH to your raspberry pi, and check the network configuration:

 # ifconfig -a
 eth0      Link encap:Ethernet  HWaddr XX:XX:XX:XX:XX:XX
           inet adr:  Bcast:  Masque:
           RX packets:1575384 errors:0 dropped:62 overruns:0 frame:0
           TX packets:810579 errors:0 dropped:0 overruns:0 carrier:0
           collisions:0 lg file transmission:1000
           RX bytes:271762165 (259.1 MiB)  TX bytes:189260556 (180.4 MiB)
 lo        Link encap:Boucle locale
           inet adr:  Masque:
           UP LOOPBACK RUNNING  MTU:65536  Metric:1
           RX packets:4781492 errors:0 dropped:0 overruns:0 frame:0
           TX packets:4781492 errors:0 dropped:0 overruns:0 carrier:0
           collisions:0 lg file transmission:1
           RX bytes:402951806 (384.2 MiB)  TX bytes:402951806 (384.2 MiB)
ifconfig -a before plugging the adapter

Now plug the network adapter USB side to your PI, and connect the ethernet cable to the ethernet adapter.

Network adapter plugged

Network adapter plugged

We’ll check the adapter is working by doing the same command, but now we should see eth1 !

 # ifconfig -a
 eth0      Link encap:Ethernet  HWaddr XX:XX:XX:XX:XX:XX
           inet adr:  Bcast:  Masque:
           RX packets:1576244 errors:0 dropped:62 overruns:0 frame:0
           TX packets:811252 errors:0 dropped:0 overruns:0 carrier:0
           collisions:0 lg file transmission:1000
           RX bytes:271834756 (259.2 MiB)  TX bytes:189382050 (180.6 MiB)
 lo        Link encap:Boucle locale
           inet adr:  Masque:
           UP LOOPBACK RUNNING  MTU:65536  Metric:1
           RX packets:4781492 errors:0 dropped:0 overruns:0 frame:0
           TX packets:4781492 errors:0 dropped:0 overruns:0 carrier:0
           collisions:0 lg file transmission:1
           RX bytes:402951806 (384.2 MiB)  TX bytes:402951806 (384.2 MiB)

 eth1      Link encap:Ethernet  HWaddr XX:XX:XX:XX:XX:XX
           BROADCAST MULTICAST  MTU:1500  Metric:1
           RX packets:0 errors:0 dropped:0 overruns:0 frame:0
           TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
           collisions:0 lg file transmission:1000
           RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
ifconfig -a after plugging the adapter

Perfect, now let’s configure the network, edit the file /etc/network/interfaces by adding the following:

 auto eth1
 iface eth1 inet static
         netmask 24

Bring up eth1 end ping your bridge:

#  ifup eth1
 # ping
 PING ( 56(84) bytes of data.
 64 bytes from icmp_seq=1 ttl=64 time=1.86 ms
 64 bytes from icmp_seq=2 ttl=64 time=1.45 ms
 --- ping statistics ---
 2 packets transmitted, 2 received, 0% packet loss, time 1001ms
 rtt min/avg/max/mdev = 1.454/1.661/1.868/0.207 ms
Bring up eth1 and ping your bridge !

If it all works, you can move on to the HTTPS part, else, try using some networking tools such as tcpdump to determine what goes wrong.


New release of the Hue bridge uses HTTPS, of course it can’t rely on a real domain name since it’s connecting on the IP of the bridge and it can be different, after doing some reverse engineering it I found out how it works. Actually every bridge as an ID. Now that the link between your PI and the bridge is UP you can get your ID easily and prepare to create your own HTTPS certificate.

# openssl s_client -showcerts -connect </dev/null
Server certificate
subject=/C=NL/O=Philips Hue/CN=00xxxxxxxx
issuer=/C=NL/O=Philips Hue/CN=00xxxxxxxx
Check what's the CN of your bridge

So there you go you have your CN which is actually what’s necessary to create your own HTTPS certificate. If you want to change your ID, you can, you’ll have to change it also in the PHP below.

First create a directory to store your key, certificate.

# mkdir -p /etc/ssl/hue
Create the /etc/ssl/hue directory

Now the key and the certificate

# openssl req -newkey rsa:4096 -nodes -keyout key_hue.pem -x509 -days 3650 -out certificate_hue.pem
Create your self signed certificate

The only parameter that matters here is the CN, put a correct bridge ID, in my case I just changed a few values.

Finally just concat both files to create a pem.

# cat certificate_hue.pem key_hue.pem > pem_hue.pem
Create the full certificate

A word of advice, as of now (version 1806051111 of the bridge), the hue app will use HTTPS to connect to the bridge, the first time you validate the connection it will stick the certificate. If you ever change the certificate, you’ll have to remove the credentials in your Android/iOS (i.e clear all data of the app) and press on the button again.

Second word of advice, if you test a lot, be careful to keep clean your whitelist user, it gets messy very fast ! You can delete some doing a DELETE request on /api/userYouControl/config/whitelist/userYouWishTodelete

Reverse proxy

Do you remember the MAC address of your bridge ? If, as I previously said you did, then we will use it pretty soon.

Stay on your PI and open up again /etc/network/interfaces, we will change the mac address of eth0 so if it will be seen as a HUE bridge for the mobile apps. You can use the mac address of the real bridge and alter it so it’s different, I suggest you use this website to make it sure it’s still seen as “Philips Lighting BV“.

auto eth0
iface eth0 inet static
        netmask 24
        # faking MAC address to Philips HUE style
        hwaddress ether 00:17:88:78:45:12
Change the mac address

Now on your home box, set the IP of your PI as a static one for this tutorial it will be

It’s time to install haproxy, apache and php, I won’t describe this here, do as you wish, we’ll just go through what’s really important.

There goes a valid haproxy configuration:

# Faking Hue Bridge requires HTTPS now

frontend f_http_hue
        mode http
        use_backend b_http_hue

frontend f_https_hue
        mode http
        bind ssl crt /etc/ssl/hue/pem_hue.pem
        use_backend b_http_hue

backend b_http_hue
        mode http
        server bridge

Install mod_proxy and mod_http_proxy, create a new virtualhost /etc/apache2/sites-available/hue.conf this way:

    DocumentRoot /var/www
    ServerName xxxxxxx
    CustomLog /var/log/apache2/hue_access.log combined env=!forwarded
    CustomLog /var/log/apache2/hue_access.log proxy env=forwarded
    ErrorLog /var/log/apache2/hue_error.log

    RewriteEngine On
    RewriteCond %{REQUEST_URI}  ^$ [OR]
    RewriteCond %{REQUEST_URI}  ^/$ [OR]
    RewriteCond %{REQUEST_URI}  \.png$ [OR]
    RewriteCond %{REQUEST_URI}  \.xml$ [OR]
    RewriteCond %{REQUEST_URI}  ^/debug/clip.html
    RewriteRule (.*)    $1    [P,L]

    RewriteRule ^(/api.*)$ /index.php?q=$1 [L,QSA]

Activate it and edit /var/www/index.php:

* Activate proxy_module and proxy_http_module


$mac_address = [ '<mac address of the real bridge>',  '<your fake Philips HUE mac address>' ];
$ip_hue = [ '<ip of the real bridge>', '<ip of your PI>' ];
$bridge_id = [ '<the real bridge id>', '<faked id bridge>' ];
$gateway_hue = [ '<ip of your PI>', '<gateway of your local network>' ];
$url = ''.$_SERVER['REQUEST_URI'];
$useDB = false;

$options =[ 
    'http' => [
        'header'  => "Accept-Encoding: gzip, deflate\r\nAccept-language: en-US,en;q=0.8\r\nUser-Agent: ".$_SERVER["HTTP_USER_AGENT"]."\r\n",
        'method'  => $_SERVER["REQUEST_METHOD"],

    $options['http']['header'] .= "Content-type: application/x-www-form-urlencoded\r\n";
    $options['http']['content'] = file_get_contents("php://input");

$context  = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) {  }

// faking HUE bridge EDIT: 13/08, it needs to be faked all the time now
$result = str_replace($mac_address[0], $mac_address[1], $result);
$result = str_replace($ip_hue[0], $ip_hue[1], $result);
$result = str_replace($gateway_hue[0], $gateway_hue[1], $result);
$result = str_replace($bridge_id[0], $bridge_id[1], $result);

echo $result;
$size = ob_get_length();
header("Content-Length: {$size}");
header("Connection: close");

/** DB part **/

    $_user = '';
    $_password = '';
    $_database = '';
    $_host = '';

    try {
	$_db_link = new PDO('mysql:host='.$_host.';dbname='.$_database.';charset=utf8', $_user, $_password);
    } catch (Exception $e) {
        die('Erreur : ' . $e->getMessage());

    $stmt = $_db_link->prepare("INSERT INTO hue_log (ip, method, url, content) VALUES (:ip, :method, :url, :content)");
    $stmt->bindParam(':ip', hash('sha256', $_SERVER['REMOTE_ADDR']));
    $stmt->bindParam(':method', $_SERVER['REQUEST_METHOD']);
    $stmt->bindParam(':url', $_SERVER['REQUEST_URI']);
    $stmt->bindParam(':content', $result);

Now restart Apache and open your browser on, it should load ! Check the logs of Apache, you should also see some requests.

Philips’ upgrades

I didn’t mention it, because I hadn’t figure it yet, but all the Philips’ Upgrades won’t be done anymore since the bridge has no internet access. I found out one way to do it, it’s tricky but anyone can do it.

I use the Hue App on my mobile to control lights, it tells you when some upgrades are required, it’s how I know I should run them. When it happens, I simply forward packets from my bridge to my PI and force the update thought the API, let’s do it.

Allow packet forwarding and forward the bridge to the PI:

 echo 1 > /proc/sys/net/ipv4/ip_forward
 iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
 iptables -A FORWARD -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT
 iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
Allow kernel forwarding and forward bridge to the PI

You should notice that the third light is now lit, it reaches internet, no worries we open it up only temporarily.

Connect to the API and run the following commands:

         "portalservices": true
Do a PUT request to http://<ip-address.of.the.bridge>/api/<username>/config

{"swupdate": {"checkforupdate":true}}
Do a PUT request to http://<ip-address.of.the.bridge>/api/<username>/config

         "swupdate": {
                     "updatestate": 3
Do a PUT request to http://<ip-address.of.the.bridge>/api/<username>/config

It should download the update, restart your bridge, launch the update from your mobile app, sometimes it’s quite long ! To update three bulbs it took me around 1 hour, it depends on the update.

Once everything is done, cut the bridge from the internet:

 iptables -F nat
 iptables -F FORWARD
 echo 0 > /proc/sys/net/ipv4/ip_forward
Clean up the firewall and shut down forwarding

Reboot it once again so remaining connections will be stopped. Only two lights should remain.

You might check that your bridge is really off the internet by doing a GET request to http://<ip-address.of.the.bridge>/api/<username>/config, you should have that:

     "portalstate": {
         "signedon": false,
         "incoming": false,
         "outgoing": false,
         "communication": "disconnected"
     "internetservices": {
         "internet": "disconnected",
         "remoteaccess": "disconnected",
         "time": "disconnected",
         "swupdate": "disconnected"
Content of the GET to http://<ip-address.of.the.bridge>/api/<username>/config

Also, it’s possible you do a tcpdump to check to what your bridge tries to contact, it might amuse you.

Sources for the upgrades:


Your HUE bridge is hidden behind your raspberry PI, it’s secure moreover you can also edit the PHP to add new functionality !

xbox360 controllers with xboxdrv/Dolphin


I was given a new xbox360 wireless controller at xmas, and I wanted to run my both controllers with one receiver in Dolphin emulator, for whatever reason the normal way didn’t work. Never was the second controller seen in Dolphin !

I went through testing and reading tons of stuff and I ended UP using xboxdrv.


As mentionned in the man, xboxdrv – A Xbox/Xbox360 gamepad driver that works in userspace !

First step, install the necessary packages:

# apt-get install evtest xboxdrv
Necessary packages

Alright evtest is not that important, but to debug it can be useful.

Now we’ll blacklist xpad to be sure it won’t bother our configuration.

# echo "blacklist xpad" >>/etc/modprobe.d/blacklist.conf
Blacklist xpad

Now you have to reboot before to go on, it’s important.

Back online, plug in your USB wireless receiver. Check it’s there:

# lsusb  | grep -i --color "xbox"
Check the USB wireless receiver is detected

Do the procedure to register your controllers (one after another):

  • Press the X button on the controller
  • Push the “wavy” button on the receiver, it should blink
  • Do the same with the “wavy” button on the controller (tiny little button on top of the controller)
  • The controller should blink briefly
  • Both the receiver and the controller are now linked, light is on, no blinking
  • Do it again for the other controllers

Now we’ll check that xboxdrv is working by listing our receiver(s)/controller(s):

# xboxdrv -L
 id | wid | idVendor | idProduct | Name
  0 |   0 |   0x045e |    0x0719 | Microsoft Xbox 360 Wireless Controller (PC) (Port: 0)
  0 |   1 |   0x045e |    0x0719 | Microsoft Xbox 360 Wireless Controller (PC) (Port: 1)
  0 |   2 |   0x045e |    0x0719 | Microsoft Xbox 360 Wireless Controller (PC) (Port: 2)
  0 |   3 |   0x045e |    0x0719 | Microsoft Xbox 360 Wireless Controller (PC) (Port: 3)
xboxdrv -L

As you might have noticed, I have one xbox receiver that can manage up to four controllers (they all do that), explanations:

  • id : receiver’s id (here it’s id 0)
  • wid : controller’s id (column wid from 0 to 3)
  • what’s left doesn’t matter

We can now setup our controllers, you can use my script below, even though you don’t have four controllers, you can still use that script as it is:

#!/usr/bin/env bash

# apt install xboxdrv
# added at session opening
# visudo -f /etc/sudoers.d/xbox360
# floreo ALL = (root) NOPASSWD: /usr/bin/xboxdrv

sudo xboxdrv --daemon  --dbus session \
-i 0 --wid 0 --detach-kernel-driver --mimic-xpad \
--next-controller -i 0 --wid 1 --detach-kernel-driver --mimic-xpad \
--next-controller -i 0 --wid 2 --detach-kernel-driver --mimic-xpad \
--next-controller -i 0 --wid 3 --detach-kernel-driver --mimic-xpad &>/dev/null &

As stated in the commentaries, make sure to configure sudo for your user (here mine’s floreo) and the command xboxdrv, indeed it needs to be root to work.

In my case, everytime my session starts, the script does too. Depending on your OS I don’t know where you can put it. You can also do an init script but it’s more of a bother.

UPDATE: Following this post, I’ve added the –mimic-xpad flag in my script so my right stick would eventually work ! It allows you to control the camera in games for example in Steam which is quite better now.

Launch the script:

# bash
Launch the script

Dolphin emulator

Now open up Dolphin and click on Controllers, in device you should now see evdev/0/Xbox Gamepad (userspace driver) and there should be four of them, the last three ones with a #X. (X being an integer)

Select the first one, press refresh and wait a second. It should now be recognized, press buttons on your controller and the interface should blink in red for every input (try A/B/X/Y first).

If it’s not working, go to troubleshooting else you just can start playing !


If nothing works, check again that everything is plugged and that your controllers are registered, do it one more time to be sure.

Kill the script as root and open up two terminals, in one you’ll launch that command:

# xboxdrv --daemon  --dbus session -i 0 --wid 0 --detach-kernel-driver
Start one controller

In the other do that:

# dmesg | grep -iE 'xbox.+'
Check via dmesg

Some result should popup if none then it’s too bad, it certainly mean you didn’t blacklist well xpad, that your kernel’s too old, or something else.

You might try to check with evtest as root:

# evtest

It should show you a list of what’s connected to your computer, with any luck you could see Xbox Gamepad, if not you’ll have to try to test them.


# ls /dev/input/ | grep event*
List your inputs

You should have a list of several inputs, you can try them one after the other like that:

# evtest /dev/input/eventX
Try the inputs one by one

Press buttons on your controller, if it displays anything then it works.

Well voilà, that’s all I can say for help, good luck, it’s quite long to debug that.

How to install Haproxy

Let’s talk about Haproxy which is quite a good reverse proxy, I assume if you are here you know what it is ^^

Let’s walk trough installing it on Raspbian (would work on any *nux), if you are on Debian/Ubunt you can use a cool link that will give you the sources.list.

I wanted to install haproxy using the package manager on my system, but it’s always old versions:

# apt-cache policy haproxy
  Installé : (aucun)
  Candidat : 1.5.8-3+deb8u2
 Table de version :
     1.5.8-3+deb8u2 0
        500 jessie/main armhf Packages
        100 /var/lib/dpkg/status
Old package version

If the version shown in your package manager if what you want, just install it and you go to the configuration.

I needed the version 1.6, so let’s compile ! If you need an other version, keep reading it’s not that hard.

# replace the version by yours
cd /usr/src
wget${_HAPROXY_VERSION%.*}/src/haproxy-${_HAPROXY_VERSION}.tar.gz &&
cd haproxy-${_HAPROXY_VERSION}/
Download haproxy's sources

Now a few dependencies that you might need too:

apt-get install libpcre3-dev libssl-dev
haproxy dependencies

Finally let’s do it:

Compile haproxy

As you might notice I require PCRE, LIBCRYPT and most important for me OPENSSL.

If you have a few errors try to google them, don’t forget to do what’s below before you try to compile again:

make clean
Clean the previous try

Now we got the binary that we can move:

cp -a haproxy /usr/sbin/haproxy
Move the binary

Last but not least, you need an init script, there you go (I kindly copied it from a package installed version, all the credit goes to the author)

# Provides:          haproxy
# Required-Start:    $local_fs $network $remote_fs $syslog
# Required-Stop:     $local_fs $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: fast and reliable load balancing reverse proxy
# Description:       This file should be used to start and stop haproxy.

# Author: Arnaud Cornet <>


test -x $HAPROXY || exit 0

if [ -e /etc/default/haproxy ]; then
	. /etc/default/haproxy

test -f "$CONFIG" || exit 0

[ -f /etc/default/rcS ] && . /etc/default/rcS
. /lib/lsb/init-functions

	$HAPROXY -c -f "$CONFIG" >/dev/null
	if [ $? -eq 1 ]; then
		log_end_msg 1
		exit 1

	[ -d "$RUNDIR" ] || mkdir "$RUNDIR"
	chown haproxy:haproxy "$RUNDIR"
	chmod 2775 "$RUNDIR"


	start-stop-daemon --quiet --oknodo --start --pidfile "$PIDFILE" \
		--exec $HAPROXY -- -f "$CONFIG" -D -p "$PIDFILE" \
		$EXTRAOPTS || return 2
	return 0

	if [ ! -f $PIDFILE ] ; then
		# This is a success according to LSB
		return 0

	for pid in $(cat $PIDFILE); do
		start-stop-daemon --quiet --oknodo --stop \
			--retry 5 --pid $pid --exec $HAPROXY || ret=$?

	[ $ret -eq 0 ] && rm -f $PIDFILE

	return $ret


		|| return 2
	return 0

	if [ ! -f $PIDFILE ] ; then
		# program not running
		return 3

	for pid in $(cat $PIDFILE) ; do
		if ! ps --no-headers p "$pid" | grep haproxy > /dev/null ; then
			# program running, bogus pidfile
			return 1

	return 0

case "$1" in
	log_daemon_msg "Starting haproxy" "haproxy"
	case "$ret" in
		log_end_msg 0
		log_end_msg 1
		echo "pid file '$PIDFILE' found, haproxy not started."
		log_end_msg 1
	exit $ret
	log_daemon_msg "Stopping haproxy" "haproxy"
	case "$ret" in
		log_end_msg 0
		log_end_msg 1
	exit $ret
	log_daemon_msg "Reloading haproxy" "haproxy"
	case "$ret" in
		log_end_msg 0
		log_end_msg 1
	exit $ret
	log_daemon_msg "Restarting haproxy" "haproxy"
	case "$ret" in
		log_end_msg 0
		log_end_msg 1
		log_end_msg 1
	exit $ret
	case "$ret" in
		echo "haproxy is running."
		echo "haproxy dead, but $PIDFILE exists."
		echo "haproxy not running."
	exit $ret
	echo "Usage: /etc/init.d/haproxy {start|stop|reload|restart|status}"
	exit 2


If needed, make some changes ! In my case, everything ran smoothly.

The installation is done, next step is the configuration.