Running a Web Server on a Home Router

You know that little blue box sitting in the corner of your home office, providing you with access to the glorious World Wide Web? Yes – I mean your wireless router. Did you know that you can serve web pages directly off of it? I bet you didn’t. Well I’m going to show you how.

Before we get started, however, I would like to remind you that you’re taking a risk (albeit small one if you know what you’re doing) here by voiding your warranty and modifying your router. Make sure you have a spare router just in case you screw up and brick it :)

First off, I’m going to assume that you’re a self-respecting geek who’s already flashed your Linksys, Buffalo, ASUS, Belkin, D-Link, Motorola, Netgear, or ZyXel router with some variant of homebrew Linux firmware. If not, I suggest you pick up a copy of Tomato, OpenWrt, DD-WRT, or the like and load it up. For this tutorial, I’m going to use Tomato 1.10 build 1188, since it happens to leave a decent amount of free space on the flash to host your own content, and is fairly feature rich.

Once you’ve got your router all configured and running an SSH server, go ahead and connect to it. If you run ps you should notice that there is an instance of httpd already running on port 80! Don’t get yourself excited though – this is the special web server used to admin the router, and it’s pointed at the read-only directory /www. Actually, if you notice, everything on the router is mounted read-only (with the exception of /tmp which is mounted tmpfs).

Unlocking Flash for Writing

Nevertheless, it is easy to unlock a portion of the flash memory for our own use. Point your browser at the internal webserver, click Administration and JFFS2, and then format/enable the journaled filesystem. It will be automatically mounted read-write on /jffs. As for the box about executing a script, tell it to run /jffs/start.sh – I’ll explain why in a minute.

Back in your open shell, change directory over into /jffs and type mkdir web. Ok, so now you’re thinking that we’re just going to point the existing /usr/sbin/httpd at /jffs/web – but you’re wrong! After a quick email with Jon, the creator of Tomato, I found out that the password prompt and default filename are statically compiled into the binary. Can you guess what that means? We get to compile our own special httpd with our own modifications – how exciting!

Compiling the Server

Grab a copy of the Tomato source code along with the official Linksys code. Don’t worry if you don’t have a Linksys router, we’re not compiling anything model-specific – in fact, I’m doing this with a Buffalo WBR2-G54. Extract everything in the way the Tomato README explains, and change to tomato/release/src/router/httpd.

Bring up httpd.c in your favorite *nix code editor (*cough* vim *cough*) and find and remove the line that says sprintf(header, "WWW-Authenticate: Basic realm=\"%s\"", realm);. Do the same for send_error(401, header, NULL);. This will remove the code that would have instructed the browser that it sent an invalid username/password. Next you have to remove the two lines that check the authentication on the router side. In the same file, locate and neutralize the two instances of if (!check_auth(authorization, cl)) return;. Finally, do a search-and-replace for status-overview.asp and replace it with whatever you want to call your default page (I picked index.asp). Save the file and close your editor.

Make sure your distro’s compilers are set up properly and make httpd, or just build the whole entire thing and copy the resulting binary file out of httpd. If you’re using Debian or Ubuntu as your host, you’ll want to apt-get install build-essential as root beforehand.

If something gets messed up and you’re getting build errors, you can just download and uncompress my prebuilt binary to your router.

# cd /jffs
# wget http://192.168.1.51/tomato110-custom-httpd.gz
# mv tomato110-custom-httpd.gz httpd.gz
# gunzip httpd.gz

Creating Boot Scripts

Remember that shell script we referenced a while ago? Now it is time to create it.

# cd /jffs
# cat << EOF > start.sh
#!/bin/ash
cd /jffs/web
/jffs/httpd -p 90
EOF
# chmod +x start.sh

Notice how the script changes into the directory that httpd will be serving up, and specifies port 90 as to not interfere with the internal web server used for configuration. (Don’t worry, we’ll map port 80 later on.)

Finalizing Access

In order to enable access from the outside, you will need to go to poke two holes in the NAT/firewall. First, go to Port Forwarding / Basic and forward external port 80 to internal port 90 on the internal IP assigned to your router. Second, go to Administration / Scripts, click the Firewall tab, and add this line of code to allow direct connections to port 90 on the router.

iptables -A INPUT -p tcp -m tcp --dport 90 -j ACCEPT

You can now reboot your router and do a quick test that your special instance of our new mini web server is running. Assuming the test went well, you can go ahead and fill up the tiny flash partition with some static HTML (remember to name the home page index.asp) for your own use — whatever that may be. Happy hacking ;-)

About these ads

23 Comments on “Running a Web Server on a Home Router”

  1. pepito says:

    how map port 80 later on???

  2. Lio says:

    Great but i am lost in the beginning so can we do that step by step tutorial. I couldn’t find that version of tomato. I cant do the compilling. Thank you for the post it is a blind spot for google search so for the common people.

  3. Lio says:

    How can one transfer files on the router. ssh for ehample but what is the syntax since wget didnt worked for me. Thank you! sorry for the dummyest question

    • brianez21 says:

      From your computer just use SCP to copy the file to the router (ex. 192.168.1.1).
      $ scp tomato110-custom-httpd.gz 192.168.1.1:/jffs/httpd.gz
      Then on the router side, uncompress it.
      # gunzip httpd.gz
      Don’t forget to set permissions on the file after extracting.
      # chmod +x httpd

  4. Lio says:

    i dont know what i touched but it works
    THANK YOU THANK YOU!!!
    the clues were enough for a blind man to pass

  5. Lio says:

    how do you open “httpd” file you made?

    • Brian says:

      All you need to do is give it execute permissions with “chmod +x ./httpd” and then run it with “./httpd -p 90″ where 90 can be replaced with the port number you want to bind it to. By default it will serve files from the directory you started it inside of.

  6. sco says:

    Any ideas on how to modify this setup to understand the application/x-ns-proxy-autoconfig mime type? This would be for the purpose of serving up a web proxy automatic detection (wpad) file (wpad.dat/proxy.pac) directly from the router. This httpd binary as well as tomato’s web server don’t seem to be configured to natively handle this mime type.

    • Brian says:

      The web server binary that ships with the source code is a very basic implementation of HTTP and does not support advanced features like this. It is really only meant for the admin interface. You could try editing the source code and compiling your own if you would like; but my suggestion would be to port over a small web server that supports these features from a distribution such as OpenWRT.

      • sco says:

        That’s what I was thinking. I’ve looked into setting up lighttpd (OpenWRT package) (I looked at a number of others as well) but have already run out of space on the jffs partition getting all the libraries it requires to run. It seems it wouldn’t take very much to add to the tomato httpd source. Could you share the process you used to compile your httpd binary. Perhaps provide a copy of the official Linksys source if you still have it since that link is dead. I thought I had found another copy at the twtomato google code project but I get a bad crc when extracting the tgz from the joined zip file and after fully extracting it some stuff appears to be missing as there are a number of compile errors – the tomato/tools/brcm folder doesn’t exist which contains the mipsel-uclibc-gcc binary which appears to be requisite for compilation.

      • Brian says:

        As stated in a previous comment.
        For the Linksys code try using the WRT54GL tarball from: http://homesupport.cisco.com/en-us/gplcodecenter
        For the Tomato code get the Tomato_Source tarball from: http://sourceforge.net/projects/tomatofirmware/files/tomato/1_28/

  7. Lio says:

    are these asp commands possible to run on the httpd server i got from here or it does not support these? Thank you

    PS: Still proud to have my website on the router!!!

  8. Lio says:

    i ment these

    set FSO = Server.CreateObject(“scripting.FileSystemObject”)
    set myFile = fso.CreateTextFile(“/jffs/web/form/xx.txt”, true)
    myFile.WriteLine(“my text here”)
    myFile.WriteLine(“more text here”)
    myFile.Close

  9. Vincent says:

    When I ./httpd -p 80, I get “segmentation error”..
    yet when I, service httpd start, it completes.
    However, when I, service httpd -p 90 start, it refuses to do anything..

  10. Felix Lee says:

    Hi Brian, Do you still have a copy of the httpd? The link is down. thanks


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 45 other followers