summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2020-05-01 11:15:40 +0300
committerLars Wirzenius <liw@liw.fi>2020-05-01 11:15:40 +0300
commit1a6b171b184381fcda3eab5bcad0bac1a25e8a61 (patch)
tree30a3622a17d4127b352928de338e4eb8f452f9ef
downloadewww-1a6b171b184381fcda3eab5bcad0bac1a25e8a61.tar.gz
initial commit
-rw-r--r--ewww.md149
1 files changed, 149 insertions, 0 deletions
diff --git a/ewww.md b/ewww.md
new file mode 100644
index 0000000..9214753
--- /dev/null
+++ b/ewww.md
@@ -0,0 +1,149 @@
+# Introduction
+
+This is a web server for static sites. It aims to be simple code,
+simple to configure, simple to keep running, and fast.
+
+## Use cases
+
+* I have files in a directory, and a domain name pointing at the host.
+ I want to serve the files using HTTPS. I want the TLS certificate to
+ come from Let's Encrypt, and get renewed automatically.
+
+* Same, but I have multiple domain names and each should serve from
+ different directories and potentially have their own certificates.
+
+* Same, but some of the domain names are aliases for each other, and
+ web clients should be redirected to the main one.
+
+
+# Requirements
+
+These are main, highlevel requirements. Detailed requirements are
+expressed as _scenarios_ in the acceptance criteria chapter.
+
+* Fast, at least 100 requests per second over localhost, using HTTPS,
+ on my Thinkpad T480 laptop. A self-signed certificate is OK.
+* Fast, time from starting server to having served first HTTPS request
+ should be at most 100 ms.
+* Serves only HTTPS, except what Let's Encrypt needs to be served over
+ plain HTTP.
+
+I don't need flexibility, and I don't want to configure anything
+that's not essential for this. Hardcoded assumptions are A-OK, if my
+life as someone running the program is easier.
+
+At this point, I don't need support for `If-Modified-Since` or `ETag`.
+or generating directory listings. I don't even care about MIME types
+for now. Those will probably become important once I start using this
+software for real, but for now I am trying to keep requirements
+minimal.
+
+
+# Architecture
+
+This is a thin layer on top of the Rust warp crate. It does minimal
+processing for each request, and does not cache anything.
+
+At startup, the server is provided with a directory and it reads all
+configuration files in that directory. Each configuration file looks
+like this:
+
+~~~yaml
+webroot: /srv/http/example.com
+hosts:
+ - example.com
+ - www.example.com
+ports:
+ http: 80, 8080, 8888
+ https: 443, 4433
+tls-cert: /etc/letsencrypt/live/certname/fullchain.pem
+tls-key: /etc/letsencrypt/live/certname/privkey.pem
+~~~
+
+The hosts are aliases; the first host on the list is the main one, the
+others automatically redirect to it.
+
+The server is started as `root`, reads in the TLS private key and
+cert, binds to the ports, then drops privileges to `nobody`. The
+configuration specifies for each port if plain HTTP or HTTPS is
+expected.
+
+The server automatically listens on both port 80 (http) and 443
+(https) so that it can serve the Let's Encrypt files. It only serves
+the `/.well-known/` path prefix in the webroot on port 80. Everything
+else gets redirected to 443. I don't think I need to serve other
+ports, but it's a handy feature to have for testing, so it shall be
+supported at least for testing.
+
+There is no "reload configuration". The server needs to be restarted.
+This is good enough for me, but may not be good enough for more
+serious use on sites with much traffic. Restarting should be fast.
+
+Only the GET and HEAD methods are supported for HTTP: this is a server
+for static content only. Every other method returns an error.
+
+
+# Acceptance criteria
+
+## Smoke test
+
+~~~scenario
+given a self-signed certificate as snakeoil.pem, using key snakeoil.key
+and a running server using config file smoke.yaml
+
+when I request GET http://example.com/
+then I am redirected to https://example.com/
+
+when I request GET http://example.com/.well-known/foo
+then I get status code 404
+
+when I create webroot/foo
+and I request GET http://example.com/.well-known/foo
+then I get status code 200
+and content-type is application/octet-stream
+
+when I request HEAD http://example.com/.well-known/foo
+then I get status code 200
+
+when I request GET https://example.com/
+then I get status code 200
+
+when I request HEAD https://example.com/
+then I get status code 200
+
+when I request GET https://www.example.com/
+then I get redirected to https://example.com/
+~~~
+
+The following config file does not specify port numbers. The test
+scaffolding adds randomly chosen port numbers so that the test can run
+without being root.
+
+~~~{#smoke.yaml .file .yaml .numberLines}
+webroot: webroot
+hosts:
+ - example.com
+ - www.example.com
+tlscert: snakeoil.pem
+tlskey: snakeoil.key
+~~~
+
+## Performance test
+
+~~~scenario
+given a self-signed certificate as snakeoil.pem, using key snakeoil.key
+and a running server using config file smoke.yaml
+and 1000 files in webroot
+when I request files under https://example.com in random order 100000 times
+then I can do at least 100 requests per second
+~~~
+
+# Unhappy scenarios
+
+* not GET or HEAD
+
+
+---
+title: Web server for static sites
+bindings: webserver.yaml
+...