
HTTP static server one-liners - known
https://gist.github.com/willurd/5720255
======
tyingq
I'm pushing the definition of "one liner" here, and it's got some major
shortcomings (including directory traversal!), but here's one with Gnu awk:

    
    
      gawk '@load "filefuncs";func send(s,e,d,t,b) {;print "HTTP/1.0 "s" "e|&S;print "Content-Length: "b|&S;print"Content-Type: "t|&S;print d|&S;close(S);}func mt(f) {;c = "file -b --mime-type " f;r="";while ((c|getline z)>0) {;r=r z;}  ;close(c);return r;} ;BEGIN {RS=ORS="\r\n";while(1){;S="/inet/tcp/8080/0/0";while((S|&getline l)>0) {;split(l,f," ");if(f[1]=="GET"){p=substr(f[2],2)}if(p==""){p="index.html"}stat(p,s);if (s["type"]=="file") {;m=mt(p);while ((getline i <p)>0){o=o i}send(200,"OK",o,m,s["size"]);break;} ;n="<html>Not Found</html>";send(404,"Not Found",n,"text/html",length(n));break;}}}'
    

edit: Added better mime-type detection and 404s. It actually sorta works well
now.

~~~
tyingq
Oof. It wasn't handling binary files. Also fixed directory traversal, and you
can optionally specify a content directory on the cmd line.

    
    
      gawk '@load"filefuncs";@load"readfile";func send(s,e,d,t,b){print"HTTP/1.0 "s" "e|&S;print"Content-Length: "b|&S;print"Content-Type: "t|&S;print d|&S;close(S);}func cf(x){split(x,y,"/");for(z in y){print "FOUND "y[z];if(y[z]==".."){return 0;}}return 1;}func mt(f){c="file -b --mime-type "f;r="";while((c|getline z)>0){r=r z;}close(c);return r;}BEGIN{if(ARGV[1]!=""){if(chdir(ARGV[1])){print "Failed to chdir to "ARGV[1];exit;}ARGC=1;}RS=ORS="\r\n";while(1){S="/inet/tcp/8080/0/0";while((S|&getline l)>0){split(l,f," ");if(f[1]=="GET"){p=substr(f[2],2)}if(p==""){p="index.html"}stat(p,s);if(cf(p)&&s["type"]=="file"){m=mt(p);o=readfile(p);send(200,"OK",o,m,s["size"]);break;}n="<html>Not Found</html>";send(404,"Not Found",n,"text/html"RS,length(n));break;}}}'

~~~
freedomben
You are a hero good sir or madam. Is this redistributable with attribution?

~~~
tyingq
Heh. Sure...licensed under WTFPL.
[http://www.wtfpl.net/about/](http://www.wtfpl.net/about/)

~~~
richard78459
Very clever command but be warned, the link is NSFW.

------
nickcw
There is of course rclone:
[https://rclone.org/commands/rclone_serve_http/](https://rclone.org/commands/rclone_serve_http/)

    
    
        rclone serve http .
    

You can replace . with any of your other cloud storage backends too (s3,
google drive, dropbox, etc), or http with sftp, webdav, ftp, dlna. It works on
Windos/macOS/Linux.

(Rclone author ;-)

~~~
kaendfinger
rclone is our backup solution at work, huge props to you!

------
scanr
Asked for an HTTPS one liner on stackoverflow a while back and got this
answer:

    
    
        ruby -r webrick/https -e '
          WEBrick::HTTPServer.new(
            Port: 8000, DocumentRoot: ".",
            SSLEnable: true, SSLCertName: [%w[CN localhost]]).start'
    

[https://stackoverflow.com/a/37986354/59325](https://stackoverflow.com/a/37986354/59325)

~~~
avip
Caddy is brilliant for this task.

~~~
divbzero
For reference the HTTPS one-liner with Caddy [1] would be:

    
    
        caddy file-server --domain example.com
    

And similarly for HTTPS reverse proxy:

    
    
        caddy reverse-proxy --from example.com --to localhost:9000
    

[1]: [https://caddyserver.com/](https://caddyserver.com/)

This plus hosts file can be a quick way to test secure cookies, secure
headers, etc.

------
rahuldottech
Netcat ones are my favourite, I use them frequently:
[https://gist.github.com/willurd/5720255#gistcomment-2851087](https://gist.github.com/willurd/5720255#gistcomment-2851087)

The same thing, in `batch` for Windows:
[https://github.com/rahuldottech/netcat-http-server-for-
windo...](https://github.com/rahuldottech/netcat-http-server-for-
windows/blob/master/simple/simple.cmd)

------
sondr3
Using `nix` I have an alias called `serve` that runs `nix run nixpkgs.caddy -c
caddy -host 0.0.0.0 -port 8000 browse` which will download Caddy if it is not
in my cache and then run it. It's one of my favorite aliases and I use it way
more frequently than I'd expect.

------
PhilippGille
Like some others in this thread I'll throw in my own shameless plug for
`serve`:
[https://github.com/philippgille/serve](https://github.com/philippgille/serve)

It's similar to the others mentioned here, with the nice extras that there's
optional basic auth, optional HTTPS with automatic creation and use of a self-
signed certificate, there are installers for most popular OS's package
managers (snap, homebrew, scoop, chocolatey), tiny 2-5 MB zero-dependency
binary and some other features.

I've had plans to add automatic Let's Encrypt certs, Onion service creation
and reverse SSH functionality (either using one's own SSH server or one of the
public ones) for a while and hope I'll get to them soon. Does anyone have any
specific preferences for one of those or another feature specifically for the
use case of serving files to another person as quickly as possible?

------
laurent123456
I'm surprised there's no one-liner for Node without dependency since it has a
server by default.

Edit: Didn't know there was an `eval` flag for Node, so that will do the job:

node --eval "var fs = require('fs'), http = require('http');
http.createServer(function (req, res) { fs.readFile(__dirname + req.url,
function (err,data) { if (err) { res.writeHead(404);
res.end(JSON.stringify(err)); return;}res.writeHead(200);res.end(data);
});}).listen(8080);"

~~~
hombre_fatal
Doesn't protect against folder climbing/traversal like `curl :8080/../../etc`.

~~~
djsumdog
Huh .. that'd be a fun post; see how many of these can be susceptible for
climbing out of their web root. The author does list which ones support dir
indexes.

~~~
pvillano
hopefully you're not using a one-liner for your actual deployment. I use it
for no stakes development

~~~
hombre_fatal
Caddy is a one-liner. Plenty of the one-liners are suitable for production.
There are so many solutions that you might as well use one, even in
development, that doesn't have such glaring issues, because you're basically
training your muscle memory to reach for it.

------
inconshreveable
It's missing my personal favorite:

ngrok http file:///Users/alan/share

~~~
capableweb
You might want to include a disclaimer that you're the author, maintainer and
person behind the company that operates ngrok ;)

Just wanted to chime in and say I love ngrok too, not allow allows you to
easily create proxies, it allows you to create proxies that also works on the
public internet (ngrok assigns you a x.ngrok.io address) and with tcp
connections. Great work on it inconshreveable!

------
divbzero
Another good option for static site development is devd [1] [2] which can
automatically open the site in browser with livereload:

    
    
       devd -ol .
    

[1]: [https://github.com/cortesi/devd](https://github.com/cortesi/devd)

[2]:
[https://news.ycombinator.com/item?id=10436111](https://news.ycombinator.com/item?id=10436111)

------
Svenstaro
Shameless plug:
[https://github.com/svenstaro/miniserve/](https://github.com/svenstaro/miniserve/)

------
fyp
Some of these aren't one line but could be (for example the one for node.js
can use npx instead)

------
kragen
I was pleased and surprised that the Python 3 one works with Termux on this
cellphone. I've had trouble with Python socket stuff on here in the past, but
now I suspect that may have been specific to IP multicast.

~~~
slim
The busybox one works too

------
severus_snape
There is woof: [http://www.home.unix-
ag.org/simon/woof.html](http://www.home.unix-ag.org/simon/woof.html)

When -U is specified, it provides an upload form, allowing file uploads.

------
jmull
I've been using this:

    
    
        npx serve
    

(This is a node.js thing.)

~~~
runarberg
Unlike `python3 -m http.server`, `npx serve` doesn’t redirect `/path/to/dir`
to `/path/to/dir/`. This is a problem if you are using relative paths in your
`/path/to/dir/index.html`.

~~~
jmull
For my purposes that hasn’t been a problem.

I guess I would normally just start with ‘path/to/dir/‘ or
‘/path/to/dir/index.html’

------
Minor49er

      php -S localhost:8000

------
acidx
Lwan ([https://lwan.ws](https://lwan.ws)) can also be used like this, although
I wouldn't call it a "one liner" like many of the examples listed there:

    
    
        lwan -r /path/to/files/to/serve

------
gravitas
I still have a copy of bash-httpd laying around, if any of y'all remember
this: [http://frakir.org/~morty/lue/bash-
httpd.html](http://frakir.org/~morty/lue/bash-httpd.html)

------
3xblah
Don't forget socat.

Or tcpserver from djb

.

------
arendtio
Does someone know if there is a way of doing this purely with POSIX tools?

~~~
arminiusreturns

      while TRUE; do { echo -e 'HTTP/1.1 200 OK\r\n'; cat /path/to/thing; } | nc -l 8000; done
    
    

From: [https://krypted.com/](https://krypted.com/)

~~~
ainar-g
Neither echo -e nor nc are POSIX. I don't think there is a strictly POSIX one-
liner.

~~~
arendtio
`echo -e` should be easily replaceable with `printf` but nc remains to be a
problem.

~~~
tyingq
Is inetd "Posix"? It has command line switches to not fork, and to specify the
config file. Maybe it takes a config file of "-" to mean stdin.

~~~
arendtio
I doubt it. At least I can't find it anywere here:

[https://pubs.opengroup.org/onlinepubs/9699919799/utilities/c...](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html)

------
vorticalbox
If you use npx http-server -p 8080

You don't need to fully install globally

------
forgotmypw
How many of these can output a "standard" access log?

Instructions for how to do that would be a helpful addition to this page.

~~~
beizhia
The Crystal version can. I just commented an update for it that will run on
0.32.1, but for logging you can include the HTTP::LogHandler:

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

------
3xblah
rarun2 from radare2

    
    
       rarun2 listen=80 program=/usr/bin/printf arg1="HTTP/1.1 200 OK\r\nContent-type=text/html\r\nConnection: close\r\n\r\n"

------
exegete
Last revised in 2013 FYI.

------
teknopaul
My favourite...

    
    
        apt install nginx
    

Why settle for less.

------
anderspitman
Bit of a stretch but you can also use curl if you proxy it through my
patchbay.pub[0] service:

curl [https://patchbay.pub/abcd1234.html](https://patchbay.pub/abcd1234.html)
\--data-binary @index.html

[0] [https://patchbay.pub](https://patchbay.pub)

------
londons_explore
Lots of people use these one liners for Dev/test environments.

Most of those people aren't aware how insecure they are.

For example, with the python SimpleHTTPServer I can simply request
[http://localhost/../../.ssh/id_rsa](http://localhost/../../.ssh/id_rsa)

All your SSH private keys are now mine. I can steal your browser cookie
database and get into your email/Facebook/Twitter in the same way.

 _Any_ web page can request that, or any software on any machine on your local
network.

~~~
guessmyname
> _For example, with the python SimpleHTTPServer I can simply
> request[http://localhost/../../.ssh/id_rsa](http://localhost/../../.ssh/id_rsa)
> _

Eh! That’s not true. I just tried and both Python 2.7.16 and Python 3.7.6
return a "404 Not Found” when I try to download and existing file that is
located one or more levels up from the directory where the HTTP server was
started. Here is a screenshot showing both results:
[https://i.imgur.com/uizp7zV.png](https://i.imgur.com/uizp7zV.png)

~~~
londons_explore
Maybe behaviour has changed recently? In a past version someone has
demonstrated this attack on me...

~~~
tveita
AFAICT SimpleHTTPServer has been protected against basic traversal attacks for
a very long time.

There have been bugs though, like
[https://bugs.python.org/issue26657](https://bugs.python.org/issue26657)

