9 ms·
Show HN: Nano-web – a low latency one binary webserver designed for serving SPAs
I'd found that whilst there's a lot of good options out there for webservers, I was looking for something that is a single deployable binary for usage with containers or unikernels and solves some of the problems that you get with other setups like nginx.
It uses a single compiled binary, it's going to have extremely low latency on account of caching all files in memory at runtime, and also the fun feature and really useful that's good for SPAs (e.g. Vite) or things like Astro is that you can inject configuration variables into it at runtime and access them from within your frontend code, so you don't have to rebuild any images for different environments as part of your CI.
Whilst I'm sure this problem has been solved time and time again, I could never get a solution to be quite right.
Also, serving things like Astro from S3 gets to be tricky because CloudFront doesn't support index pages in subdirectories so the routing breaks. This fixes this.
Use it or don't, I think it's a cool little project and it's been a while since I worked on and released something :)
- synergy20 3y agohow about civetweb? or lighttpd? both are well known and field tested, light weight and as portable as you need. what are the different features needed for serving SPA comparing to a normal http server?
- EGreg 3y agoI like the idea! Have you seen redbean, which is a universal binary and serves static files from a zipfile? How does this compare to that? Honestly, I think that the current Web can easily use libp2p from IPFS and serve files from any browser peer to peer, with relays on the internet. I think the Web lacks two major things: 1) Address resolution only uses federated DNS and you need extensions to use, say, self-sovereign Web3 domains which can’t be stolen 2) There is NO WAY to load files by their content hash like onion links in Tor. If there was, we’d have a much more secure Web.
- vundercind 3y agoFederation’s a non-starter when most devices people use are battery powered and don’t like to hold connections open when idle. Like, it works, but it won’t work well enough unless most devices are just going through gateways, which largely defeats the point.
- EGreg 3y agoWhat about all those desktop computers on 24/7 in the world?
- vundercind 3y agoAs a share of web clients, those are a rounding error. Phones dominate, with tablets, laptops, and desktops that haven’t been configured to never sleep, following.
- i_have_to_speak 3y agoh2o (https://h2o.examp1e.net/index.html https://h2o.examp1e.net/index.html) is a full-fledged, single-binary, open source web server. Check it out.
- todotask 3y agoThe last time I used it for serving multiple WordPress sites and realise having lengthy YAML can be hard to maintain, and I read that mruby can impacts the performance. Their alternative, picohttpparser that V langauge uses on Techempower benchmark is fast but not useful for real world.
- Brajeshwar 3y agoCan you elaborate "CloudFront doesn't support index pages in subdirectories" and how does it not work? I'm not much into them these days but if I remember correctly in the 4-5 years prior, they just works! In-fact, CloudFront was easier to serve static web assets than serving directly from S3. Or have I misunderstood what you meant?
- VWWHFSfQ 3y agoYeah maybe I'm misunderstanding what this person is referring to, but cloudfront definitely supports index pages in any directory
- antihero 3y agoWhen was this added? I recall several years ago having to do this with edge lambdas. IE the it would happily resolve / to /index.html would be fine, but if you wanted to do /my-dir and have it resolve to /my-dir/index.html it would 404.
- Brajeshwar 3y agoNow that I'm curious because I remember facing no such issues. Cloudfront was my way of testing all of these scenarios to see what happens when the URL endpoint changes, etc. and then move to Akamai to scale up. Did some quick searches and I think there seems to be some kinks indeed and of course the solutions. Here are a few; - https://stackoverflow.com/questions/59634922/how-do-i-serve-index-html-in-subfolders-with-s3-cloudfront https://stackoverflow.com/questions/59634922/how-do-i-serve-... - https://aws.amazon.com/blogs/networking-and-content-delivery/implementing-default-directory-indexes-in-amazon-s3-backed-amazon-cloudfront-origins-using-cloudfront-functions/ https://aws.amazon.com/blogs/networking-and-content-delivery... Update/Edit: I think the setting to use correct S3 Endpoint makes a difference (which was indeed always my default way when I did). https://stackoverflow.com/questions/31017105/how-do-you-set-a-default-root-object-for-subdirectories-for-a-statically-hosted https://stackoverflow.com/questions/31017105/how-do-you-set-...
- qwerty456127 3y agoBy the way, is there a really minimal, really fast, reasonably secure, zero-cofig single-binary web server which would only support HTTP GET and just expose all the static content in a given directory over it?
- supriyo-biswas 3y ago"caddy file-server"[1] and sirv-cli[2] should have you covered, but in case you're looking for something more niche and less powerful, you could look at busybox httpd[3]. I wrote something similar long ago in < 400 lines of Go (with most of it being templates and mimetype information) that just supports GET, HEAD and gzip, in case you're interested[4]. [1] https://caddyserver.com/docs/quick-starts/static-files https://caddyserver.com/docs/quick-starts/static-files [2] https://www.npmjs.com/package/sirv-cli https://www.npmjs.com/package/sirv-cli [3] https://openwrt.org/docs/guide-user/services/webserver/http.httpd https://openwrt.org/docs/guide-user/services/webserver/http.... [4] https://github.com/supriyo-biswas/gohttpd https://github.com/supriyo-biswas/gohttpd
- qwerty456127 3y agoThanks, I'll take a look. I also care about it being reasonably secure so I don't write it myself (I'm far from a pro in avoiding vulnerabilities) and also prefer to decrease the attack surface by giving up all non-essential features. gzip is unnecessary because 99% of the traffic I would serve is going to be pre-compressed (like zip and jpeg files).
- ricardobeat 3y agoCaddy [1] is a single binary. It is not minimal, but the size difference is barely noticeable. serve also comes to mind. If you have node installed, `npx serve .` does exactly that. There are a few go projects that fit your description, none of them very popular, probably because they end up being a 100-line wrapper around http frameworks. [1] https://caddyserver.com/ https://caddyserver.com/
- busfahrer 3y ago
- gwbas1c 3y ago> SPA mode to service 404s as index (200) to support client side routing. Be careful: SPAs can handle 404s client-side. All you need to do is continue to return the 404 result code and include the same exact content that you normally do. Then your SPA recognizes that the route isn't set up and displays the error page.
- antihero 3y agoI could certainly add this as a configuration option! Generally an SPA could do this by simply not having that route and handle accordingly but if it's something people would be interesting it is a quick change. Perhaps make a ticket/PR and I can look into adding it :) That said, thinking about it - the server has no idea whether a client side route is actually correct. You could have https://example.com/potato/tomato https://example.com/potato/tomato which will not exist on the server of course, but will be handled by client side JS on /index.html and could be a correct route within the app, so it is safer to 200 it. SPAs aren't really generally made for SEO also. With something like Astro which is SEO friendly, it could actually return a 200 as expected and a 404 if not.
- kijin 3y agoYep, returning the wrong HTTP status code is going to confuse a lot of search engines, chat app link previews, and other automated consumers of your SPA, even if you subsequently display the correct error page.
- leptons 3y ago>returning the wrong HTTP status code is going to confuse a lot of search engines How is the search engine going to find a page that doesn't exist, isn't in a sitemap, isn't linked to in any nav anchors, in order to index it?
- traverseda 3y agoI will submit it to google to be indexed myself, purely out of spite for the fact that you're willfully and with malice aforethought returning 200 when you know you should be returning a 404.
- jazzjazz 3y agoNeat idea! We did a blog post around just using nginx for something similar. Which is to say NGINX serving SPA. https://medium.com/disney-streaming/api-driven-spa-with-nginx-1546a80b5fef https://medium.com/disney-streaming/api-driven-spa-with-ngin... There is even a sample template repos. https://medium.com/disney-streaming/api-driven-spa-with-nginx-1546a80b5fef https://medium.com/disney-streaming/api-driven-spa-with-ngin... Looking forward to diving into nano-web
- varbhat 3y agoI wrote a similar tool long time ago. https://github.com/varbhat/serv https://github.com/varbhat/serv * Serve the SPA (fallback to index.html): `serv -spa` * Serve the directory and all it's contents: : `serv -dir=/path/to/my/dir`
- Alifatisk 3y agoThe interesting bit is that the project is using a unikernel instead of Docker, I hope this becomes a trend. https://github.com/radiosilence/nano-web?tab=readme-ov-file#nanosops-quick-start https://github.com/radiosilence/nano-web?tab=readme-ov-file#...
- antihero 3y agoIt is set up to use both. Currently working on automating releasing the unikernel OPS package (https://repo.ops.city/v2/packages/radiosilence/show https://repo.ops.city/v2/packages/radiosilence/show) but I had to submit a patch to the OPS project that needs to be released first (or I can make a custom image to use with GHA to build it with a version from master).
- Alifatisk 3y agoHow has your experience with Nanos unikernel been so far since you started? Have you noticed any benefits over Docker?
- antihero 3y agoI mean, I think it's an interesting approach to and kind of nice to be going back to more PaaS primitives. I haven't used it in production, it does seem extremely quick and kind of simple and nice. Either way, I figure the more projects that support it natively, the bigger the ecosystem grows and the more data we'll see based on real world usage. The tooling seems pretty good, though the documentation could do with some improvement (I intend to do more discovery and PR some documentation improvements when I have time).
- Alifatisk 3y ago> Either way, I figure the more projects that support it natively, the bigger the ecosystem grows and the more data we'll see based on real world usage. I like your approach towards this, I'm thinking the same. I appreciate the response you provided, I've been planning on playing around with it for a while when I get the time. Your comment made me even more interested. It went quite quick from seeing your comment on the post about Nanos to your own project integrating it!
- ngrilly 3y agoConsidering the latency between the user web browser and the server, does the “extremely low latency on account of caching all files in memory” really matter? The files should already be cached by the OS and using sendfile lets the OS copy the file directly to the network.
- antihero 3y agoI just figured any savings where savings can be made is a good thing, especially if there are zero downsides, plus it means very low CPU usage as it's literally just pulling from RAM without any CPU usage. It also precaches gzipped and brotli'd versions of sensible files so that it can accept-encoding for a variety of browsers.
- rofldang 3y ago[flagged]
- pvg 3y agoCouldn't the extra memory copies end up being an actual downside? I.e. the sort of thing that inspired sendfile(2) usage in some servers?
- antihero 3y agoI’m not so sure, if you’re serving massive files this is not perhaps the option you want. If your SPA is so big you can’t handle a container that has its app code and assets in RAM perhaps it’s also too large. I see it as a pragmatic trade off between speed and RAM. Even free tier EC2 instance should have enough RAM to handle pretty much any SPA even if the text content is duplicated (compressed) especially seeing as with a unikernel you have no RAM used up by Linux processes.
- pvg 3y agoI think the argument is the same for files that fit in memory. This sort of thing is fairly well-trodden (if unsettled, to mix up the metaphors) ground, for yet another take there's varnish and Poul-Henning Kamp's strident writings about it.
- Sohcahtoa82 3y ago> SPA_MODE when set to 1 404 request will return /public/index.html as a 200. oof, as someone who frequently has to run DAST tools, returning a 200 for something that should be a 404 is the bane of my existence. The tool will try to request sensitive files by trying something as simple as fetching hxxps://example.com/../../../etc/passwd. If you return a "200 OK", it will flag as a security issue, even if the resulting data isn't a passwd file. I don't think you can convince me that returning a 200 OK and some default content for a URL that doesn't exist is ever the correct thing to do. If you want to use 301 or 302 to redirect them to the front page, that's probably fine, but the most correct thing to do is 404.
- __jonas 3y agoBut if it's an SPA, how else would you handle this case? How is the webserver supposed to know in advance which URLs the SPA is able to handle?
- phanimahesh 3y agoHandle a prefix maybe?
- ch_sm 3y agoI typically keep all my SPA routes/route names in a single JSON, and then reference those from the App, instead of repeating the routes everywhere. I can then pass those to the server to let it know what the SPA can handle.
- antihero 3y agoThis is an opinionated approach that is out of scope really I think. Though if it works for you, awesome!
- shkkmo 3y agoI'm not sure what is 'opinionated' about this approach. It seems like a pretty standard and reasonable way of correctly serving an SPA in a way that doesn't violate web standards.
- debarshri 3y agoAre people using nanovms in production? We love to understand the landscape? We are considering it lately. Would love to learn some of the upsides and downsides.
- RiverCrochet 3y agoThere is also Rapid Web Application Server in Assembly: https://2ton.com.au/rwasa/ https://2ton.com.au/rwasa/
- password4321 3y agoAre there bigger latency wins supporting HTTP/2 or HTTP/3? Is HTTP/2 or HTTP/3 even useful behind a service mesh (istio/envoy etc.)?
- antihero 3y agoIf you want TLS, HTTP/3, quic etc I’d suggest that’s the job of whatever is terminating the connection not the core server.
- lipanski 3y agoIf this is the nano version then let me share the pico alternatives with you: * BusyBox httpd [1] * thttpd [2] * Lwan Web Server [3] * gatling [4] I built and maintain a super tiny Docker image (~158KB) for serving static files [5]. My current implementation is based on Busybox httpd and scratch but I also tried out thttpd in the past, which worked well but came with a high memory footprint in some cases. thttpd was used to serve big projects back in the day but it doesn't seem maintained any more. The other two projects were on my list of things to try out. All these projects should compile to binaries <500KB. By comparison nano-web builds a 18.5MB image on my machine. In my experience you can't go below 5-6MB with Alpine (scratch is the way to go if you can compile statically) and you can't go below ~500KB with Golang or Rust, at least not for serving http requests (C or ASM is probably the way to go). Note that I'm not saying that small is always better, it probably depends on your use case and there are reasons for using nginx for a static website as well. [1] https://www.busybox.net/ https://www.busybox.net/ [2] https://www.acme.com/software/thttpd/ https://www.acme.com/software/thttpd/ [3] https://lwan.ws/ https://lwan.ws/ [4] https://www.fefe.de/gatling/ https://www.fefe.de/gatling/ [5] https://github.com/lipanski/docker-static-website https://github.com/lipanski/docker-static-website
- Solvency 3y agoLet's say you have a personal portfolio website. Single index.html file. Written entirely in vanilla HTML/CSS/JS with zero dependencies whatsoever. Project "pages" are fullscreen slideshows of high-rez images (3200x2000) etc. So basically a handcrafted static site. Would buying a virtual server and running any one of these mini servers to run your site make it more performant than throwing it on a regular host like Dreamhost? Like, does the simplicity in the server itself offer ANY speed/performance/latency advantages for a site that is ultimately showcasing big imagery for a folio?
- joekrill 3y agoOP says of nano-web: > you can inject configuration variables into it at runtime and access them from within your frontend code Is there a way to do that with BusyBox httpd or the others?