In this issue, I would like to:
- collect everything that has so far been said about configuration files in the context of the HTTP Unix daemon.
- add new information that has since arisen due to new features of
library(ssl)
- find an elegant, flexible and convenient way to run HTTPS servers with SWI-Prolog.
The (perceived) need for a configuration file was first raised and supported in #54, with Wouter and me in favour of the idea. It was dismissed again because for that concrete issue, a more trivial fix was applied. Now, a few months later and with the availability of new features for HTTPS servers, this is coming up again in #76.
First, I would like to give a short summary of what a typical HTTPS server needs as its configuration. It is evident that in the very near future, HTTPS servers will become the "normal" web servers, since plain HTTP servers will be marked as insecure by all major browsers. Therefore, it is wise to consider how to best accommodate their configuration.
Currently, a typical SWI-Prolog HTTPS server is started by supplying the following command line options to the Unix daemon:
--https
(mandatory)
--keyfile=File
(almost all servers will use this, even though it could theoretically be omitted)
--certfile=File
(again, used by almost all servers).
A significant portions of these servers will also use:
--redirect
to redirect HTTP to HTTPS.
--cipherlist=Atom
to set ciphers with (currently) acceptable security.
Now, with recent changes to library(ssl)
, the following configurations must also be considered:
- SNI, to supply different certificates depending on the host name of the client request
- multiple certificate to support different ciphers, for example dual-stack RSA/ECDSA servers.
SNI is already supported in the Unix daemon by the hook http:sni_options/2
. Multiple certificates are not yet possible. However, it is clear that this use case will become increasingly relevant in the future, and so it should also be possible to supply multiple certificates somehow.
Currently, a typical invocation of an HTTPS server could like like this:
swipl rules.pl proloxy.pl \
--no-fork --user=www --https --certfile=server.crt \
--keyfile=server.key \
--pidfile=/var/run/https_proloxy.pid --workers=32 --syslog=https_proloxy \
--cipherlist=EECDH+AESGCM:EDH+AESGCM:EECDH+AES256:EDH+AES256:CHACHA20 \
--keep_alive_timeout=2
I have highlighted options that are specific to HTTPS.
It is evident that such an invocation is extremely inconvenient. Moreover, the following problem arises: If you put all this for example in a .service
file for systemd
, then you need to do sudo systemctl daemon-reload
every time you change the configuration parameters. This is also inconvenient, and there is no way around this.
The point has been raised that the Unix daemon is becoming too complex altogether, providing features that go far beyond its initial conception of a "Unix daemon". To be honest, my impression is almost the opposite: In less than 1000 lines of code (including extensive documentation), the daemon manages to expose an impressive amount of very flexible functionality, far more than I initially thought would be possible by so little glue code. If this is now deemed too complex, I wonder what to think about certain other areas of the code that ships with SWI-Prolog. To me, it is a testament to the elegant architecture of the web framework that the Unix daemon takes comparatively little and quite straight-forward code.
We are almost at the point that all of the above is supported. However, multiple certificates remain pending in #76, and this has now provided the impetus to look more closely at the best approach to include this feature too.
In general, we actually need triples of the form:
- certificate
- key
- password.
Using passwords to protect private keys is certainly advisable, but frequently simply not done in practice, also not by Let's Encrypt: In this case and many others, suitable file permissions are used to severely restrict access to private keys and even certificates. Still, we support also encrypted private keys by means of the --pwfile
option (which is to be preferred over --password
, since command line arguments can be easily inspected by other processes).
So, we could support multiple certificates by using for example multiple occurrences of --certfile
etc. However, this gets increasingly complex and unwieldy to use (the implementation remains rather straight-forward, and does not significantly increase the complexity of the Unix daemon).
Now the main point: I still think that a configuration file would be a great idea to solve all this. The main reason for this is the following:
- HTTPS servers will become increasingly common.
- Let's Encrypt provides free certificates that are easy to set up and use.
- SWI-Prolog is increasingly used for web applications.
- That's a great chance to advertise Prolog as a configuration language.
The Prolog community missed the boat when it came to choosing a syntax for RDF and many other web standards, where Prolog syntax could have played a very important role. Why miss the next boat too? Wouldn't it be nice to have Prolog based configuration files as follows, say config.pl
:
https.
certfile('server.crt').
keyfile('server.key').
cipherlist('EECDH+AESGCM:EDH+AESGCM:EECDH+AES256:EDH+AES256:CHACHA20').
user(www).
keep_alive_timeout(2).
workers(32).
And then start the daemon with:
swipl rules.pl proloxy.pl --config=config.pl --no-fork
Further, SNI could be accommodated by providing http:sni_options/2
in the same file.
Moreover, multiple certfile/1
and keyfile/1
options could appear.
Of course, the following syntax would make even more sense:
server([keyfile='server.key',
certfile='server.crt',
https=true,
cipherlist='EECDH+AESGCM:EDH+AESGCM:EECDH+AES256:EDH+AES256:CHACHA20',
keep_alive_timeout=2,
workes=32]).
I think adding this feature to the HTTP Unix daemon would allow a very flexible and convenient configuration of (multiple) HTTPS servers and at the same time advertise Prolog as a nice language for configuration files too.