Skip to content

Instantly share code, notes, and snippets.

@ryanflorence
Last active July 3, 2025 03:26
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");
@amejiarosario
Copy link

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

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

@kovid-rathee
Copy link

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

@duluca
Copy link

duluca commented Feb 28, 2017

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

@Julia991
Copy link

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
Copy link

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
Copy link

robole commented Jun 26, 2017

ty. min req, what i was after

@dkebler
Copy link

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
Copy link

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
Copy link

Thanks a lot :)

@mandaputtra
Copy link

Thanks a lot, but it can be hijacked

@XMB5
Copy link

XMB5 commented Jun 10, 2018

This is insecure, someone can request /../../../etc/shadow or similar to read any file they want.

@Abd-Elrazek
Copy link

thanks ...it's great, that why I'm looking for it

@CCorb
Copy link

CCorb commented Feb 29, 2020

path.exists is now called fs.exists

@unsaved
Copy link

unsaved commented Mar 19, 2020

This is insecure, someone can request /../../../etc/shadow or similar to read any file they want.

I guess you're not familiar with how path.join works, because as coded here it won't resolve to a directory outside of cwd directory branch.

@rpivo
Copy link

rpivo commented Apr 12, 2021

fs.exists is deprecated. fs.statSync can be used to check if file path exists, as in dkebler's code above.

@codespede
Copy link

Thank you for this!

@Anna-art125
Copy link

Incredible article, thanks for sharing it! I think this article will also be useful for you - Node js vs Python.

@JafarAkhondali
Copy link

I'm 15 years late to the party, but this is indeed insecure. PoC:
curl --path-as-is http://localhost:8888/../../../../../../../../etc/passwd

By default, when you send HTTP requests using curl, they'll be normalized. With --path-as-is flag you can prevent normalization, thus the exploit works. The same thing happens if you test the PoC in your browser. I think that's why most people didn't find the vulnerability.

This is insecure, someone can request /../../../etc/shadow or similar to read any file they want.

I guess you're not familiar with how path.join works, because as coded here it won't resolve to a directory outside of cwd directory branch.

No, I think you're not familiar with how path.join works, there is no mitigation for the directory boundary check here. We wrote a paper about this vulnerability as it spread almost EVERYWHERE.

You can test it in Node:
node -e 'console.log(path.join("/opt/app/www", "/../../../../etc/passwd")) // It will print /etc/passwd'

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