Skip to content

Instantly share code, notes, and snippets.

@willurd
Last active November 13, 2024 13:44
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 .

Or:

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

Depends on Twisted.

Ruby

$ ruby -rwebrick -e'WEBrick::HTTPServer.new(:Port => 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.

Perl

$ 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 127.0.0.1:8000

Credit: /u/prawnsalad and MattLicense

No directory listings.

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

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

No directory listings.

busybox httpd

$ busybox httpd -f -p 8000

Credit: lvm

webfs

$ 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.

Meta

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)
@radiosilence
Copy link

radiosilence commented Sep 16, 2023 via email

@olejorgenb
Copy link

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

python -m http.server --bind 127.0.0.1

@danini-the-panini
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
source: https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-released/

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

  • sdbm
  • webrick
  • net-telnet
  • xmlrpc

@sancarn
Copy link

sancarn commented Oct 5, 2023

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

@danini-the-panini
Copy link

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

@realyukii
Copy link

realyukii commented Feb 24, 2024

@wtarreau says:

once most universal

not included on arch linux fresh installation

@realyukii
Copy link

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

@nilslindemann
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.

@wtarreau
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 https://github.com/margaretbloom/nash-f/ 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.

@mieszko4
Copy link

mieszko4 commented Feb 25, 2024

Well, in this case on x86 you can use some asm servers such as https://github.com/margaretbloom/nash-f/ and just emit their tiny code like this:

🚀

@realyukii
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?

@wtarreau
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 :-)

@realyukii
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 :-(

@realyukii
Copy link

realyukii commented Feb 27, 2024

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

@DestyNova
Copy link

crystal eval 'require "http/server"; server = HTTP::Server.new( [HTTP::LogHandler.new, HTTP::StaticFileHandler.new("./")] ); server.bind_tcp "127.0.0.1", 8080; server.listen'

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

@air3ijai
Copy link

air3ijai commented Jun 26, 2024

Using Nginx docker image we can set a simple custom index page

# Run
docker run \
  --rm \
  --name nginx \
  --publish 80:80 \
  nginx \
  bash -c "echo host-a >/usr/share/nginx/html/index.html; nginx -g 'daemon off;'"

  # bash -c "echo host-b >/usr/share/nginx/html/index.html; nginx -g 'daemon off;'"
# Check
while true; do curl localhost; sleep 1; done
host-a
host-a
host-a

@mwilsoncoding
Copy link

mwilsoncoding commented Jul 5, 2024

Update for Elixir (1.17.1):

elixir --no-halt -e 'Application.start(:inets); :inets.start(:httpd, port: 8000, server_root: ~c".", document_root: ~c"./doc", server_name: ~c"localhost", mime_types: [{~c"html",~c"text/html"},{~c"htm",~c"text/html"},{~c"js",~c"text/javascript"},{~c"css",~c"text/css"},{~c"gif",~c"image/gif"},{~c"jpg",~c"image/jpeg"},{~c"jpeg",~c"image/jpeg"},{~c"png",~c"image/png"}])'

This example uses the doc directory for a quick way to locally host/view docs generated with ExDoc.

Here's the more readable version of the string being eval'd, shown as an iex session:

iex(1)> Application.start(:inets)
:ok
iex(2)> :inets.start(:httpd,
...(2)>   port: 8000,
...(2)>   server_root: ~c".",
...(2)>   document_root: ~c"./doc",
...(2)>   server_name: ~c"localhost",
...(2)>   mime_types: [
...(2)>     {~c"html", ~c"text/html"},
...(2)>     {~c"htm", ~c"text/html"},
...(2)>     {~c"js", ~c"text/javascript"},
...(2)>     {~c"css", ~c"text/css"},
...(2)>     {~c"gif", ~c"image/gif"},
...(2)>     {~c"jpg", ~c"image/jpeg"},
...(2)>     {~c"jpeg", ~c"image/jpeg"},
...(2)>     {~c"png", ~c"image/png"}
...(2)>   ]
...(2)> )
{:ok, #PID<0.118.0>}

^ woops- just found this

It's not technically a one-liner, but my use-case is better solved with:

mix do hex.docs fetch + docs && cp -r doc "${HEX_HOME}/docs/hexpm/${OTP_APP}/${OTP_APP_VERSION}" && mix hex.docs offline "${OTP_APP}"

@joeky888
Copy link

Deno:

deno run --allow-net --allow-read jsr:@std/http/file-server

@BananaAcid
Copy link

BananaAcid commented Oct 7, 2024

Powershell:

Install-Module -Name Pode

Start-PodeStaticServer -Port 8085

Serves files from current folder.

https://badgerati.github.io/Pode/Functions/Core/Start-PodeStaticServer/

Newbie start:
Set-ExecutionPolicy unrestricted

Install-Module -Name Pode
Import-Module Pode

Start-PodeStaticServer -FileBrowser -Address 0.0.0.0

@johnwyles
Copy link

Powershell:

Install-Module -Name Pode

Start-PodeStaticServer -Port 8085

Serves files from current folder.

Awesome! But just so we’re clear you are able to do 127.0.0.1:8085 and get a portal but also expose that port externally and it hit the local files in the dir?

@BananaAcid
Copy link

Powershell:

Install-Module -Name Pode

Start-PodeStaticServer -Port 8085

Serves files from current folder.

Awesome! But just so we’re clear you are able to do 127.0.0.1:8085 and get a portal but also expose that port externally and it hit the local files in the dir?

with Start-PodeStaticServer -FileBrowser you get a file listing at localhost:8080 / 127.0.0.1:8080 in the current folder

with Start-PodeStaticServer you get index.html serverd by localhost:8080 / 127.0.0.1:8080

with Start-PodeStaticServer -Address 0.0.0.0 binds to all adapters and makes it reachable over network

@pkieltyka
Copy link

$ go run github.com/goware/webify@latest -h

@realyukii
Copy link

@cameronkerrnz

And in case you're wondering where HTTPS is in all this...

Turns out to pretty simple with OpenSSL's s_server utility. I've just used this to help test out a load-balancer configuration before the real backend was ready (not to serve content per-se). The first line creates a self-signed certificate.

openssl req -newkey rsa:2048 -nodes -x509 -subj '/CN=name-you-want.example.com' -days 3650 -out server.cert -keyout server.key
openssl s_server -accept 7781 -cert server.cert -key server.key -WWW

Unfortunately, this does not work for HEAD requests, which is a shame, because the behaviour is to time out.

See the manual page for s_server for more info.

Hello, I tried your snippet command, but I encounter the following error:

Error opening '' mode='r'
80DB80C77E780000:error:80000002:system library:BIO_new_file:No such file or directory:crypto/bio/bss_file.c:67:calling fopen(, r)
80DB80C77E780000:error:10000080:BIO routines:BIO_new_file:no such file:crypto/bio/bss_file.c:75:

is this openssl bug? I'm not sure if I understand the error properly

@harrigan
Copy link

Java has joined the chat:

jwebserver

By default, the server runs in the foreground and binds to the loopback address and port 8000. It serves the current directory.

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