Introduction: Toggle an LED Via the Web With Raspberry Pi

About: Firmware Engineer

This tutorial will go over how to toggle an LED via a web page using lighttpd, Python and wiringpi. There are many other tutorials of a similar nature, I wanted to walk through how I accomplished this with these tools.

Step 1: Prerequisites

You will need the following:

  1. A Raspberry Pi with Raspbian installed. I also recommend creating a new user and removing the pi user.
  2. Access to a terminal on the pi, either through a keyboard and screen, or SSH.
  3. An LED.
  4. A 220 Ohm resistor.
  5. Some wires and a breadboard.

Step 2: Connect the LED

Connect the LED as pictured. Connect the anode (longer pin) to the 3.3V pin on the Raspberry Pi. Connect one end of the 220 Ohm resistor to the cathode (short pin) and the other end to wiring pi pin 8 (SDA on all Raspberry Pi Model B boards).

Step 3: Install Necessary Software

You will need to install a few packages via apt. We'll need a webserver (lighttpd), something to control the gpio pins (wiringpi) and an interpreter to respond to web requests (python, because there's already plenty of info on PHP). Run the following commands to install everything you'll need:

sudo apt-get update
sudo apt-get install lighttpd wiringpi python python-pip python-virtualenv

The webserver should automatically start. If you put the hostname of your Raspberry Pi in your web browser you should see the lighttpd default landing page.

Step 4: Configure Lighttpd

In order to get python to work correctly, we'll need to make some configuration changes to lighttpd.

First, enable the fastcgi mod:

sudo lighttpd-enable-mod fastcgi

Then, add the following to /etc/lighttpd/lighttpd.conf:

fastcgi.serer = (
  ".py" => (
    "python-fcgi" => (
      "socket" => "/tmp/fastcgi.python.socket",
      "bin-path" => "/var/www/html/",
      "check-local" => "disable",
      "max-procs" => 1

This tells lighttpd to use the FastCGI protocol whenever it encounters files ending in ".py". Instead of loading the file, it will call the file specified by bin-path (

Restart lighttpd:

sudo service lighttpd restart

Step 5: Setup Permissions

We'll need to change some permissions in the /var/www/html directory so that our program can work correctly. First, add the current user to the www-data group:

sudo usermod -a -G www-data $USER

Next, change the ownership of everything in html directory:

sudo chown -R "$USER":www-data /var/www/html

Then setup the permissions:

find /var/www/html -type f -exec chmod 0640 {} +
sudo find /var/www/html -type d -exec chmod 2750 {} +

This will ensure that all files created from here on out will belong to the www-data group, and have permissions of 0640 (users can read/write, group can read, no one else has any access).

Step 6: Setup Python Environment

It is not entirely necessary to use virtualenv, but it is recommended practice, so we'll go ahead and use it. Go ahead and setup the virtual environment:

virtualenv .venv

And enable it:

. .venv/bin/activate

Then install flup, which we'll need for our python script to handle web requests:

pip install flup

Finally, deactivate the virtual environment:


Step 7: Create the Landing Page

Our landing page will be a simple HTML button with some javascript to make a post request back to our server whenever we click it. Place the following in /var/www/html/index.html:

<!DOCTYPE html>
  <meta charset="utf-8" />
    <button type="button" onclick=sendRequest()>Click Me!</button>

function sendRequest()
  var xhr = new XMLHttpRequest();
  var url = "";"POST", url, true);

This will create a page with a single button with the text "Click Me!". When the button is clicked, the "sendRequest" function will form an HTTP request for the page "" and send it back to our server. Next, we'll write so that it will toggle the LED state whenever it receives a request.

Step 8: Write the Python Script

Unfortunately, we cannot toggle the LED directly from python, as this requires the script to be run as root (which we don't want to do because allowing our web server to execute as root is generally a bad idea). Instead, we'll use the subprocess module to call wiringpi's gpio-utility. Every time we receive a request, we will toggle the state of the LED. Place the following in /var/www/html/

from flup.server.fcgi import WSGIServer
from subprocess import Popen, PIPE, call

def application(environ, start_response):
    status = '200 OK'

    call(['gpio', 'mode', '8', 'out'])
    call(['gpio', 'toggle', '8'])

    response_headers = [('Content-type', 'text/plain'),
                        ('Content-Length', str(0))]

    start_response(status, response_headers)
    return []

if __name__ == '__main__':

We start by making sure we're using the virtual environment we setup earlier (#!.venv/bin/python). Then we import flup's FastCGI adapter for WSGI. If that was complete gibberish, don't worry too much about it. It basically just allows our webserver to communicate with python and vice-versa. The remainder of the code is mostly just there to conform to WSGI. Where we actually control the LED is in the two lines inside our "application" function:

<p>call(['gpio', 'mode', '8', 'out'])<br>call(['gpio', 'toggle', '8'])</p>

This sets the mode of the pin to "output" and then toggles it's state. So if the pin is high, it will go low, and if it is low, it will go high. This function is run every time the page "" is requested from our webserver.

Step 9: Set Permissions on Our Python Script

In order for the webserver to execute our python script, we'll need to set up the correct permissions:

chmod ug+x /var/www/html/

Step 10: Test!

Open up a web browser and navigate to your new webserver (if you're on the pi, you can use localhost or If you're on a different computer that is on the same LAN as the pi, you can either use the hostname of the pi, or it's ip address, which you can find by running ifconfig on the pi). You should see our new web page. Click the button and the light should toggle on and off.