Notes about lwsws
=================
-Libwebsockets Web Server
-------------------------
+@section lwsws Libwebsockets Web Server
lwsws is an implementation of a very lightweight, ws-capable generic web
server, which uses libwebsockets to implement everything underneath.
-Build
------
+If you are basically implementing a standalone server with lws, you can avoid
+reinventing the wheel and use a debugged server including lws.
+
+
+@section lwswsb Build
Just enable -DLWS_WITH_LWSWS=1 at cmake-time.
It enables libuv and plugin support automatically.
+NOTICE on Ubuntu, the default libuv package is called "libuv-0.10". This is ancient.
+
+You should replace this with libuv1 and libuv1-dev before proceeding.
+
+@section lwswsc Lwsws Configuration
-Configuration
--------------
+lwsws uses JSON config files, they're pure JSON except:
-lwsws uses JSON config files, they're pure JSON but # may be used to turn the rest of the line into a comment.
+ - '#' may be used to turn the rest of the line into a comment.
+
+ - There's also a single substitution, if a string contains "_lws_ddir_", then that is
+replaced with the LWS install data directory path, eg, "/usr/share" or whatever was
+set when LWS was built + installed. That lets you refer to installed paths without
+having to change the config if your install path was different.
There is a single file intended for global settings
"gid": "48", # apache user
"count-threads": "1",
"server-string": "myserver v1", # returned in http headers
+ "ws-pingpong-secs": "200", # confirm idle established ws connections this often
"init-ssl": "yes"
}
}
# cp ./lwsws/etc-lwsws-conf.d-localhost-EXAMPLE /etc/lwsws/conf.d/test-server
# sudo lwsws
```
-Vhosts
-------
+
+@section lwsogo Other Global Options
+
+ - `reject-service-keywords` allows you to return an HTTP error code and message of your choice
+if a keyword is found in the user agent
+
+```
+ "reject-service-keywords": [{
+ "scumbot": "404 Not Found"
+ }]
+```
+
+ - `timeout-secs` lets you set the global timeout for various network-related
+ operations in lws, in seconds. It defaults to 5.
+
+@section lwswsv Lwsws Vhosts
One server can run many vhosts, where SSL is in use SNI is used to match
the connection to a vhost and its vhost-specific SSL keys during SSL
That sets up three vhosts all called "localhost" on ports 443 and 7681 with SSL, and port 80 without SSL but with a forced redirect to https://localhost
-Vhost name and port
--------------------
+@section lwswsvn Lwsws Vhost name and port sharing
The vhost name field is used to match on incoming SNI or Host: header, so it
must always be the host name used to reach the vhost externally.
the client has been parsed.
-Protocols
----------
+@section lwswspr Lwsws Protocols
Vhosts by default have available the union of any initial protocols from context creation time, and
any protocols exposed by plugins.
```
-Other vhost options
--------------------
+@section lwswsovo Lwsws Other vhost options
- If the three options `host-ssl-cert`, `host-ssl-ca` and `host-ssl-key` are given, then the vhost supports SSL.
- "`ssl-option-clear'": "<decimal>" Clears the SSL option flag value for the vhost.
It may be used multiple times and OR's the flags together.
-Mounts
-------
+ - "`headers':: [{ "header1": "h1value", "header2": "h2value" }]
+
+allows you to set arbitrary headers on every file served by the vhost
+
+recommended vhost headers for good client security are
+
+```
+ "headers": [{
+ "Content-Security-Policy": "script-src 'self'",
+ "X-Content-Type-Options": "nosniff",
+ "X-XSS-Protection": "1; mode=block",
+ "X-Frame-Options": "SAMEORIGIN"
+ }]
+
+```
+
+@section lwswsm Lwsws Mounts
Where mounts are given in the vhost definition, then directory contents may
be auto-served if it matches the mountpoint.
-Other mount options
--------------------
+@section lwswsomo Lwsws Other mount options
+
+1) Some protocols may want "per-mount options" in name:value format. You can
+provide them using "pmo"
+
+ {
+ "mountpoint": "/stuff",
+ "origin": "callback://myprotocol",
+ "pmo": [{
+ "myname": "myvalue"
+ }]
+ }
-1) When using a cgi:// protcol origin at a mountpoint, you may also give cgi environment variables specific to the mountpoint like this
+2) When using a cgi:// protcol origin at a mountpoint, you may also give cgi environment variables specific to the mountpoint like this
```
{
"mountpoint": "/git",
```
This allows you to customize one cgi depending on the mountpoint (and / or vhost).
-2) It's also possible to set the cgi timeout (in secs) per cgi:// mount, like this
+3) It's also possible to set the cgi timeout (in secs) per cgi:// mount, like this
```
"cgi-timeout": "30"
```
-3) `callback://` protocol may be used when defining a mount to associate a
+4) `callback://` protocol may be used when defining a mount to associate a
named protocol callback with the URL namespace area. For example
```
{
See the related notes in README.coding.md
-4) Cache policy of the files in the mount can also be set. If no
+5) Cache policy of the files in the mount can also be set. If no
options are given, the content is marked uncacheable.
```
{
}
```
-4) You can also define a list of additional mimetypes per-mount
+6) You can also define a list of additional mimetypes per-mount
```
"extra-mimetypes": {
".zip": "application/zip",
}
```
-Plugins
--------
+Normally a file suffix MUST match one of the canned mimetypes or one of the extra
+mimetypes, or the file is not served. This adds a little bit of security because
+even if there is a bug somewhere and the mount dirs are circumvented, lws will not
+serve, eg, /etc/passwd.
+
+If you provide an extra mimetype entry
+
+ "*": ""
+
+Then any file is served, if the mimetype was not known then it is served without a
+Content-Type: header.
+
+7) A mount can be protected by HTTP Basic Auth. This only makes sense when using
+https, since otherwise the password can be sniffed.
+
+You can add a `basic-auth` entry on a mount like this
+
+```
+{
+ "mountpoint": "/basic-auth",
+ "origin": "file://_lws_ddir_/libwebsockets-test-server/private",
+ "basic-auth": "/var/www/balogins-private"
+}
+```
+
+Before serving anything, lws will signal to the browser that a username / password
+combination is required, and it will pop up a dialog. When the user has filled it
+in, lwsws checks the user:password string against the text file named in the `basic-auth`
+entry.
+
+The file should contain user:pass one per line
+
+```
+testuser:testpass
+myuser:hispass
+```
+
+The file should be readable by lwsws, and for a little bit of extra security not
+have a file suffix, so lws would reject to serve it even if it could find it on
+a mount.
+
+
+@section lwswspl Lwsws Plugins
Protcols and extensions may also be provided from "plugins", these are
lightweight dynamic libraries. They are scanned for at init time, and
dumb increment, mirror and status protocol plugins are provided as examples.
-Additional plugin search paths
-------------------------------
+@section lwswsplaplp Additional plugin search paths
Packages that have their own lws plugins can install them in their own
preferred dir and ask lwsws to scan there by using a config fragment
}
```
-lws-server-status plugin
-------------------------
+@section lwswsssp lws-server-status plugin
One provided protocol can be used to monitor the server status.
"update-ms": "5000"
}
```
-"update-ms" is used to control how often updated JSON is sent on a ws link.
+`"update-ms"` is used to control how often updated JSON is sent on a ws link.
And map the provided HTML into the vhost in the mounts section
```
}
```
You might choose to put it on its own vhost which has "interface": "lo", so it's not
-externally visible.
+externally visible, or use the Basic Auth support to require authentication to
+access it.
+
+`"hide-vhosts": "{0 | 1}"` lets you control if information about your vhosts is included.
+Since this includes mounts, you might not want to leak that information, mount names,
+etc.
+
+`"filespath":"{path}"` lets you give a server filepath which is read and sent to the browser
+on each refresh. For example, you can provide server temperature information on most
+Linux systems by giving an appropriate path down /sys.
+
+This may be given multiple times.
-Integration with Systemd
-------------------------
+@section lwswsreload Lwsws Configuration Reload
+
+You may send lwsws a `HUP` signal, by, eg
+
+```
+$ sudo killall -HUP lwsws
+```
+
+This causes lwsws to "deprecate" the existing lwsws process, and remove and close all of
+its listen sockets, but otherwise allowing it to continue to run, until all
+of its open connections close.
+
+When a deprecated lwsws process has no open connections left, it is destroyed
+automatically.
+
+After sending the SIGHUP to the main lwsws process, a new lwsws process, which can
+pick up the newly-available listen sockets, and use the current configuration
+files, is automatically started.
+
+The new configuration may differ from the original one in arbitrary ways, the new
+context is created from scratch each time without reference to the original one.
+
+Notes
+
+1) Protocols that provide a "shared world" like mirror will have as many "worlds"
+as there are lwsws processes still active. People connected to a deprecated lwsws
+process remain connected to the existing peers.
+
+But any new connections will apply to the new lwsws process, which does not share
+per-vhost "shared world" data with the deprecated process. That means no new
+connections on the deprecated context, ie a "shrinking world" for those guys, and a
+"growing world" for people who connect after the SIGHUP.
+
+2) The new lwsws process owes nothing to the previous one. It starts with fresh
+plugins, fresh configuration, fresh root privileges if that how you start it.
+
+The plugins may have been updated in arbitrary ways including struct size changes
+etc, and lwsws or lws may also have been updated arbitrarily.
+
+3) A root parent process is left up that is not able to do anything except
+respond to SIGHUP or SIGTERM. Actual serving and network listening etc happens
+in child processes which use the privileges set in the lwsws config files.
+
+@section lwswssysd Lwsws Integration with Systemd
lwsws needs a service file like this as `/usr/lib/systemd/system/lwsws.service`
```
- [Unit]
- Description=Libwebsockets Web Server
- After=syslog.target
-
- [Service]
- ExecStart=/usr/local/bin/lwsws
- StandardError=null
-
- [Install]
- WantedBy=multi-user.target
+[Unit]
+Description=Libwebsockets Web Server
+After=syslog.target
+
+[Service]
+ExecStart=/usr/local/bin/lwsws
+ExecReload=/usr/bin/killall -s SIGHUP lwsws ; sleep 1 ; /usr/local/bin/lwsws
+StandardError=null
+
+[Install]
+WantedBy=multi-user.target
```
You can find this prepared in `./lwsws/usr-lib-systemd-system-lwsws.service`
-Integration with logrotate
---------------------------
+@section lwswslr Lwsws Integration with logrotate
For correct operation with logrotate, `/etc/logrotate.d/lwsws` (if that's
where we're putting the logs) should contain