ESP8266 Webserver Serving Multiple Pages

Introduction: ESP8266 Webserver Serving Multiple Pages

With NodeMCU, the ESP8266 can easily serve a webpage.

In its simplest form, the server responds to a request by sending back 'client:send() one line at a time for each line in the page.

This works. However if you need to make changes in your webpage, you must upload a new .lua file and restart the module and dofile().

Also, it is pretty much limited to the webpage created by the 'server'. Only one server allowed at a time. So our server is limited to one page.

Webserver, one page?

Webserves should deliver multiple pages!

Step 1: Basic Server Setup.

To begin, we need an ESP8266, any version.

For this Instructable, the module needs to be flashed with NodeMCU.

I'm using NodeMCU release dev20150310-2.

Upload this server.lua file to your module, Restart and "dofile(server.lua)"

Ensure that your module has connected to your LAN and has an IP address assigned.

Open a browser and enter the module's IP number.
In my case,
You should see:

Server is working!

Step 2: This Is Great, But I Need More Flexibility!

Congratulations! Your ESP8266 webserver is working.
To make changes to this displayed page, simply edit the server.lua file, upload and Restart the module and dofile("server.lua").

Here is where things get interesting. As you know, a webserver, when receiving a request with no file specified will 'look' in the root directory for a index file. htm,html,asp,php........... and serve up that page. Our module with this server.lua file doesn't do that, it simply serves up the lines in the server.lua file that start with conn:send, from top to bottom.

How about different pages?

Lets say, for example that I want my ESP8266 to serve up different webpages for the names and contact information for each of our three employees, this information changes frequently. Oh, and I also want to know if they are in their office or not. And there is high employee turnover.

With our current setup, we would need to edit, upload, restart and dofile for each time a change is made. All this information would need to be in the server.lua file. This of course is possible, and could even be streamlined to make it not too painful.

Perhaps, I want to create a file called bob.htm and serve that file for Bob's information. Also, I can modify the index page. I can do this and not disturb the other employees information or have to restart the server.

The fun part of these modules is that there are many ways to accomplish a task. Here is an alternative.

Step 3: Lets Make Some Changes!

Hypothetically, I have three employees. Bob, Jill and Barb.

I would like my server to default to a landing page that lists hyperlinks to each employee:


ESP8266 server
Employee information:



I would like to click on an employee and be taken to their webpage for contact information and status.


I'll create a separate htm file for each employee and a htm file for the landing page and I will serve them up by URL.

For example, the IP to my module is for the index page the URL will be: or

For Bob the URL will be

Jill's information will be


In a nutshell, I will use a modified server.lua called newserver.lua file to serve up the individual files for the employees. Or for that matter, any file in the module's memory.

The archive below contains newserver.lua, index.htm and bob.htm
The archive can also be found here.

Unzip this archive and upload the files to your ESP8266 module. Restart and dofile("newserver.lua").

These files can be edited individually for each employee as needed when information changes. Editing newserver.lua will require a Restart and dofile() to implement the changes.

Step 4: Modified Server File Called Newserver.lua, the Key to Multi-webpages.

I now have uploaded the files called newserver.lua, index.htm and bob.htm to the module; Restarted and entered dofile("newserver.lua").

Entering my module'a IP number should display the index.htm file. Clicking on the link to Bob will display bob.htm, and Home will return to the index page.

Some discussion about newserver.lua:

I have coded index.htm as the 'landing' file. I want the module to serve index.htm when I enter the module's IP in a browser.

I am using some LUA code to parse the incoming header request to determine if the request specifies a file or not. A request to just my module's IP number doesn't specify a particular file.

A portion of a typical header requesting index. may look like:

GET / HTTP/1.1
Host: Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

This request is asking for bob.htm:

GET /bob.htm HTTP/1.1
Host: Connection: keep-alive Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 ..............etc.

Parsing the first example, newserver.lua would not find a specific file to open. Since I want index.htm to be the landing file, when tgtfile returns nil, I substitute index.htm. Line 6.

Parsing the header for second request will identify that the request is specifying a file, in this case 'bob.htm'. So, bob.htm is opened and sent one line at at time with the client:send( code.

It is important to not files that don't exist.
This will cause the module to panic and Restart.

So, before reading I test to see if the file exist with, line 7 and 8.

If no file, newserver.lua simply sends back 'file not found', and a link back to the landing page.

This happens when I click on Jill or Barb until I upload htm files for them.


  1. -- newserver.lua
  2. srv=net.createServer(net.TCP)
  3. srv:listen(80,function(conn)
  4. conn:on("receive", function(client,payload)
  5. tgtfile = string.sub(payload,string.find(payload,"GET /") +5,string.find(payload,"HTTP/") -2 )
  6. if tgtfile == "" then tgtfile = "index.htm" end
  7. local f =,"r")
  8. if f ~= nil then
  9. client:send(
  10. file.close()
  11. else
  12. client:send("<html>")
  13. client:send(tgtfile.." not Found - 404 error.")
  14. client:send("<a href='index.htm'>Home</a>")
  15. end
  16. client:close()
  17. collectgarbage()
  18. f = nil
  19. tgtfile = nil
  20. end)
  21. end)


Step 5: Final Thoughts.

The value of this particular process is dubious, however, it is always interesting to explore and expand what these little modules are capable of.

Some savvy LUA programming can certainly make these pages dynamic.

I mentioned earlier that I would like to know if the employees were in the office or not. Perhaps a sensor and a .LUA file that could open() and write to bob.htm on a timer would fit the bill? We can do that to.

The possibilities are endless!

I hope you have enjoyed this instructable and that it has furthered your knowledge of the ESP8266.

Be the First to Share


    • Make It Bridge

      Make It Bridge
    • For the Home Contest

      For the Home Contest
    • Game Design: Student Design Challenge

      Game Design: Student Design Challenge


    Rodrigo AraújoV
    Rodrigo AraújoV

    6 years ago

    Is there anyway to add a domain name for the esp?


    Reply 4 years ago

    Yes there is, you are looking for mDNS...

    mdns.register("DeskLight", { description="Desk Lamp Light Show", service="http", port=80, location='Office Desk Lamp' })

    and to access it you would enter: "http://desklight.local" in your browser (you must be connected to the same WiFi network) have to be aware of the fact that mDNS needs your ESP to be connected to the WiFi network before you can register it... to get around this i wraped my register command in a timer like so:

    tmr.alarm(1, 1000, tmr.ALARM_AUTO, function()
    if wifi.sta.getip() ~= nil then
    print('mDNS: ', 'DONE');
    --mdns.register() command here
    Rodrigo AraújoV
    Rodrigo AraújoV

    Reply 6 years ago

    Thanks breagan22. I'll look toward it.


    Reply 6 years ago

    Did you end up figuring this out?


    5 years ago

    I successfully ran your code. However I can only access newserver on my 8266 using my home network.

    I want to replace the line: srv:listen(80,function(conn) with: srv:listen(6633,function(conn). Then I can port-forward my router (ip: to my 8266 (ip: so that when I'm away from home I can open a web browser and enter: which will connect to my 8266 on its port 6633 which will have the newserver listening.

    Note: I can't use the standard port 80 on the 8266 because that confuses the router.

    Also note: when I try using the port 6633 on my home network, I get the message: sent an invalid response. ERR_INVALID_HTTP_RESPONSE.

    Can anyone help me?



    5 years ago

    i know how to code esp8266 using Arduino IDE software. your process seems to be different.Can you help me in understanding how it is diffrent from Arduino IDE coading.


    6 years ago

    nice work.


    6 years ago

    nice work.


    7 years ago

    Thanks for the help. Your article really got me going with this little chip.It is amazing what you can do with it. Chris in Miami


    7 years ago

    The files in the file have been updated to be in compliance with Master v1.4 and dev v1.5.


    7 years ago

    Its very useful for me. I made it. and i want to create a server that can monitor my employees current status (like Available/not in a particular department) and can should provide some buttons for control.

    I dont know Is it possible to monitor and control process at a time???


    Reply 7 years ago

    The ESP can certainly monitor and control at the same time. With NodeMcu, like any micro-controller, the ESP can poll sensors and/or respond to interrupts and it can send/receive data via WIFI polling or responding to interrupts.