Skip to content

Instantly share code, notes, and snippets.

Last active June 7, 2024 03:53
Show Gist options
  • Save willurd/5720255 to your computer and use it in GitHub Desktop.
Save willurd/5720255 to your computer and use it in GitHub Desktop.
Big list of http static server one-liners

Each of these commands will run an ad hoc http static server in your current (or specified) directory, available at http://localhost:8000. Use this power wisely.

Discussion on reddit.

Python 2.x

$ python -m SimpleHTTPServer 8000

Python 3.x

$ python -m http.server 8000

Twisted (Python)

$ twistd -n web -p 8000 --path .


$ python -c 'from twisted.web.server import Site; from twisted.web.static import File; from twisted.internet import reactor; reactor.listenTCP(8000, Site(File(".")));'

Depends on Twisted.


$ ruby -rwebrick -e' => 8000, :DocumentRoot => Dir.pwd).start'

Credit: Barking Iguana

Ruby 1.9.2+

$ ruby -run -ehttpd . -p8000

Credit: nobu

adsf (Ruby)

$ gem install adsf   # install dependency
$ adsf -p 8000

Credit: twome

No directory listings.

Sinatra (Ruby)

$ gem install sinatra   # install dependency
$ ruby -rsinatra -e'set :public_folder, "."; set :port, 8000'

No directory listings.


$ cpan HTTP::Server::Brick   # install dependency
$ perl -MHTTP::Server::Brick -e '$s=HTTP::Server::Brick->new(port=>8000); $s->mount("/"=>{path=>"."}); $s->start'

Credit: Anonymous Monk

Plack (Perl)

$ cpan Plack   # install dependency
$ plackup -MPlack::App::Directory -e 'Plack::App::Directory->new(root=>".");' -p 8000

Credit: miyagawa

Mojolicious (Perl)

$ cpan Mojolicious::Lite   # install dependency
$ perl -MMojolicious::Lite -MCwd -e 'app->static->paths->[0]=getcwd; app->start' daemon -l http://*:8000

No directory listings.

http-server (Node.js)

$ npm install -g http-server   # install dependency
$ http-server -p 8000

Note: This server does funky things with relative paths. For example, if you have a file /tests/index.html, it will load index.html if you go to /test, but will treat relative paths as if they were coming from /.

node-static (Node.js)

$ npm install -g node-static   # install dependency
$ static -p 8000

No directory listings.

PHP (>= 5.4)

$ php -S

Credit: /u/prawnsalad and MattLicense

No directory listings.


$ 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"}]}]).'

Credit: nivertech (with the addition of some basic mime types)

No directory listings.

busybox httpd

$ busybox httpd -f -p 8000

Credit: lvm


$ webfsd -F -p 8000

Depends on webfs.

IIS Express

C:\> "C:\Program Files (x86)\IIS Express\iisexpress.exe" /path:C:\MyWeb /port:8000

Depends on IIS Express.

Credit: /u/fjantomen

No directory listings. /path must be an absolute path.


If you have any suggestions, drop them in the comments below or on the reddit discussion. 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,
  4. require no configuration (from files or otherwise) beyond the command itself (no framework-specific servers, etc)
  5. must run, or have a mode where it can run, in the foreground (i.e. no daemons)
Copy link

npx serve

Yep, this is probably the easiest

Copy link

With serverino:

npx serverino --port 8000

Use --secure to automatically generate a certificate and serve on SSL (at https://localhost:8000).

Copy link

With Sergio - a Kestrel wrapper using Argu:


This will serve the current directory at https://[::]:8080.

To specify listener details:

sergio --listener localhost 8080

To display all options:

sergio --help

Copy link

dbohdan commented May 13, 2021


You will need Tcl 8.6 with Tcllib 1.19 or later.

echo 'package require httpd 4; ::httpd::server create HTTPD port 8000 myaddr doc_root [pwd]; vwait forever' | tclsh

Credit to @rkeene.

Copy link



Copy link

vi commented May 13, 2021

websocat can serve specific explicit list of files on explicit URLs with explicit Content-Types.

websocat -s 1234 -F /index.html:text/html:./index.html -F /script.js:text/javascript:/path/to/thescript.js

There is no ability to automatically include more files based on existence on the filesystem, but sometimes 100% explicit approach may be beneficial.

Copy link

carlosneves0 commented May 13, 2021

docker run --rm --volume "$(pwd):/www:ro" --publish 80:80 /www
docker image ls --format 'table {{.Repository}}:{{.Tag}}\t{{.Size}}' p3terx/darkhttpd:1.13
p3terx/darkhttpd:1.13   91.7kB

docker run --rm --volume "$(pwd):/usr/share/nginx/html:ro" --publish 80:80
docker image ls --format 'table {{.Repository}}:{{.Tag}}\t{{.Size}}' nginx:1.20.0-alpine
nginx:1.20.0-alpine   22.6MB

Copy link

Lwan can be used as an one-liner web server, too: lwan -r /path/to/files/to/serve.

Copy link

Surprised that the once most universal thttpd wasn't even mentioned given how simple and convenient it is:

$ thttpd
$ netstat -ltnp | grep thttpd
tcp6       0      0 :::8080                 :::*                    LISTEN      25130/thttpd        

Copy link

A listening socket is exactly the type of thing I wouldn't want to see in a web browser!

Copy link

Offirmo commented May 15, 2021

Node serve much more professional that the other listed node.js options at this time.

Note that npm doesn't require you to install the package, so a true one-liner would be:

npx serve  --listen 8000
npx node-static -p 8000
npx http-server -p 8000

Thanks for the page!

Copy link


@wtarreau why?

Browsers' security is extremely brittle, and it's already extremely hard for them to protect themselves from abuses by rogue sites and fake ads or limiting the impact of poorly written plugins that always risk to be used to steal user information. By opening them to the outside world using an incoming connection, you're suddenly bypassing a lot of the isolation efforts made in the browser by immediately exposing the process to the outside world. You just need a small bug in the server or a small overlook in the isolation between the server and the rest of the browser and your browser's sensitive info such as passwords, cookies, certificates, or history can immediately leak, or some dummy certs and cookies, or trojans can be inserted.

Copy link

For a ColdFusion / CFML powered web server in the current directory you can use commandbox:

box server start port=8123

The box binary (dependency) can be installed by running brew install commandbox or via several other methods:

Copy link

Winstone, a wrapper around Jetty. Install:

mvn dependency:get -Dartifact=org.jenkins-ci:winstone:5.20 -DremoteRepositories=

and run

java -jar ~/.m2/repository/org/jenkins-ci/winstone/5.20/winstone-5.20.jar --webroot=.

Copy link

Another option in go is goshs

Copy link

meydjer commented Dec 17, 2021

Just found nws which supports basepath:

If you want all requests to resolve to a base path (i.e. http://localhost:3030/basepath) without having to place all files into a src/basepath sub-directory, use the -b flag:

nws -b basepath

Copy link

nahteb commented Mar 30, 2022

In Java 18:

jwebserver -p 8080

Copy link

When running in docker compose along with nominatim-docker

FROM nginx:1.21-alpine

RUN wget &&\
    tar -xvf nominatim-ui-3.2.4.tar.gz --strip-components=1 &&\
    cp -r dist/* /usr/share/nginx/html/ &&\
    sed -i 's/http:\/\/localhost\/nominatim\//http:\/\/nominatim:8080\//g' /usr/share/nginx/html/config.defaults.js


Copy link

georgefst commented May 26, 2022

Haskell, with just Cabal:

echo 'WaiAppStatic.CmdLine.runCommandLine (const id)' | cabal repl -b wai-app-static

It's a bit verbose, but on the plus side you're in a REPL, so it's easy to modify things.

Prompted by a question on Reddit.

Nix alternative

Faster reloads, but relies on my repo, which may not be ideal if one would prefer something more centralised.

nix run github:georgefst/nix-haskell-static-http

Copy link

dkorpel commented Aug 7, 2022

D, with package 'serve':

dub run serve
dub run serve -- path/to/index.html

Copy link

tblaisot commented Sep 9, 2022

for SPA static workload and without dependencies:
npx servor <root> <fallback> <port>

Copy link

x-yuri commented Sep 16, 2022

Failed to install HTTP::Server::Brick in an Alpine container:

Unimplemented: POSIX::tmpnam(): use File::Temp instead at t/serving.t line 87.

And it might be abandoned.

Copy link

SBoteroP commented Jan 8, 2023

Anyone know how to do it with elixir?

Copy link

krackers commented Jan 9, 2023

Another option in go is goshs

For the Go equivalent you could use http.FileServer like . Can also do tls just by changing to ListenAndServeTLS

Copy link

mLuby commented Feb 1, 2023

Submitted for your approval, a NodeJS solution in 123 chars. ⛳


Run it in bash to serve files relative to that directory, and also any file on your computer if given an absolute path. 😱

node -e 'r=require;r("http").createServer((i,o)=>r("stream").pipeline(r("fs").createReadStream(i.url.slice(1)),o,e=>console.log(i.url,e))).listen(8080)'

I prefer the 153-char version that logs out each file request and doesn't serve outside the command's directory. 🪵


Here's that one-liner unobfuscated, deminimized, and explained. 🧑‍🏫

require("http").createServer((request, response) => {
  require("stream").pipeline( // Pipes from each stream to the next ending in a callback to handle errors
    require("fs").createReadStream( // Reads the file at the specified path.
      require("path").join(".", request.url) // Forces the file path to start with this directory,
    ),                                       // so no absolute paths or ../ing upward.
    response, // This is a writable stream so the file read stream pipes into the server response stream.
    (error, value) => { console.log(request.url, error); } // This callback handles the error & we use it
  )                                                        // here to log the filepath.
).listen(8080); // Actually starts the server listening on this port.


Copy link

renich commented Feb 11, 2023

Here's a crystal oneliner:

crystal eval 'require "http/server"; server = [,"./")] ); server.bind_tcp "", 8080; server.listen'


Copy link

python3 -m http.server -d web 8000

for when you want to host a specific directory in one line

Copy link

go run


echo 'package main; import ("net/http"); func main() {fs := http.FileServer(http.Dir(".")); http.Handle("/", fs); println("Listening on http://localhost:8000"); http.ListenAndServe(":8000", nil)}' > main.go; go run main.go; rm main.go

Copy link

radiosilence commented Sep 16, 2023 via email

Copy link

Limiting request to a certain interface (eg.: do not allow request from the network)

python -m http.server --bind

Copy link

Ruby 3.0+ does not include webrick by default, you will have to gem install webrick before you can use any of the Ruby one-liners

The following libraries are no longer bundled gems or standard libraries. Install the corresponding gems to use these features.

  • sdbm
  • webrick
  • net-telnet
  • xmlrpc

Copy link

sancarn commented Oct 5, 2023

@danini-the-panini is there no web server replacement in the standard library?

Copy link

@sancarn unfortunately not. you can see what's in the standard library of each Ruby version here:
net-http is only a client. Since the webrick removal there is no built-in web server included with ruby.

Copy link

RealYukiSan commented Feb 24, 2024

@wtarreau says:

once most universal

not included on arch linux fresh installation

Copy link

is there any command that work on fresh installation of linux system? (no need to install additional package)

Copy link

nilslindemann commented Feb 24, 2024

@RealYukiSan on Linux Mint, Python is installed by default, so $ python -m http.server 8000 works. But Arch seems not to have Python. On Arch, You may try things like this, using netcat. Edit: But I am not sure if that is installed on Arch.

Copy link

is there any command that work on fresh installation of linux system? (no need to install additional package)

Well, in this case on x86 you can use some asm servers such as and just emit their tiny code like this:

base64 -d <<< "H52Qf4owMRKgIICDCBEKADAAQACEYAARQEAjocWDFUE4BIDC4sODYCBKRBBxIiGEJw8eQAjhosuDagyoCaBGQIxtswKg84FQDQQ04EZCmSUA3Yuef67MIoCuRE8AagAoLYAuA0IoiYbFAAaLQC5fI2NIkyWiGaAtsAyYXbdtKywzjZiQIGB2EZ+5wggAQEKFCpQXMVzAACEDxuAnSxooUMwDTQwfSMqwYfMmBI8Xjn0sFAEG" | gzip -cd > httpd ; chmod 755 httpd; ./httpd

Nothing to install except making sure to have base64 and gzip. Or if you really want to have nothing but chmod, you can do that:

echo -ne '\x7fELF\x01\x01\x01\0\0\0\0\0\0\0\0\0\x02\0\x03\0\x01\0\0\0\x60\x80\x04\x08\x34\0\0\0\0\0\0\0\0\0\0\0\x34\0\x20\0\x01\0\x28\0\0\0\0\0\x01\0\0\0\x60\0\0\0\x60\x80\x04\x08\x60\x80\x04\x08\x84\0\0\0\x84\0\0\0\x07\0\0\0\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6a\x06\x6a\x01\x6a\x02\x31\xdb\xb3\x01\xe8\x3e\0\0\0\x6a\x10\x68\xe0\x80\x04\x08\x50\xb3\x02\xe8\x2f\0\0\0\x6a\x7f\x57\xb3\x04\xe8\x25\0\0\0\x6a\0\x6a\0\x57\xb3\x05\xe8\x19\0\0\0\x50\x89\xc3\x31\xc0\xb0\x04\xb9\xbe\x80\x04\x08\x31\xd2\xb2\x22\xcd\x80\x5b\xb0\x06\xcd\x80\xeb\xdb\x31\xc0\xb0\x66\x8d\x4c\x24\x04\xcd\x80\x8b\x7c\x24\x04\xc2\x04\0HTTP/1.0 200 OK\r\n\r\n<h1>Hello!</h1>\x02\0\x22\x60' > httpd; chmod 755 httpd; ./httpd

With some training, you could even learn it to send it only from memory, that could be fun.

Copy link

mieszko4 commented Feb 25, 2024

Well, in this case on x86 you can use some asm servers such as and just emit their tiny code like this:


Copy link

Thanks for the tips @wtarreau @nilslindemann !

With some training, you could even learn it to send it only from memory, that could be fun.

What do you mean by 'send it only from memory'? did you mean execute the instruction without store it to file?

Copy link

I mean memorize it entirely in your head, like people remember Pi, so that you don't have to store it anywhere. It's only 228 bytes after all :-)

Copy link

That's sounds cool! did you wrote it by yourself? I tried to understand the code by running it on gdb, but unfortunately the file not contain any symbol :-(

Copy link

RealYukiSan commented Feb 27, 2024

Ah, my bad. I didn't notice that you provided a reference to the source code.

Copy link

crystal eval 'require "http/server"; server = [,"./")] ); server.bind_tcp "", 8080; server.listen'

That one doesn't seem to work; the downloads get interrupted every time with no stacktrace (Crystal 1.9.2).

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