I have a script which generates a daily report which I want to serve to the so called general public. The problem is I don't want to add to my headaches maintance of a HTTP server (e.g. Apache) with all the configurations and security implications.

Is there a dead simple solution for serving one small HTML page without the effort of configuring a full blown HTTP server?


22 Answers 22


Try SimpleHTTPServer:

python3 -m http.server 8080

Or, for Python 2

python -m SimpleHTTPServer 8080

To bind an IP Address, do

python -m SimpleHTTPServer 8080 -b

or for Python 3

python3 -m http.server 8080 -b

It will serve whatever's in the CWD (e.g. index.html) at

  • 32
    You can optionally specify a port number like this: python3 -m http.server 1337. You can't specify which IP to bind to as far as I can tell. Note: To listen to port 80 you must have root privileges, e.g.: sudo python3 -m http.server 80
    – Hubro
    Commented Oct 30, 2014 at 10:49
  • 1
    This one is nice but it has an issue with redirecting to an URL with a trailing slash added. That's why I prefer the twistd version: twistd -n web -p 8000 --path . Commented Jul 14, 2015 at 8:49
  • 2
    To change default listening port 8080 (with python2) to something else, just put a port number after: python -m SimpleHTTPServer 3000 Commented Feb 1, 2019 at 9:56

There is a Big list of http static server one-liners:

To get on this list, a solution must:

  1. serve static files using your current directory (or a specified directory) as the server root
  2. be able to be run with a single, one line command (dependencies are fine if they're a one-time thing)
  3. serve basic file types (html, css, js, images) with proper mime types, require no configuration (from files or otherwise) beyond the command itself (no framework-specific servers, etc)
  4. must run, or have a mode where it can run, in the foreground (i.e. no daemons)

For example:

  • Twisted (Python)

    twistd -n web -p 8000 --path . 
  • Erlang:

    erl -s inets -eval 'inets:start(httpd,[{server_name,"NAME"},{document_root, "."},{server_root, "."},{port, 8000},{mime_types,[{"html","text/html"},{"htm","text/html"},{"js","text/javascript"},{"css","text/css"},{"gif","image/gif"},{"jpg","image/jpeg"},{"jpeg","image/jpeg"},{"png","image/png"}]}]).'
  • Plack (Perl)

    cpan Plack
    plackup -MPlack::App::Directory -e 'Plack::App::Directory->new(root=>".");' -p 8000
  • webfs

    webfsd -F -p 8000
  • Ruby 1.9.2+

    ruby -run -ehttpd . -p8000

Use node.js , fast and lightweight.


just use simple nc netcat command to start a quick webserver on a port and serve the content of a file including the server response headers.

Reference from Wikipedia:


{ echo -ne "HTTP/1.0 200 OK\r\n\r\n"; cat some.file; } | nc -l -p 8080
{ echo -ne "HTTP/1.0 200 OK\r\nContent-Length: $(wc -c <some.file)\r\n\r\n"; cat some.file; } | nc -l -p 8080
  • 53
    A bare node.js process with only the interactive shell running takes 15MB (7.5 is shared) of RAM. And then you have to run the HTTP server inside it. It is funny that people see it as lightweight. ;-)
    – jpc
    Commented Mar 2, 2012 at 14:00
  • yeah I consider it light weight, you can scale well with such less memory footprint. Please read thecodinghumanist.com/blog/archives/2011/5/6/… However, if you find it cumbersome to use node.js, then the simple netcat utility serves the short lived purpose well. Commented Mar 2, 2012 at 15:28
  • 2
    You are of course right if you compare node with Apache but what I found amusing was how node looks when compared to cr.yp.to/publicfile.html or something similar. :)
    – jpc
    Commented Mar 6, 2012 at 10:54
  • 14
    +1 for the nc based solution :). Note that the -ne flags for echo may not be portable, using the printf command instead may be a better alternative. Commented Nov 5, 2016 at 9:35
  • 2
    Chrome won't stop throbbing unless you use the second nc command. Also, not both of the nc commands show will quit after responding. You can keep restarting it with: while :; do { echo -ne "HTTP/1.0 200 OK\r\nContent-Length: $(wc -c <some.file)\r\n\r\n"; cat some.file; } | nc -l -p 8080; done. Use ctrl+z to but it to sleep.
    – Ray Foss
    Commented Mar 7, 2019 at 18:10

Since version 5.4.0 PHP also has a built-in web server:

php -S localhost:8000

You can Specify the web server's documents directory with -t, for example:

php -S localhost:8000 -t /var/lib/www

If you want to be able to access the server over the network then:

php -S -t /var/lib/www
  • 2
    Wow that was easy and helpful!
    – Michael-O
    Commented May 16, 2015 at 19:08
  • This one is really nice if you want to test php-scripts locally.
    – erik
    Commented Jul 27, 2015 at 9:51

Yes, nweb.

Can be found here: nweb.c

(previously at ibm.com)

To compile nweb.c:

gcc -O -DLINUX nweb.c -o nweb
  • 1
    It works well, but 2 comments for users: 1) it serves index.html from the provided directory, 2) from nweb --help: "Not Supported: URLs including "..", Java, Javascript, CGI". So, for example, Live.js to automatically refresh the page on file update does not work.
    – xealits
    Commented Dec 13, 2019 at 13:41
  • That's right, but you actually just need to add the wanted extensions to the list of mime types for the files to be served. Same for index.html, you can adjust that very easely.
    – Hexdump
    Commented May 1, 2022 at 15:13

Node has a simple, fast, light HTTP server module. To install:

sudo npm install http-server -g

(Assuming you have node and npm already installed.)

To run it, using the current directory as the website root:


This creates a server on

  • It works. I have a Node project on a FreeBSD machine, I just run npm install -D http-server inside project directory and then add the following lines to my package.json file: "scripts": { "build": "webpack && cd src/public && http-server" }, now I just need to run npm run build on project directory to start the HTTP server, listening on port 8080 by default.
    – Megidd
    Commented Sep 14, 2017 at 12:52
  • 3
    First I tried "python3 -m http.server", but it's single-threaded and only 1 client can download at a time, the others need to wait. This solution with Node.js works better, due to the async nature of Node. If you want to share a file with several people, use this.
    – Jabba
    Commented Sep 14, 2017 at 16:14
  • 1
    The module may be "light", node.js isn't. You'd be running a JS runtime just to serve static files.
    – c z
    Commented Dec 17, 2020 at 15:02
  • To add CORS support: http-server -p 3000 --cors
    – human
    Commented Apr 5, 2022 at 5:13

A simple fix/enhancement to a slightly unfairly (imho) down voted answer might also work. Let's set up the html file first ...

echo '<html><head><title>My Test File</title></head><body><h1>OK!</h1></body></html>' > my_file.html

(Thx to Steve Folly for catching my typo in the HTML above. fixed.)

Now you can serve it up with this one-liner:

while true; do echo -e "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n" | cat - my_file.html  | nc -l -p 8080; done

This basic idea lends itself to other tricks that might work for you via other cat or subshell ideas such as:

while true; do echo -e "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\nI think the date is $(date), Have a good day!" | nc -l -p 8080; done

Simple Ruby one liner to serve a directory:

ruby -run -e httpd . -p 8080

Try using SimpleHTTPServer in Python.

mkdir ~/public_html
command_to_generate_output > ~/public_html/output.txt

(cd ~/public_html; python -c 'import SimpleHTTPServer,BaseHTTPServer; BaseHTTPServer.HTTPServer(("", 8080), SimpleHTTPServer.SimpleHTTPRequestHandler).serve_forever()')

The first two lines are setup for the web server. The last line creates a simple web server, opened on port 8080, which only serves files from ~/public_html. If only one file is in that directory, then only that is exposed: http://localhost:8080/output.txt.

  • that's what i use, just copy the lastline and paste it on a .py file, then run it with python (or make it executable). Keep in mind that you have to run with python 2.x interpreter.
    – Hanan
    Commented Feb 20, 2012 at 21:40

try caddy

curl https://getcaddy.com | bash

serve content from /var/www caddy -root /var/www "browse"

now you find the server at http://localhost:2015

  • I love to just caddy from a local directory and enjoy having a modern and secure webserver.
    – Duvrai
    Commented Oct 16, 2019 at 8:54

Another option would be to install lighttpd. Following are suggested steps to install lighttpd on a Unbuntu 12.04 LTS.

apt-get update
apt-get upgrade --show-upgraded
apt-get install lighttpd
/etc/lighttpd/lighttpd.conf (Edit to add server.port)
server.port = "8080"

Note: Documentroot is where all web accessible files will be places. The location is /var/wwww

The above step will install a basic lighttpd web server. For more information refer the following references



./devd -o -a -P devd:devd .

  • -o opens url in browser
  • -a for all interfaces
  • -P auth user/pass
  • . serve files in same directory



I've improved the nc solution a bit so it:

  • Adds the filename= hint,
  • Runs in a loop until Ctrl + C,
  • Saves a PID to /tmp/serveFile-$PORT so you can kill it later easily.



if [ "$FILE" == "" ] ; then echo "Usage: $0 <file-to-serve> [<port:7979>]"; exit; fi
echo Serving $FILE at $PORT, PID: $$
echo $$ > /tmp/serveFilePID-$PORT

while true; do 
    { echo -ne "HTTP/1.0 200 OK\r\nContent-Length: $(wc -c <$FILE)\r\nContent-Disposition: inline; filename=\"$(basename $FILE)\"\r\n\r\n"; cat $FILE; } | nc -l $PORT
    #echo "Code: $CODE";
    if [ $CODE -gt 128 ] ; then break; fi;

rm /tmp/serveFilePID-$PORT

One could also use nc -k -l ... but this way you can

  • do custom actions between files served,
  • make several files alternate.

Simple netcat example to put in bash script:

while true ; do nc -l 80 <index.html ; done 
  • 16
    That entirely fails to speak HTTP.
    – derobert
    Commented Aug 6, 2014 at 11:54
  • 1
    I tried while [ 1=1 ] ; do echo "TEST" | nc -l 80; done - going to indeed returns the contents. I had to do that as root though. So in an extremely crude way - it can get the job done, and I like that. I tried going to my-hostnname.local on another machine in the LAN and it worked too.
    – unfa
    Commented Dec 11, 2017 at 11:33

Oldschool Ruby WEBrick HTTP server:

#!/usr/bin/env ruby

require 'webrick'
server = WEBrick::HTTPServer.new(:Port => 8000,
                                 :DocumentRoot => '~/webrickroot')

# stop server with Ctrl-C
trap('INT') { server.stop }

Make sure to modify the DocumentRoot for your setup. See also this.


You can piggy back on xinetd. Put the following config file into /etc/xinetd.d/ and service xinetd reload:

service http
  flags = REUSE IPv4
  protocol = tcp
  socket_type = stream
  port = 80
  wait = no
  user = nobody
  server = /bin/echo
  server_args = -e HTTP/1.0 301 Moved Permanently\nContent-Length: 0\nLocation: https://goo.gl/\n\n
  disable = no

Works for my redirecting purposes:

# wget
--2016-04-04 22:56:20--
Connecting to connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: https://goo.gl/ [following]

I used these instructions to install a web server on my CentOS machine without having to use sudo or touch any system files:

First install node (see the latest available version of the nodejs package here and change the package filename in the wget):

$ cd ~
$ wget https://nodejs.org/download/release/latest/node-v18.10.0-linux-x64.tar.gz
$ tar node-v18.10.0-linux-x64.tar.gz

then install http-server:

$ export PATH=~/node-v18.10.0-linux-x64/bin:$PATH
$ npm install http-server

then run http-server on port 12321:

$ ~/node-v18.10.0-linux-x64/bin/node_modules/http-server/bin/http-server -p 12321
  • For future readers coming here from search: this is using a sledgehammer to crack a nut. There are many easier and smaller solutions (e.g. stackoverflow.com/questions/4994638/… suggested in question comments).
    – kiler129
    Commented Dec 21, 2022 at 20:15

SFK worth mentioning here


an excellent multipurpose tool with no dependencies

available in both deb and rpm flavours

sfk httpserv -port 1234

will serve current directory

sfk httpserv -port 1234 -rw

will also allow file uploading


My five cents, written in shell: https://gitlab.com/mezantrop/supermatic

Supermatic can run on FreeBSD and any other OS which has Bourne Shell and inetd-like daemon. It serves static HTML and TXT files along with GIF, JPEG and PNG image formats. What's about any other standards and features? No, never heard of them.


A docker based one liner so you don't have to have any particular language installed:

docker run --rm -i -p 8000:8000 -v $(pwd):/app -w /app ruby:alpine ruby -run -ehttpd . -p8000

Pure bash: A web server in a shell script.

Also, you'll need xinetd (I believe available in any distro) to listen port and run the script when needed, so you don't have to code tcp stack etc in bash.


To nweb.c I have added directory listing functionality. https://github.com/jbabuc/nweb

nweb.c, simple http server with directory listing.
nwebs, statically compiled binary for linux.

  • Welcome to the site, and thank you for your contribution. Please note that nweb was already mentioned in the accepted answer. Please review your answer and check if you can add anything new to make it more distinct. Alternatively, consider submitting an edit proposal to the accepted answer.
    – AdminBee
    Commented Mar 18, 2021 at 14:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .