Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Node.JS static file web server. Put it in your path to fire up servers in any directory, takes an optional port argument.
var http = require("http"),
url = require("url"),
path = require("path"),
fs = require("fs")
port = process.argv[2] || 8888;
http.createServer(function(request, response) {
var uri = url.parse(request.url).pathname
, filename = path.join(process.cwd(), uri);
path.exists(filename, function(exists) {
if(!exists) {
response.writeHead(404, {"Content-Type": "text/plain"});
response.write("404 Not Found\n");
response.end();
return;
}
if (fs.statSync(filename).isDirectory()) filename += '/index.html';
fs.readFile(filename, "binary", function(err, file) {
if(err) {
response.writeHead(500, {"Content-Type": "text/plain"});
response.write(err + "\n");
response.end();
return;
}
response.writeHead(200);
response.write(file, "binary");
response.end();
});
});
}).listen(parseInt(port, 10));
console.log("Static file server running at\n => http://localhost:" + port + "/\nCTRL + C to shutdown");
@davidgovea

This comment has been minimized.

Show comment Hide comment
@davidgovea

davidgovea Aug 3, 2011

Thank you!

Thank you!

@agentgt

This comment has been minimized.

Show comment Hide comment
@agentgt

agentgt Aug 31, 2011

likewise on the thank you!

agentgt commented Aug 31, 2011

likewise on the thank you!

@jameswomack

This comment has been minimized.

Show comment Hide comment
@jameswomack

jameswomack Nov 30, 2011

Thank you for making this available

Thank you for making this available

@hhadri

This comment has been minimized.

Show comment Hide comment
@hhadri

hhadri Jan 28, 2012

Thank you!

hhadri commented Jan 28, 2012

Thank you!

@respectTheCode

This comment has been minimized.

Show comment Hide comment
@respectTheCode

respectTheCode Feb 27, 2012

This doesn't set the mim type. You can use the mime module like this https://gist.github.com/1926868

This doesn't set the mim type. You can use the mime module like this https://gist.github.com/1926868

@shahalpk

This comment has been minimized.

Show comment Hide comment
@shahalpk

shahalpk Mar 5, 2012

Thanks a lot!

shahalpk commented Mar 5, 2012

Thanks a lot!

@manhhung741

This comment has been minimized.

Show comment Hide comment
@manhhung741

manhhung741 Mar 16, 2012

thanks XD

thanks XD

@tonylukasavage

This comment has been minimized.

Show comment Hide comment
@tonylukasavage

tonylukasavage Mar 27, 2012

Great stuff, exactly what I was looking for.

Great stuff, exactly what I was looking for.

@hamxiaoz

This comment has been minimized.

Show comment Hide comment
@hamxiaoz

hamxiaoz Mar 28, 2012

You may use the non-static module as well

You may use the non-static module as well

@mattrudder

This comment has been minimized.

Show comment Hide comment
@mattrudder

mattrudder Apr 2, 2012

Thanks for this! :)

Thanks for this! :)

@dylantack

This comment has been minimized.

Show comment Hide comment
@dylantack

dylantack Apr 10, 2012

Careful! This code is vulnerable to a directory traversal attack.

Careful! This code is vulnerable to a directory traversal attack.

@tonylukasavage

This comment has been minimized.

Show comment Hide comment
@tonylukasavage

tonylukasavage Apr 10, 2012

I'm just using it for a local web preview anyway

I'm just using it for a local web preview anyway

@smurph269

This comment has been minimized.

Show comment Hide comment
@smurph269

smurph269 Jul 1, 2012

I'm just getting started with node.js and backbone.js and this has been perfect for setting up demo apps quickly.

I'm just getting started with node.js and backbone.js and this has been perfect for setting up demo apps quickly.

@alexblackie

This comment has been minimized.

Show comment Hide comment
@alexblackie

alexblackie Aug 3, 2012

I needed to put up a holding page for a website I was building and this was an awesome lightweight solution... Thanks!

I needed to put up a holding page for a website I was building and this was an awesome lightweight solution... Thanks!

@jagtesh

This comment has been minimized.

Show comment Hide comment
@jagtesh

jagtesh Jan 8, 2013

Just what I was looking for. Danke Shoen!

jagtesh commented Jan 8, 2013

Just what I was looking for. Danke Shoen!

@yaniv-aknin

This comment has been minimized.

Show comment Hide comment
@yaniv-aknin

yaniv-aknin Jan 20, 2013

Consider also python -m SimpleHTTPServer 888 or twistd -n web -p 8888 --path .. The former is installed pretty much anywhere where there's Python, the latter is better performing and is bundled with many distributions including Mac OSX - no need for pasting/downloading another file.

Consider also python -m SimpleHTTPServer 888 or twistd -n web -p 8888 --path .. The former is installed pretty much anywhere where there's Python, the latter is better performing and is bundled with many distributions including Mac OSX - no need for pasting/downloading another file.

@yosske

This comment has been minimized.

Show comment Hide comment
@yosske

yosske Jan 21, 2013

Thanks!

yosske commented Jan 21, 2013

Thanks!

@Filirom1

This comment has been minimized.

Show comment Hide comment
@Filirom1

Filirom1 Feb 11, 2013

So good !

So good !

@Premier

This comment has been minimized.

Show comment Hide comment
@Premier

Premier Feb 24, 2013

Great!

Premier commented Feb 24, 2013

Great!

@axelsears

This comment has been minimized.

Show comment Hide comment
@axelsears

axelsears Mar 11, 2013

Thank you, this rocks!

Thank you, this rocks!

@ubinix-warun

This comment has been minimized.

Show comment Hide comment
@ubinix-warun

ubinix-warun Mar 18, 2013

Thanks!

Thanks!

@Waxolunist

This comment has been minimized.

Show comment Hide comment
@Waxolunist

Waxolunist Apr 26, 2013

path.exists should be changed to fs.exists

path.exists should be changed to fs.exists

@kljensen

This comment has been minimized.

Show comment Hide comment
@kljensen

kljensen Oct 30, 2013

Nice! I typically use

python -m SimpleHTTPServer

to serve the cwd.

Nice! I typically use

python -m SimpleHTTPServer

to serve the cwd.

@srgg6701

This comment has been minimized.

Show comment Hide comment
@srgg6701

srgg6701 Dec 5, 2013

Brilliant solution!

srgg6701 commented Dec 5, 2013

Brilliant solution!

@samof76

This comment has been minimized.

Show comment Hide comment
@samof76

samof76 Feb 4, 2014

fantastic.... love this!

samof76 commented Feb 4, 2014

fantastic.... love this!

@adamgibbons

This comment has been minimized.

Show comment Hide comment
@adamgibbons

adamgibbons Feb 25, 2014

nice, this totally is the javascript spirit of the python SimpleHTTPServer

nice, this totally is the javascript spirit of the python SimpleHTTPServer

@serverwentdown

This comment has been minimized.

Show comment Hide comment
@serverwentdown

serverwentdown Mar 2, 2014

I dumped in piping because I was using it to transfer larger files. May be slow... gist

I dumped in piping because I was using it to transfer larger files. May be slow... gist

@aamirafridi

This comment has been minimized.

Show comment Hide comment
@aamirafridi

aamirafridi Apr 9, 2014

Great example to understand

Great example to understand

@Lordoomer

This comment has been minimized.

Show comment Hide comment
@Lordoomer

Lordoomer Apr 17, 2014

Wow the first one that works for me thank very much for this code!
Well, it works everywhere except in...surprise: IE11 & <

Wow the first one that works for me thank very much for this code!
Well, it works everywhere except in...surprise: IE11 & <

@Ajedi32

This comment has been minimized.

Show comment Hide comment
@Ajedi32

Ajedi32 Apr 21, 2014

Quick question: does this script ensure that data in higher-level directories is inaccessible via http requests? E.g. I can't request /../../../../.ssh/id_rsa (just an example) and have it send that data to me?

Ajedi32 commented Apr 21, 2014

Quick question: does this script ensure that data in higher-level directories is inaccessible via http requests? E.g. I can't request /../../../../.ssh/id_rsa (just an example) and have it send that data to me?

@samuelfine

This comment has been minimized.

Show comment Hide comment
@samuelfine

samuelfine May 9, 2014

@dylantack @Ajedi32 I was concerned about this as well, but after some quick testing it appears that url.parse is sanitizing the requested path. For example, if this node server is running from /home and you try visiting 1.2.3.4:8888/../../../../.ssh/id_rsa it resolves to /home/.ssh/id_rsa.

@dylantack @Ajedi32 I was concerned about this as well, but after some quick testing it appears that url.parse is sanitizing the requested path. For example, if this node server is running from /home and you try visiting 1.2.3.4:8888/../../../../.ssh/id_rsa it resolves to /home/.ssh/id_rsa.

@tahiralvi

This comment has been minimized.

Show comment Hide comment
@tahiralvi

tahiralvi May 14, 2014

Thanks.

Thanks.

@nathanbuckley

This comment has been minimized.

Show comment Hide comment
@nathanbuckley

nathanbuckley May 26, 2014

Great work, Thanks

Great work, Thanks

@bgkittrell

This comment has been minimized.

Show comment Hide comment
@bgkittrell

bgkittrell Jun 13, 2014

FYI, if you're serving media files you might want to look at the send module. It will handle large files better, and Partial Content requests (important for HTML5 video).

https://github.com/visionmedia/send

FYI, if you're serving media files you might want to look at the send module. It will handle large files better, and Partial Content requests (important for HTML5 video).

https://github.com/visionmedia/send

@Jerska

This comment has been minimized.

Show comment Hide comment
@Jerska

Jerska Aug 29, 2014

To be sure to avoid transversal directory attacks without relying on url.parse, one could also do

var cwd = process.cwd();
http.createServer (function (req, res) {
    var uri = url.parse(req.url).pathname,
        filename = path.join(cwd, uri);
    if (filename.indexOf(cwd) !== 0)
        // Abort
}

Also, I would use filename = path.join(filename, 'index.html') instead of filename += '/index.html'. / isn't necessarily the OS separator, or we wouldn't use a path module.

Jerska commented Aug 29, 2014

To be sure to avoid transversal directory attacks without relying on url.parse, one could also do

var cwd = process.cwd();
http.createServer (function (req, res) {
    var uri = url.parse(req.url).pathname,
        filename = path.join(cwd, uri);
    if (filename.indexOf(cwd) !== 0)
        // Abort
}

Also, I would use filename = path.join(filename, 'index.html') instead of filename += '/index.html'. / isn't necessarily the OS separator, or we wouldn't use a path module.

@johnjqc

This comment has been minimized.

Show comment Hide comment
@johnjqc

johnjqc Jan 7, 2015

muy bueno, gracias

johnjqc commented Jan 7, 2015

muy bueno, gracias

@meetkiran

This comment has been minimized.

Show comment Hide comment
@meetkiran

meetkiran Feb 4, 2015

thanks a lot dude

thanks a lot dude

@brandt1871

This comment has been minimized.

Show comment Hide comment
@brandt1871

brandt1871 Apr 15, 2015

Many thanks.

Shouldn't the method "exists" be used with fs instead of path?
On line 12 of the code we have:

path.exists(filename, function(exists) {...});

This gave me an error and it seemed fine after I replaced it with:

fs.exists(filename, function(exists) {...});

Many thanks.

Shouldn't the method "exists" be used with fs instead of path?
On line 12 of the code we have:

path.exists(filename, function(exists) {...});

This gave me an error and it seemed fine after I replaced it with:

fs.exists(filename, function(exists) {...});
@einsiol

This comment has been minimized.

Show comment Hide comment
@einsiol

einsiol Jun 7, 2015

Agree with the last comment, replacing path.exist with fs.exist fixed an error that I did not fully understand. Otherwise, fantastic solution, perfect for beginners :)

einsiol commented Jun 7, 2015

Agree with the last comment, replacing path.exist with fs.exist fixed an error that I did not fully understand. Otherwise, fantastic solution, perfect for beginners :)

@raidenz

This comment has been minimized.

Show comment Hide comment
@raidenz

raidenz Jun 23, 2015

yes thanks brandt1871 path.exists is now called fs.exists

raidenz commented Jun 23, 2015

yes thanks brandt1871 path.exists is now called fs.exists

@fordnox

This comment has been minimized.

Show comment Hide comment
@fordnox

fordnox Jul 17, 2015

Same issue here, path.exists is now called fs.exists

Please fix for future generations :)

fordnox commented Jul 17, 2015

Same issue here, path.exists is now called fs.exists

Please fix for future generations :)

@ratneshnavlakhe

This comment has been minimized.

Show comment Hide comment
@ratneshnavlakhe

ratneshnavlakhe Aug 24, 2015

Thanks!!!

Thanks!!!

@Deele

This comment has been minimized.

Show comment Hide comment
@Deele

Deele Sep 28, 2015

Please, include package.json so that we could npm install. Thanks!

Deele commented Sep 28, 2015

Please, include package.json so that we could npm install. Thanks!

@bye-webster

This comment has been minimized.

Show comment Hide comment
@bye-webster

bye-webster Nov 14, 2015

You saved my day brotha.. Thanks :) ~

You saved my day brotha.. Thanks :) ~

@CustomsoftGH

This comment has been minimized.

Show comment Hide comment
@CustomsoftGH

CustomsoftGH Jan 8, 2016

For those newbies out there, path.exists has been depricated to fs.exists.

For those newbies out there, path.exists has been depricated to fs.exists.

@harismohammed

This comment has been minimized.

Show comment Hide comment
@harismohammed

harismohammed Jan 23, 2016

thank u

thank u

@evenfrost

This comment has been minimized.

Show comment Hide comment
@evenfrost

evenfrost May 18, 2016

If anyone is interested in ES6+ version, I've revamped it here.

If anyone is interested in ES6+ version, I've revamped it here.

@kostasx

This comment has been minimized.

Show comment Hide comment
@kostasx

kostasx May 23, 2016

Small typo: fs = require("fs") is missing a comma at the end of the line, making port on the next line a global variable.
Thank you for sharing!

kostasx commented May 23, 2016

Small typo: fs = require("fs") is missing a comma at the end of the line, making port on the next line a global variable.
Thank you for sharing!

@archasek

This comment has been minimized.

Show comment Hide comment
@archasek

archasek Jun 9, 2016

Fixed the whole code. Enjoy :)

var http = require("http"),
    url = require("url"),
    path = require("path"),
    fs = require("fs"),
    port = process.argv[2] || 8888;

http.createServer(function(request, response) {

  var uri = url.parse(request.url).pathname
    , filename = path.join(process.cwd(), uri);

  fs.exists(filename, function(exists) {
    if(!exists) {
      response.writeHead(404, {"Content-Type": "text/plain"});
      response.write("404 Not Found\n");
      response.end();
      return;
    }

    if (fs.statSync(filename).isDirectory()) filename += '/index.html';

    fs.readFile(filename, "binary", function(err, file) {
      if(err) {        
        response.writeHead(500, {"Content-Type": "text/plain"});
        response.write(err + "\n");
        response.end();
        return;
      }

      response.writeHead(200);
      response.write(file, "binary");
      response.end();
    });
  });
}).listen(parseInt(port, 10));

console.log("Static file server running at\n  => http://localhost:" + port + "/\nCTRL + C to shutdown");

archasek commented Jun 9, 2016

Fixed the whole code. Enjoy :)

var http = require("http"),
    url = require("url"),
    path = require("path"),
    fs = require("fs"),
    port = process.argv[2] || 8888;

http.createServer(function(request, response) {

  var uri = url.parse(request.url).pathname
    , filename = path.join(process.cwd(), uri);

  fs.exists(filename, function(exists) {
    if(!exists) {
      response.writeHead(404, {"Content-Type": "text/plain"});
      response.write("404 Not Found\n");
      response.end();
      return;
    }

    if (fs.statSync(filename).isDirectory()) filename += '/index.html';

    fs.readFile(filename, "binary", function(err, file) {
      if(err) {        
        response.writeHead(500, {"Content-Type": "text/plain"});
        response.write(err + "\n");
        response.end();
        return;
      }

      response.writeHead(200);
      response.write(file, "binary");
      response.end();
    });
  });
}).listen(parseInt(port, 10));

console.log("Static file server running at\n  => http://localhost:" + port + "/\nCTRL + C to shutdown");
@CforED

This comment has been minimized.

Show comment Hide comment
@CforED

CforED Jul 4, 2016

Hi, Everyone:

Problem: There is a failure in the JavaScript code (server.js) to route a var to the following directory: ./public/index.html.

Symptoms: HTTP Error 403.14 - Forbidden.

Request for Support: What is the correct JavaScript to route var to a particular directory?

URL References:

1.) GitHub URL link: https://github.com/CforED/WebSite/blob/master/server.js

2.) Gist URL link: https://gist.github.com/CforED/177a2e73dfb87313576376fc00a2c9f4.js

3.) GitHub URL link to website:
https://github.com/CforED/WebSite/tree/master/public

Hal

CforED commented Jul 4, 2016

Hi, Everyone:

Problem: There is a failure in the JavaScript code (server.js) to route a var to the following directory: ./public/index.html.

Symptoms: HTTP Error 403.14 - Forbidden.

Request for Support: What is the correct JavaScript to route var to a particular directory?

URL References:

1.) GitHub URL link: https://github.com/CforED/WebSite/blob/master/server.js

2.) Gist URL link: https://gist.github.com/CforED/177a2e73dfb87313576376fc00a2c9f4.js

3.) GitHub URL link to website:
https://github.com/CforED/WebSite/tree/master/public

Hal

@amejiarosario

This comment has been minimized.

Show comment Hide comment
@amejiarosario

amejiarosario Aug 24, 2016

I created a new one that handles MIME types and uses ES6+

https://gist.github.com/amejiarosario/53afae82e18db30dadc9bc39035778e5

I created a new one that handles MIME types and uses ES6+

https://gist.github.com/amejiarosario/53afae82e18db30dadc9bc39035778e5

@kovid-rathee

This comment has been minimized.

Show comment Hide comment
@kovid-rathee

kovid-rathee Feb 3, 2017

Got an error with path.exists, changed it to fs.exists and the snippet worked fine.

Got an error with path.exists, changed it to fs.exists and the snippet worked fine.

@duluca

This comment has been minimized.

Show comment Hide comment
@duluca

duluca Feb 28, 2017

@kovid-rathee I ran in to the same issue and your solution worked!

duluca commented Feb 28, 2017

@kovid-rathee I ran in to the same issue and your solution worked!

@Julia991

This comment has been minimized.

Show comment Hide comment
@Julia991

Julia991 Mar 28, 2017

Hey, guys what do you think about this article?
he best Node.js framework for your project: Express.js, Koa.js or Sails.js is express js the best framework for Node js?

Hey, guys what do you think about this article?
he best Node.js framework for your project: Express.js, Koa.js or Sails.js is express js the best framework for Node js?

@cmshiyas

This comment has been minimized.

Show comment Hide comment
@cmshiyas

cmshiyas Jun 14, 2017

Awesome! I am new to Node.js and was trying to figure out how to configure this...This worked with a minor update as givne in another post creationix/howtonode.org#88
Thank you very much!

Awesome! I am new to Node.js and was trying to figure out how to configure this...This worked with a minor update as givne in another post creationix/howtonode.org#88
Thank you very much!

@robole

This comment has been minimized.

Show comment Hide comment
@robole

robole Jun 26, 2017

ty. min req, what i was after

robole commented Jun 26, 2017

ty. min req, what i was after

@dkebler

This comment has been minimized.

Show comment Hide comment
@dkebler

dkebler Oct 31, 2017

path.exists has been deprecated. If you want a sync check then

  if (!fs.statSync(filename)) {
    response.writeHead(404, {'Content-Type': 'text/plain'})
    response.write('404 Not Found\n')
    response.end()
    return
  }

dkebler commented Oct 31, 2017

path.exists has been deprecated. If you want a sync check then

  if (!fs.statSync(filename)) {
    response.writeHead(404, {'Content-Type': 'text/plain'})
    response.write('404 Not Found\n')
    response.end()
    return
  }
@dkebler

This comment has been minimized.

Show comment Hide comment
@dkebler

dkebler Oct 31, 2017

even better how about the handler's fs stuff all async with callbacks

fs.stat(filename, function(err,stats) {
    if (err) {
      response.writeHead(404, {'Content-Type': 'text/plain'})
      response.write('404 Not Found\n')
      response.end()
      return
    }

    if (stats.isDirectory()) filename += '/index.html'

    fs.readFile(filename, 'binary', function(err, file) {
      if(err) {
        response.writeHead(500, {'Content-Type': 'text/plain'})
        response.write(err + '\n')
        response.end()
        return
      }
      response.writeHead(200)
      response.write(file, 'binary')
      response.end()
    })
  })

dkebler commented Oct 31, 2017

even better how about the handler's fs stuff all async with callbacks

fs.stat(filename, function(err,stats) {
    if (err) {
      response.writeHead(404, {'Content-Type': 'text/plain'})
      response.write('404 Not Found\n')
      response.end()
      return
    }

    if (stats.isDirectory()) filename += '/index.html'

    fs.readFile(filename, 'binary', function(err, file) {
      if(err) {
        response.writeHead(500, {'Content-Type': 'text/plain'})
        response.write(err + '\n')
        response.end()
        return
      }
      response.writeHead(200)
      response.write(file, 'binary')
      response.end()
    })
  })
@Risyandi

This comment has been minimized.

Show comment Hide comment
@Risyandi

Risyandi Apr 19, 2018

Thanks a lot :)

Thanks a lot :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment