In my last post about redesigning the Awyr site, I mentioned using rwasa to serve the content.

I found rwasa via an HN thread for one of their other projects, hnwatch. It was possibly a very canny bit of marketing, definitely appealing to the general userbase of HN.

2 Ton’s rwasa is a web server written in 64-bit assembly, and, to avoid simply regurgitating the content of 2 Ton’s page, I thought it might be worth looking at a number of aspects of the software that I appreciate:

  • It’s a self-contained 364KB executable
  • It has no configuration file
  • It consumes about 2KB RAM while idle

Normally to serve content I’d go straight for nginx. It’s small, performant, well known, and well documented. It’s also capable of serving multiple sites from the same configuration file. However, to run nginx you either need to install it or compile it. rwasa scores here; if I want, I can quickly serve arbitrary content as my normal user. How often do you fire up a container or VM just to test some web content? With rwasa, I can just:

rwasa -foreground -bind 8080 -runas jonathon -sandbox /home/jonathon/documents/Awyr/www/_site/ -filestattime 1

and I have a small, local, web server. Yes, jekyll serve does this too, but rwasa is far more responsive. It’s a proper web server, after all. In case you’re wondering, -filestattime sets the minimum amount of time rwasa before it checks whether the file has changed (the default is 120 seconds; there are many other nice little performance enhancements like this).

Notice that all of the information rwasa needs to serve the content is provided via command line arguments. The lack of a configuration file probably seems odd at first. What this means, though, is faster deployment. You can’t worry about misconfiguring something - instead, you point rwasa at your content, and that’s that.

Next up - memory footprint. For serving the above content, rwasa spawns two threads:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
jonathon  5950  0.0  0.0   1556   832 pts/3    S+   21:11   0:00 rwasa -foreground -bind 8080 -runas jonathon -sandbox ...
jonathon  5953  0.0  0.0   3300  1616 pts/3    S+   21:11   0:00 rwasa -foreground -bind 8080 -runas jonathon -sandbox ...

which appear to reserve a total of 2448 bytes of RAM. I have yet to see how rwasa scales up to serving more than a handful of concurrent connections, but 2KB as a baseline? Can’t be bad.

Combined, these properties also make rwasa highly suited to containerisation. It’s a single process, with nearly zero configuration, so we don’t need supervisors or anything fancy. I use alpine as my Docker container base image (5MB!), so a Dockerfile could be as simple as:

FROM alpine:latest

RUN apk -U -f upgrade && \
    apk add wget ca-certificates && \
    wget https://2ton.com.au/standalone_binaries/rwasa -O /usr/local/bin/rwasa && \
    chmod a+x /usr/local/bin/rwasa

VOLUME [ "/var/www", "/var/log/rwasa" ]

EXPOSE 8000

CMD /usr/local/bin/rwasa -foreground -bind 8000 -sandbox /var/www -logpath /var/log/rwasa -errlog /var/log/rwasa/error.log

and if I could get ADD or COPY to work it would be even simpler… However, this approach results in a 10MB Docker image. It’s a little larger than an nginx equivalent of 7MB (which actually surprised me at first until I thought of the extra overhead of wget and ca-certificates) but it’s worth it.

Written by Jonathon, categorised as software, 26 August 2015