[HN Gopher] Big list of HTTP static server one-liners
       ___________________________________________________________________
        
       Big list of HTTP static server one-liners
        
       Author : raytracer
       Score  : 255 points
       Date   : 2021-05-13 06:11 UTC (16 hours ago)
        
 (HTM) web link (gist.github.com)
 (TXT) w3m dump (gist.github.com)
        
       | TheRealPomax wrote:
       | now please also do one for https, no one wants to deal with the
       | cert hassle when they just need a temporary https server for
       | working with some local content.
        
       | tngranados wrote:
       | I wrote a zsh function[1] that runs an http server using ruby,
       | php or python (2 and 3) depending on what's available in the
       | system.
       | 
       | [1]
       | https://github.com/tngranados/dotfiles/blob/0ebdc12f2454061a...
        
       | gunnarmorling wrote:
       | It will be a one-liner in Java soon too, once JEP 408 ("simple
       | web server") has landed. In the meantime, this will do:
       | jbang webster@gunnarmorling
       | 
       | This launches Vert.x, publishing the current directory, via the
       | JBang launcher. Source code is here if you want to see what you
       | actually run: https://github.com/gunnarmorling/jbang-
       | catalog/blob/master/w...
        
       | bawolff wrote:
       | Weird to call these one liners, they're just invocation commands.
       | 
       | By that logic, apache is a one-liner.
        
         | niklasrde wrote:
         | apache requires a config file. I guess you could put any
         | relevant config into a single line and pipe that through
         | somehow, but it would be a lot more than a single command to
         | define a directory and a port to serve.
        
           | bawolff wrote:
           | PHP was on the list. It also takes a config file (less
           | relavent though to this use)
        
         | forgotpwd16 wrote:
         | Apache requires configuration. The point of those is that
         | they're opening ad hoc an HTTP server without requiring any
         | configuration.
         | 
         | Edit: Someone has posted an Apache example:
         | https://gist.github.com/willurd/5720255#gistcomment-3050599
        
         | oss2020 wrote:
         | With that logic there are no one-liners. Even binary code is
         | just an abstraction interpreted by microcode.
         | 
         | The point is that there is a working http server already
         | installed on your machine. And you just need to run this one
         | simple, memorable command to use it.
         | 
         | Very useful if you just want to quickly copy some files from A
         | to B in your LAN or WAN (wouldn't use it over Internet because
         | not encrypted).
        
       | xonix wrote:
       | My take on this [1]. Explanation article [2]. In fact the use-
       | case I addressed was slightly different (explained in the
       | article) and later I found the similar tool [3] which probably is
       | more powerful.
       | 
       | [1] https://github.com/xonixx/serv
       | 
       | [2] https://medium.com/cmlteam/develop-a-utility-on-graalvm-
       | cc16...
       | 
       | [3] https://github.com/schollz/croc
        
       | mbell wrote:
       | What I use for https:                   $ ruby -r webrick/https
       | -e "WEBrick::HTTPServer.new(Port: 9001, DocumentRoot: '.',
       | SSLEnable: true, SSLCertName: [%w[CN localhost]]).start"
        
       | FriedrichN wrote:
       | I often use netcat to test stuff locally.                 while
       | true; do cat index.html | nc -l 9999 -q 1; echo -e "\n---"; done
        
         | rijoja wrote:
         | nice one
        
           | mousepilot wrote:
           | netcat is just handy in general!
        
       | zachrose wrote:
       | Are that any that can serve the same index.html file to any
       | request with an Accept: text/html header?
        
       | lipanski wrote:
       | My favourite is thttpd [1] which is super tiny, battle-tested and
       | actually meant for the job (and only this job). It's available as
       | a package on most Linux distros.
       | 
       | Serving a static folder `/static` on port `3000` as user `static-
       | user` and with cache headers set to 60 seconds would go like
       | this:                 thttpd -D -h 0.0.0.0 -p 3000 -d /static -u
       | static-user -l - -M 60
       | 
       | Even if you've got Python lying around on every Ubuntu server, I
       | still don't get why you wouldn't use something leaner to serve
       | your static files, as long as it's easy to install/configure.
       | Same goes for most of the runtimes in that list.
       | 
       | [1] https://www.acme.com/software/thttpd/
        
         | throw0101a wrote:
         | > _My favourite is thttpd [1] which is super tiny, battle-
         | tested and actually meant for the job (and only this job). It
         | 's available as a package on most Linux distros._
         | 
         | Surprising not on Debian or Ubuntu AFAICT:
         | 
         | * https://packages.debian.org/search?keywords=thttpd
         | 
         | Though it does seem to have this from the same author:
         | 
         | * https://packages.debian.org/search?keywords=mini-httpd
         | 
         | * http://www.acme.com/software/mini_httpd/
         | 
         | There are times that I want to run Let's Encrypt that's not a
         | full-time web server (SMTP, IMAP, etc), and it would be handy
         | to spin up something _ad hoc_ on tcp /80 to do the verification
         | step and then stop it right after.
        
         | makeworld wrote:
         | https://github.com/blueness/sthttpd
        
         | Evidlo wrote:
         | Because the point is that I want a webserver up _now_. If I was
         | running something long-term I would just use Caddy anyway.
        
           | Macha wrote:
           | Yeah, I want a HTTP server up because I need an actual server
           | to test my web app or because I want to send a large file to
           | someone on my local network and don't want to guide them
           | through setting up smb/rsync/whatever and just want to give
           | them a URL.
           | 
           | I don't particularly care about what's least likely to fall
           | over under sustained load or is suitable security wise to
           | expose to the internet, because it's not going to have to
           | deal with either of these things. Being "already installed"
           | on the other hand is a big selling point.
        
         | jart wrote:
         | thttpd has one cool cat badge icon but have you seen its
         | critical path http parsing code?                       /* Read
         | the MIME headers. */             while ( ( buf = bufgets( hc )
         | ) != (char*) 0 )                 {                 if ( buf[0]
         | == '\0' )                     break;                 if (
         | strncasecmp( buf, "Referer:", 8 ) == 0 )                     {
         | cp = &buf[8];                     cp += strspn( cp, " \t" );
         | hc->referrer = cp;                     }                 else
         | if ( strncasecmp( buf, "Referrer:", 9 ) == 0 )
         | {                     cp = &buf[9];                     cp +=
         | strspn( cp, " \t" );                     hc->referrer = cp;
         | }                 else if ( strncasecmp( buf, "User-Agent:", 11
         | ) == 0 )                     {                     cp =
         | &buf[11];                     cp += strspn( cp, " \t" );
         | hc->useragent = cp;                     }                 else
         | if ( strncasecmp( buf, "Host:", 5 ) == 0 )
         | {                     cp = &buf[5];                     cp +=
         | strspn( cp, " \t" );                     hc->hdrhost = cp;
         | 
         | Use perfect hash tables for known http headers, because they're
         | perfect.
        
       | punnerud wrote:
       | How many of these support the partial file loading? I know that
       | Python don't (I have been working on support for it).
       | 
       | This would make SQLite example supported:
       | https://news.ycombinator.com/item?id=27016630
        
         | wheybags wrote:
         | The node one does, and there is a fork of the python one that
         | does: https://github.com/danvk/RangeHTTPServer/
         | 
         | I know this because I have also been working on something using
         | that magic sqlite-in-browser project :D
        
           | punnerud wrote:
           | Thank you! I like the monkey patch to enable binary range
           | support: https://github.com/danvk/RangeHTTPServer/blob/master
           | /RangeHT...
        
       | eatonphil wrote:
       | Similarly here's a nice list of reverse shell one liners
       | https://github.com/swisskyrepo/PayloadsAllTheThings/blob/mas...
        
       | chrismorgan wrote:
       | (2013). There are many comments since then providing more
       | alternatives, many of which didn't exist back in 2013, but the
       | article itself hasn't been touched since 2013-07-07.
        
         | aoleinik wrote:
         | While the author hasn't updated the main link, it's clear he
         | checked up on the article until atleast 2017: one of the
         | comments originally was a base64 encoded string, and the author
         | edited and deleted it so that no one would run random base64
         | strings off the internet.
        
       | satyanash wrote:
       | The ruby one with the -run option is a bit nonintuitive in how it
       | works.                 $ ruby -run -ehttpd . -p8000
       | 
       | The -r option requires un.rb[1] which is a file full of
       | convenience functions, such as httpd in this example. Classic
       | Ruby.
       | 
       | Given that go has popularized long args with a single hyphen
       | (-name etc), it is easy to mistake -run as an option by itself.
       | 
       | [1] https://github.com/ruby/ruby/blob/master/lib/un.rb#L323
        
         | BiteCode_dev wrote:
         | > go has popularized long args, with a single hyphen (-name
         | etc)
         | 
         | Why did they do that?
         | 
         | It took us 20 years to standardize on - for short and -- for
         | long, with occasional finger rage on tar or find, and now this?
         | 
         | What were they thinking?
        
           | kazinator wrote:
           | The XWindow system used -long -opts long before that.
        
             | BiteCode_dev wrote:
             | The XWindow system is a collection of the worse api in the
             | world so it's no surprise.
             | 
             | But the vast majority of modern command line tools agree on
             | --long.
        
             | gimboland wrote:
             | ...aaaand it's more than 20 years old, so yeah, that kinda
             | agrees with the point that it took us a long time to stop
             | doing that because it's confusing.
        
               | [deleted]
        
           | masklinn wrote:
           | > What were they thinking?
           | 
           | They were starting back from the 70s.
           | 
           | Also one more check for go being alt.history.java, this style
           | is also the standard for Java tooling.
           | 
           | And Apple, I think.
        
             | nonameiguess wrote:
             | Also the standard for PowerShell.
        
           | xaduha wrote:
           | You can use -- or - as far as Go proper goes, doesn't matter
           | in most cases. I think popular args libraries do that too,
           | but there's a million of them, so some probably don't.
        
           | unscaled wrote:
           | My hunch is that Rob Pike, Ken Thompson, Russ Cox and the
           | other Bell Labs alumni behind Go disliked GNU getopt-style
           | flags, like they dislike a lot of other GNU and BSD decisions
           | that "contaminate" the original philosophy behind Unix.
           | 
           | This overall attitude has led to many design decisions in Go,
           | which define the language for better or worse. Statically-
           | linked executables, for instance, contributed more than
           | anything else to Go's popularity as a CLI tool language. Of
           | course, the Bell Labs crowd was already highly skeptical of
           | dynamic linking. See Rob Pike's opinion here:
           | http://harmful.cat-v.org/software/dynamic-linking/
           | 
           | I say it's a hunch, but I think Russ Cox's following comments
           | pretty much demonstrate this attitude against GNUisms and
           | BSDisms: https://github.com/golang/go/issues/2096#issuecommen
           | t-660578... https://news.ycombinator.com/item?id=9207316
           | 
           | On the other hand, Russ clearly goes on to say they designed
           | the flags not based on Plan 9 (which only had short single-
           | letter flags), but on Google's gflags library: https://github
           | .com/golang/go/issues/2096#issuecomment-660578...
           | 
           | In short, it's probably both:
           | 
           | - Innate distrust of all things BSD/GNU meant that the
           | original Go team didn't feel they have to honor the
           | established tradition. Just like dynamic linking, they
           | believed that if there is something that GNU does wrong, they
           | don't need to follow it just for the sake of keeping
           | compatibility.
           | 
           | - Positive experience using gflags convinced the team that
           | the gflags approach (single-dash long flags) is the best one.
           | 
           | I personally think they were wrong here. As Russ Cox himself
           | clearly stated in response to all requests for fixing go
           | flags: there are many libraries out there who implement GNU-
           | style flags. What happened in practice is that most Go
           | developers voted with their feet and chose a third-party flag
           | module (even Google's own Kubernetes is using spf13/cobra).
           | In the end, the Go flags package just ended up causing more
           | confusion and didn't solve any of the problems (perceived or
           | real) with GNU flags.
        
             | BiteCode_dev wrote:
             | Damn, a constructive and sourced answer. I wish I could
             | upvote that twice.
        
         | amarshall wrote:
         | Permalink:
         | https://github.com/ruby/ruby/blob/v3_0_1/lib/un.rb#L323
         | 
         | (Tip: can hit "y" on GitHub to change the URL to a revision-
         | based permalink)
        
         | Sohcahtoa82 wrote:
         | I've always disliked not having a space between a -parameter
         | and it's option. "-r un" is so much more readable and explicit
         | than "-run".
         | 
         | Why do people not include that space? Certainly it's not to
         | save the time of not hitting the spacebar, right?
        
       | toxik wrote:
       | Many of these are so complex you could just say nginx -c
       | <<<(config goes here) is a one liner
        
       | conradludgate wrote:
       | I'm a big fan of miniserve[0]. It can do files, directories
       | (including on the fly tgz or zip downloading), authentication and
       | upload
       | 
       | [0]: https://github.com/svenstaro/miniserve
        
       | henearkr wrote:
       | Anybody has a one-liner allowing CORS (e.g. through options)?
       | 
       | That would be utterly convenient to quickly test multithread WASM
       | applications...
       | 
       | I'm currently using ExpressJS for that, but it feels overkill..
        
         | [deleted]
        
         | mmazzarolo wrote:
         | You can try serverino (https://github.com/mmazzarolo/serverino)
         | with the --cors option.
        
         | capableweb wrote:
         | I think these are meant for development setups, which you
         | normally run in a localhost context, meaning you most likely
         | won't have to deal with CORS.
         | 
         | But, if you still need it, the http-server program has a --cors
         | flag to enable wildcard CORS.
        
           | henearkr wrote:
           | Thanks!! I'll try it again, the last time I did I thought it
           | was not allowing the right setting, but yeah a wildcard CORS
           | should be enough of course.
        
             | pixl97 wrote:
             | >but yeah a wildcard CORS should be enough of course.
             | 
             | You mean that isn't the production default?
             | 
             | /s
        
       | majkinetor wrote:
       | Powershell: Start-PodeStaticServer
       | 
       | https://github.com/Badgerati/Pode
        
       | MuffinFlavored wrote:
       | https://gist.github.com/willurd/5720255#http-server-nodejs
       | 
       | You could do `npx http-server` I believe.
        
       | divbzero wrote:
       | There is also devd: [1]                 devd .
       | 
       | [1]: https://github.com/cortesi/devd
        
       | SbEpUBz2 wrote:
       | I've started using darkhttpd[1] recently, it's simple and
       | compiles quickly to one binary, it supports directory listings
       | and supports range requests.
       | 
       | https://github.com/emikulic/darkhttpd
        
       | config_yml wrote:
       | I use busybox httpd to run my blog via cloud run. It's a fun
       | setup, using a multistage dockerfile to build the static pages
       | and then create a super small busybox image which just serves
       | those pages.
        
       | xaduha wrote:
       | Only one mention of socat, nothing does ad-hoc nonsense that you
       | probably would never use again like socat.
       | 
       | > socat TCP4-LISTEN:50000,fork EXEC:/usr/bin/ifconfig
       | 
       | > curl --http0.9 localhost:50000
       | 
       | Hmmm, does http v0.9 count?
        
         | capableweb wrote:
         | Probably because the example you made doesn't look like a
         | static file server, it seems to execute a specific unix command
         | on incoming request only. The rest of the examples from the
         | gist is proper static file servers.
         | 
         | I'd be interested in seeing if you can come up with a socat
         | one-liner that works like a static file server. Would come in
         | handy for many things, but I can't seem to figure out how to
         | make it work.
        
           | xaduha wrote:
           | Many examples here in the comments and in the gist itself
           | don't follow it to the letter either, it's easy enough to
           | serve one file.
           | 
           | This one might work https://github.com/avleen/bashttpd
           | 
           | > socat TCP4-LISTEN:8080 EXEC:/usr/local/bin/bashttpd
        
             | capableweb wrote:
             | > Many examples here in the comments and in the gist itself
             | don't follow it to the letter either, it's easy enough to
             | serve one file.
             | 
             | Curious about what you said, I looked through the gist
             | again and every one of the examples in the gist itself does
             | indeed serve all the files under a path (a "static file
             | server"). Which one are you implying does not?
        
       | 1vuio0pswjnm7 wrote:
       | Missing:                  nghttpd -v -d /home/user/www -a
       | 127.0.0.1 443 /home/user/demoCA/serverkey.pem
       | /home/user/demoCA/servercert.pem
        
       | fouronnes3 wrote:
       | What's a good one that serves gzip assets if they exist? I'm
       | looking for a way to serve a webpack prod build.
        
         | Siira wrote:
         | Caddy has it, but I doubt you could invoke the option in a one-
         | liner. Still very easy to setup though.
        
         | jart wrote:
         | try redbean https://justine.lol/redbean/ see hn thread
         | https://news.ycombinator.com/item?id=26271117 e.g.
         | sudo redbean.com -dp80 -L/var/log/redbean.log
         | -P/var/run/redbean.pid -U65534 -G65534 -vvvvmbag
        
         | capableweb wrote:
         | These are development servers, they are not meant for
         | production builds (many don't handle concurrent requests,
         | memory/performance is probably too poor as well).
         | 
         | Caddy works well and is easy to use and could replace most of
         | these examples, not only for development but for production
         | usage too.
         | 
         | Otherwise go for nginx/apache. Learn the config syntax once,
         | get lifetime worth of value :)
        
       | habitue wrote:
       | Wow, didn't realize this was started in 2013
        
       | yuvadam wrote:
       | I'm always surprised that nginx doesn't have a nice way to run as
       | a single-liner command.
        
         | [deleted]
        
         | vbsteven wrote:
         | I think it makes sense since it is completely driven by its
         | config and adheres to the Unix philosophy of doing one thing
         | well and not clutter the binary with additional stuff for
         | fringe use cases. It would make the now surprisingly simple cli
         | arguments more complex.
         | 
         | It should be trivial to write a shell script or alias that
         | templates `root $(pwd);` and invokes `nginx -c /tmp/nginx.conf`
        
           | klibertp wrote:
           | > adheres to the Unix philosophy of doing one thing well and
           | not clutter the binary with additional stuff for fringe use
           | cases
           | 
           | Nginx? Really? "One" thing? Try running `./configure --help`
           | in the Nginx source dir...
        
         | viraptor wrote:
         | What would be the use case? These are useful for experimenting
         | and doing something ad-hoc, but once you deploy to a serious
         | environment not being a one-liner is irrelevant. On the other
         | hand supporting that special case has its own costs.
        
       | [deleted]
        
       | kevincox wrote:
       | Note that a lot of these bind to 0.0.0.0 by default. This has
       | caused me surprises in the past as I was failing to connect to a
       | host that is available over IPv6. Sometimes it was even
       | intermittent as I would sometime resolve to the IPv4 and
       | sometimes get the IPv6 and fail.
       | 
       | For python3 this is easily remedied.                   python -m
       | http.server -b ::
       | 
       | On most OS configurations this will listen on both IPv4 and IPv6.
       | 
       | Or for when you only need local access:                   python
       | -m http.server -b localhost
        
         | darkwater wrote:
         | For the use cases of most of that software list, they should
         | actually listen to localhost (127.0.0.1 and ::1) only, because
         | security. Listening on every IPv6 interface, which might be
         | exposed directly on the IPv6 internet, is even a worse idea.
        
           | kevincox wrote:
           | In general I agree. Localhost is a safer default, it doesn't
           | cost much to type a bind address when you need jt. However
           | 0.0.0.0 is a worse default than ::
        
       | tannhaeuser wrote:
       | $ sthttpd/sbin/thttpd -i thttpd.pid -l `pwd`/access.log -p 8080
       | -c '/bin/*'
        
       | jfjfhvhfhfhfhfh wrote:
       | $ emrun --port 8000 . # Handles WASM; most others don't.[1]
       | 
       | [1] Emscripten's emsdk includes emrun, which actually serves WASM
       | files with the correct MIME type out-of-the-box, unlike the
       | python2 and python3 servers and most others.
        
         | henearkr wrote:
         | Does emrun allow CORS, required for SharedArrayBuffers?
        
           | capableweb wrote:
           | CORS is up to the server you're calling, not up to the server
           | hosting the JS code. Any server that supports custom HTTP
           | headers, support CORS. No, SharedArrayBuffers don't require
           | "CORS" (which you probably mean if they work in CORS context
           | rather than "require"). What they do require is a Secure
           | Context (https, localhost or similar)
           | https://developer.mozilla.org/en-
           | US/docs/Web/Security/Secure...
           | 
           | I wonder how come CORS is such a misunderstood concept
           | globally. It's a really simple concept in general, and
           | understanding it will make a lot of your work as a
           | frontend/full stack developer easier. Take a day and fully
           | understand it, it'll pay off.
        
       | mradmin wrote:
       | Some of these are multi-liners that can be converted to one-
       | liners. For example I believe "npx" can be used for all the node
       | examples for example "npx http-server -p 6007 ./root"
       | 
       | [edit] ahh i see this is called out in the gist comments
        
       | StapleHorse wrote:
       | Is there a way of doing that in a Windows without installing
       | anything?
        
         | Zecc wrote:
         | .Net via Powershell:
         | 
         | https://gist.github.com/willurd/5720255#gistcomment-2390248
        
         | TheRealPomax wrote:
         | Why would you not have things installed already? You're almost
         | guaranteed to have Node or Python or bash (via the linux
         | subsystem for windows) already available if you do any kind of
         | web dev work?
        
         | jfgiogktkt wrote:
         | Windows ships with a web server (IIS), but you need to activate
         | it in Features. Not sure if that counts as installing or not to
         | you.
         | 
         | https://www.betterhostreview.com/turn-on-iis-windows-10.html
        
       | laurent123456 wrote:
       | (2013)
        
       | abhishekjha wrote:
       | Isn't python's server blocking? If you make two requests
       | simultaneously, one of them will have to wait.
        
         | masklinn wrote:
         | That's correct. Well blocking is not much of an issue in and of
         | itself but it's blocking and single process and single
         | threaded, so it can only serve one request at a time.
         | 
         | It's not usually an issue for small stuff, but it does mean you
         | can't really use this snippet to serve big files for a lan,
         | which is a bit of a surprise the first time you hit that
         | limitation.
        
         | oss2020 wrote:
         | Python 2 was blocking. Python 3 is non-blocking.
        
       | antihero wrote:
       | If you have npm installed then simply doing                   npx
       | serve
       | 
       | is very easy
        
         | TheRealPomax wrote:
         | it's also very insecure, because you have no guarantee that the
         | version of `serve` that gets pulled down has been vetted and is
         | verified exploit-free, unless you tell npx exactly which
         | version should be used, at which point things start become less
         | easy and more "having to remember which versions are safe".
        
           | closeparen wrote:
           | Which software do you run that is vetted and verified
           | exploit-free?
        
         | kevincox wrote:
         | Of course this requires internet access. It is also arguably
         | less secure as it is downloading code from the internet and
         | means that you are trusting the latest code from a handful of
         | people https://www.npmjs.com/package/serve
        
           | eyelidlessness wrote:
           | Worth noting, because it's non-obvious but does address some
           | of the concern around npx, that it resolves to any locally
           | available version using standard Node module resolution, then
           | falls back to downloading from NPM. And in the next version
           | it will warn before downloading.
        
           | jmull wrote:
           | > ...arguably less secure as it is downloading code from the
           | internet...
           | 
           | Don't essentially all the options involve code downloaded
           | from the internet? And you have to trust the source that it
           | isn't malware or too buggy or insecure?
           | 
           | Are you making a case that the maintainers of this package
           | aren't trustworthy? Or maybe the operators of npmjs.com?
           | 
           | I'm just not understanding the claim this is less secure than
           | various other options.
        
             | filleduchaos wrote:
             | It feels somewhat disingenuous to rephrase _" is
             | downloading"_ as _" downloaded"_ as though they mean the
             | same thing.
        
               | jmull wrote:
               | How does _when you_ happen to download something affect
               | how secure it is?
               | 
               | By default -- presumably the most common case by far --
               | "npx serve" will download the most recent stable build.
               | But why should that be less secure than some previous
               | version?
               | 
               | New vulnerabilities could have been introduced. But, of
               | course, old ones could have been resolved.
               | 
               | If you generally trust the source to be working in good
               | faith and have an adequate level of competence, I would
               | expect a given package/tool tends to become more secure
               | over time, so taking the latest is a generally good
               | strategy (not perfect of course) compared to running a
               | version that is out-of-date to an arbitrary degree.
               | 
               | Of course, if you don't generally trust the source to be
               | working in good faith or have an adequate level of
               | competence, then you should not use the package/tool no
               | matter when it was built or when you downloaded it.
               | 
               | I'm not seeing the logic here.
        
       ___________________________________________________________________
       (page generated 2021-05-13 23:03 UTC)