file serve: defer transaction completed to HTTP_FILE_COMPLETION
[platform/upstream/libwebsockets.git] / README.lwsws.md
1 Notes about lwsws
2 =================
3
4 @section lwsws Libwebsockets Web Server
5
6 lwsws is an implementation of a very lightweight, ws-capable generic web
7 server, which uses libwebsockets to implement everything underneath.
8
9 If you are basically implementing a standalone server with lws, you can avoid
10 reinventing the wheel and use a debugged server including lws.
11
12
13 @section lwswsb Build
14
15 Just enable -DLWS_WITH_LWSWS=1 at cmake-time.
16
17 It enables libuv and plugin support automatically.
18
19 NOTICE on Ubuntu, the default libuv package is called "libuv-0.10".  This is ancient.
20
21 You should replace this with libuv1 and libuv1-dev before proceeding.
22
23 @section lwswsc Lwsws Configuration
24
25 lwsws uses JSON config files, they're pure JSON except:
26
27  - '#' may be used to turn the rest of the line into a comment.
28
29  - There's also a single substitution, if a string contains "_lws_ddir_", then that is
30 replaced with the LWS install data directory path, eg, "/usr/share" or whatever was
31 set when LWS was built + installed.  That lets you refer to installed paths without
32 having to change the config if your install path was different.
33
34 There is a single file intended for global settings
35
36 /etc/lwsws/conf
37 ```
38         # these are the server global settings
39         # stuff related to vhosts should go in one
40         # file per vhost in ../conf.d/
41
42         {
43           "global": {
44            "uid": "48",  # apache user
45            "gid": "48",  # apache user
46            "count-threads": "1",
47            "server-string": "myserver v1", # returned in http headers
48            "ws-pingpong-secs": "200", # confirm idle established ws connections this often
49            "init-ssl": "yes"
50          }
51         }
52 ```
53 and a config directory intended to take one file per vhost
54
55 /etc/lwsws/conf.d/warmcat.com
56 ```
57         {
58                 "vhosts": [{
59                         "name": "warmcat.com",
60                         "port": "443",
61                         "interface": "eth0",  # optional
62                         "host-ssl-key": "/etc/pki/tls/private/warmcat.com.key",  # if given enable ssl
63                         "host-ssl-cert": "/etc/pki/tls/certs/warmcat.com.crt",
64                         "host-ssl-ca": "/etc/pki/tls/certs/warmcat.com.cer",
65                         "mounts": [{  # autoserve
66                                 "mountpoint": "/",
67                                 "origin": "file:///var/www/warmcat.com",
68                                 "default": "index.html"
69                         }]
70                 }]
71         }
72 ```
73 To get started quickly, an example config reproducing the old test server
74 on port 7681, non-SSL is provided.  To set it up
75 ```
76         # mkdir -p /etc/lwsws/conf.d /var/log/lwsws
77         # cp ./lwsws/etc-lwsws-conf-EXAMPLE /etc/lwsws/conf
78         # cp ./lwsws/etc-lwsws-conf.d-localhost-EXAMPLE /etc/lwsws/conf.d/test-server
79         # sudo lwsws
80 ```
81
82 @section lwsogo Other Global Options
83
84  - `reject-service-keywords` allows you to return an HTTP error code and message of your choice
85 if a keyword is found in the user agent
86
87 ```
88    "reject-service-keywords": [{
89         "scumbot": "404 Not Found"
90    }]
91 ```
92
93  - `timeout-secs` lets you set the global timeout for various network-related
94  operations in lws, in seconds.  It defaults to 5.
95  
96 @section lwswsv Lwsws Vhosts
97
98 One server can run many vhosts, where SSL is in use SNI is used to match
99 the connection to a vhost and its vhost-specific SSL keys during SSL
100 negotiation.
101
102 Listing multiple vhosts looks something like this
103 ```
104         {
105          "vhosts": [ {
106              "name": "localhost",
107              "port": "443",
108              "host-ssl-key":  "/etc/pki/tls/private/libwebsockets.org.key",
109              "host-ssl-cert": "/etc/pki/tls/certs/libwebsockets.org.crt",
110              "host-ssl-ca":   "/etc/pki/tls/certs/libwebsockets.org.cer",
111              "mounts": [{
112                "mountpoint": "/",
113                "origin": "file:///var/www/libwebsockets.org",
114                "default": "index.html"
115                }, {
116                 "mountpoint": "/testserver",
117                 "origin": "file:///usr/local/share/libwebsockets-test-server",
118                 "default": "test.html"
119                }],
120              # which protocols are enabled for this vhost, and optional
121              # vhost-specific config options for the protocol
122              #
123              "ws-protocols": [{
124                "warmcat,timezoom": {
125                  "status": "ok"
126                }
127              }]
128             },
129             {
130             "name": "localhost",
131             "port": "7681",
132              "host-ssl-key":  "/etc/pki/tls/private/libwebsockets.org.key",
133              "host-ssl-cert": "/etc/pki/tls/certs/libwebsockets.org.crt",
134              "host-ssl-ca":   "/etc/pki/tls/certs/libwebsockets.org.cer",
135              "mounts": [{
136                "mountpoint": "/",
137                "origin": ">https://localhost"
138              }]
139            },
140             {
141             "name": "localhost",
142             "port": "80",
143              "mounts": [{
144                "mountpoint": "/",
145                "origin": ">https://localhost"
146              }]
147            }
148         
149           ]
150         }
151 ```
152
153 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
154
155
156 @section lwswsvn Lwsws Vhost name and port sharing
157
158 The vhost name field is used to match on incoming SNI or Host: header, so it
159 must always be the host name used to reach the vhost externally.
160
161  - Vhosts may have the same name and different ports, these will each create a
162 listening socket on the appropriate port.
163
164  - Vhosts may also have the same port and different name: these will be treated as
165 true vhosts on one listening socket and the active vhost decided at SSL
166 negotiation time (via SNI) or if no SSL, then after the Host: header from
167 the client has been parsed.
168
169
170 @section lwswspr Lwsws Protocols
171
172 Vhosts by default have available the union of any initial protocols from context creation time, and
173 any protocols exposed by plugins.
174
175 Vhosts can select which plugins they want to offer and give them per-vhost settings using this syntax
176 ```
177              "ws-protocols": [{
178                "warmcat-timezoom": {
179                  "status": "ok"
180                }
181              }]
182 ```
183
184 The "x":"y" parameters like "status":"ok" are made available to the protocol during its per-vhost
185 LWS_CALLBACK_PROTOCOL_INIT (@in is a pointer to a linked list of struct lws_protocol_vhost_options
186 containing the name and value pointers).
187
188 To indicate that a protocol should be used when no Protocol: header is sent
189 by the client, you can use "default": "1"
190 ```
191              "ws-protocols": [{
192                "warmcat-timezoom": {
193                  "status": "ok",
194                  "default": "1"
195                }
196              }]
197 ```
198
199
200 @section lwswsovo Lwsws Other vhost options
201
202  - If the three options `host-ssl-cert`, `host-ssl-ca` and `host-ssl-key` are given, then the vhost supports SSL.
203
204  Each vhost may have its own certs, SNI is used during the initial connection negotiation to figure out which certs to use by the server name it's asking for from the request DNS name.
205
206  - `keeplive-timeout` (in secs) defaults to 60 for lwsws, it may be set as a vhost option
207
208  - `interface` lets you specify which network interface to listen on, if not given listens on all
209
210  - "`unix-socket`": "1" causes the unix socket specified in the interface option to be used instead of an INET socket
211
212  - "`sts`": "1" causes lwsws to send a Strict Transport Security header with responses that informs the client he should never accept to connect to this address using http.  This is needed to get the A+ security rating from SSL Labs for your server.
213
214  - "`access-log`": "filepath"   sets where apache-compatible access logs will be written
215
216  - `"enable-client-ssl"`: `"1"` enables the vhost's client SSL context, you will need this if you plan to create client conections on the vhost that will use SSL.  You don't need it if you only want http / ws client connections.
217
218  - "`ciphers`": "<cipher list>"   sets the allowed list of ciphers and key exchange protocols for the vhost.  The default list is restricted to only those providing PFS (Perfect Forward Secrecy) on the author's Fedora system.
219  
220  If you need to allow weaker ciphers,you can provide an alternative list here per-vhost.
221  
222  - "`ecdh-curve`": "<curve name>"   The default ecdh curve is "prime256v1", but you can override it here, per-vhost
223
224  - "`noipv6`": "on"  Disable ipv6 completely for this vhost
225
226  - "`ipv6only`": "on"  Only allow ipv6 on this vhost / "off" only allow ipv4 on this vhost
227
228  - "`ssl-option-set`": "<decimal>"  Sets the SSL option flag value for the vhost.
229  It may be used multiple times and OR's the flags together.
230  
231  The values are derived from /usr/include/openssl/ssl.h
232 ```
233          # define SSL_OP_NO_TLSv1_1                               0x10000000L
234 ```
235  
236  would equate to
237  
238 ```
239          "`ssl-option-set`": "268435456"
240  ```
241  - "`ssl-option-clear'": "<decimal>"   Clears the SSL option flag value for the vhost.
242  It may be used multiple times and OR's the flags together.
243
244  - "`headers':: [{ "header1": "h1value", "header2": "h2value" }] 
245
246 allows you to set arbitrary headers on every file served by the vhost
247
248 recommended vhost headers for good client security are
249
250 ```
251                    "headers": [{
252                         "Content-Security-Policy": "script-src 'self'",
253                         "X-Content-Type-Options": "nosniff",
254                         "X-XSS-Protection": "1; mode=block",
255                         "X-Frame-Options": "SAMEORIGIN"
256                  }]
257
258 ```
259
260 @section lwswsm Lwsws Mounts
261
262 Where mounts are given in the vhost definition, then directory contents may
263 be auto-served if it matches the mountpoint.
264
265 Mount protocols are used to control what kind of translation happens
266
267  - file://  serve the uri using the remainder of the url past the mountpoint based on the origin directory.
268
269  Eg, with this mountpoint
270 ```
271                {
272                 "mountpoint": "/",
273                 "origin": "file:///var/www/mysite.com",
274                 "default": "/"
275                }
276 ```
277  The uri /file.jpg would serve /var/www/mysite.com/file.jpg, since / matched.
278
279  - ^http:// or ^https://  these cause any url matching the mountpoint to issue a redirect to the origin url
280
281  - cgi://   this causes any matching url to be given to the named cgi, eg
282 ```
283                {
284                 "mountpoint": "/git",
285                 "origin": "cgi:///var/www/cgi-bin/cgit",
286                 "default": "/"
287                }, {
288                 "mountpoint": "/cgit-data",
289                 "origin": "file:///usr/share/cgit",
290                 "default": "/"
291                },
292 ```
293  would cause the url /git/myrepo to pass "myrepo" to the cgi /var/www/cgi-bin/cgit and send the results to the client.
294
295  - http:// or https://  these perform reverse proxying, serving the remote origin content from the mountpoint.  Eg
296
297 ```
298                 {
299                  "mountpoint": "/proxytest",
300                  "origin": "https://libwebsockets.org"
301                 }
302 ```
303
304 This will cause your local url `/proxytest` to serve content fetched from libwebsockets.org over ssl; whether it's served from your server using ssl is unrelated and depends how you configured your local server.  Notice if you will use the proxying feature, `LWS_WITH_HTTP_PROXY` is required to be enabled at cmake, and for `https` proxy origins, your lwsws configuration must include `"init-ssl": "1"` and the vhost with the proxy mount must have `"enable-client-ssl": "1"`, even if you are not using ssl to serve.
305
306 `/proxytest/abc`, or `/proxytest/abc?def=ghi` etc map to the origin + the part past `/proxytest`, so links and img src urls etc work as do all urls under the origin path.
307
308 In addition link and src urls in the document are rewritten so / or the origin url part are rewritten to the mountpoint part.
309
310
311 @section lwswsomo Lwsws Other mount options
312
313 1) Some protocols may want "per-mount options" in name:value format.  You can
314 provide them using "pmo"
315
316                {
317                 "mountpoint": "/stuff",
318                 "origin": "callback://myprotocol",
319                 "pmo": [{
320                         "myname": "myvalue"
321                 }]
322                }
323
324 2) When using a cgi:// protcol origin at a mountpoint, you may also give cgi environment variables specific to the mountpoint like this
325 ```
326                {
327                 "mountpoint": "/git",
328                 "origin": "cgi:///var/www/cgi-bin/cgit",
329                 "default": "/",
330                 "cgi-env": [{
331                         "CGIT_CONFIG": "/etc/cgitrc/libwebsockets.org"
332                 }]
333                }
334 ```
335  This allows you to customize one cgi depending on the mountpoint (and / or vhost).
336
337 3) It's also possible to set the cgi timeout (in secs) per cgi:// mount, like this
338 ```
339         "cgi-timeout": "30"
340 ```
341 4) `callback://` protocol may be used when defining a mount to associate a
342 named protocol callback with the URL namespace area.  For example
343 ```
344                {
345                 "mountpoint": "/formtest",
346                 "origin": "callback://protocol-post-demo"
347                }
348 ```
349 All handling of client access to /formtest[anything] will be passed to the
350 callback registered to the protocol "protocol-post-demo".
351
352 This is useful for handling POST http body content or general non-cgi http
353 payload generation inside a plugin.
354
355 See the related notes in README.coding.md
356
357 5) Cache policy of the files in the mount can also be set.  If no
358 options are given, the content is marked uncacheable.
359 ```
360                {
361                 "mountpoint": "/",
362                 "origin": "file:///var/www/mysite.com",
363                 "cache-max-age": "60",      # seconds
364                 "cache-reuse": "1",         # allow reuse at client at all
365                 "cache-revalidate": "1",    # check it with server each time
366                 "cache-intermediaries": "1" # allow intermediary caches to hold
367                }
368 ```
369
370 6) You can also define a list of additional mimetypes per-mount
371 ```
372                 "extra-mimetypes": {
373                          ".zip": "application/zip",
374                          ".doc": "text/evil"
375                  }
376 ```
377
378 Normally a file suffix MUST match one of the canned mimetypes or one of the extra
379 mimetypes, or the file is not served.  This adds a little bit of security because
380 even if there is a bug somewhere and the mount dirs are circumvented, lws will not
381 serve, eg, /etc/passwd.
382
383 If you provide an extra mimetype entry
384
385                         "*": ""
386
387 Then any file is served, if the mimetype was not known then it is served without a
388 Content-Type: header.
389
390 7) A mount can be protected by HTTP Basic Auth.  This only makes sense when using
391 https, since otherwise the password can be sniffed.
392
393 You can add a `basic-auth` entry on a mount like this
394
395 ```
396 {
397         "mountpoint": "/basic-auth",
398         "origin": "file://_lws_ddir_/libwebsockets-test-server/private",
399         "basic-auth": "/var/www/balogins-private"
400 }
401 ```
402
403 Before serving anything, lws will signal to the browser that a username / password
404 combination is required, and it will pop up a dialog.  When the user has filled it
405 in, lwsws checks the user:password string against the text file named in the `basic-auth`
406 entry.
407
408 The file should contain user:pass one per line
409
410 ```
411 testuser:testpass
412 myuser:hispass
413 ```
414
415 The file should be readable by lwsws, and for a little bit of extra security not
416 have a file suffix, so lws would reject to serve it even if it could find it on
417 a mount.
418
419
420 @section lwswspl Lwsws Plugins
421
422 Protcols and extensions may also be provided from "plugins", these are
423 lightweight dynamic libraries.  They are scanned for at init time, and
424 any protocols and extensions found are added to the list given at context
425 creation time.
426
427 Protocols receive init (LWS_CALLBACK_PROTOCOL_INIT) and destruction
428 (LWS_CALLBACK_PROTOCOL_DESTROY) callbacks per-vhost, and there are arrangements
429 they can make per-vhost allocations and get hold of the correct pointer from
430 the wsi at the callback.
431
432 This allows a protocol to choose to strictly segregate data on a per-vhost
433 basis, and also allows the plugin to handle its own initialization and
434 context storage.
435
436 To help that happen conveniently, there are some new apis
437
438  - lws_vhost_get(wsi)
439  - lws_protocol_get(wsi)
440  - lws_callback_on_writable_all_protocol_vhost(vhost, protocol)
441  - lws_protocol_vh_priv_zalloc(vhost, protocol, size)
442  - lws_protocol_vh_priv_get(vhost, protocol)
443  
444 dumb increment, mirror and status protocol plugins are provided as examples.
445
446
447 @section lwswsplaplp Additional plugin search paths
448
449 Packages that have their own lws plugins can install them in their own
450 preferred dir and ask lwsws to scan there by using a config fragment
451 like this, in its own conf.d/ file managed by the other package
452 ```
453         {
454           "global": {
455            "plugin-dir": "/usr/local/share/coherent-timeline/plugins"
456           }
457         }
458 ```
459
460 @section lwswsssp lws-server-status plugin
461
462 One provided protocol can be used to monitor the server status.
463
464 Enable the protocol like this on a vhost's ws-protocols section
465 ```
466                "lws-server-status": {
467                  "status": "ok",
468                  "update-ms": "5000"
469                }
470 ```
471 `"update-ms"` is used to control how often updated JSON is sent on a ws link.
472
473 And map the provided HTML into the vhost in the mounts section
474 ```
475                {
476                 "mountpoint": "/server-status",
477                 "origin": "file:///usr/local/share/libwebsockets-test-server/server-status",
478                 "default": "server-status.html"
479                }
480 ```
481 You might choose to put it on its own vhost which has "interface": "lo", so it's not
482 externally visible, or use the Basic Auth support to require authentication to
483 access it.
484
485 `"hide-vhosts": "{0 | 1}"` lets you control if information about your vhosts is included.
486 Since this includes mounts, you might not want to leak that information, mount names,
487 etc.
488
489 `"filespath":"{path}"` lets you give a server filepath which is read and sent to the browser
490 on each refresh.  For example, you can provide server temperature information on most
491 Linux systems by giving an appropriate path down /sys.
492
493 This may be given multiple times.
494
495
496 @section lwswsreload Lwsws Configuration Reload
497
498 You may send lwsws a `HUP` signal, by, eg
499
500 ```
501 $ sudo killall -HUP lwsws
502 ```
503
504 This causes lwsws to "deprecate" the existing lwsws process, and remove and close all of
505 its listen sockets, but otherwise allowing it to continue to run, until all
506 of its open connections close.
507
508 When a deprecated lwsws process has no open connections left, it is destroyed
509 automatically.
510
511 After sending the SIGHUP to the main lwsws process, a new lwsws process, which can
512 pick up the newly-available listen sockets, and use the current configuration
513 files, is automatically started.
514
515 The new configuration may differ from the original one in arbitrary ways, the new
516 context is created from scratch each time without reference to the original one.
517
518 Notes
519
520 1) Protocols that provide a "shared world" like mirror will have as many "worlds"
521 as there are lwsws processes still active.  People connected to a deprecated lwsws
522 process remain connected to the existing peers.
523
524 But any new connections will apply to the new lwsws process, which does not share
525 per-vhost "shared world" data with the deprecated process.  That means no new
526 connections on the deprecated context, ie a "shrinking world" for those guys, and a
527 "growing world" for people who connect after the SIGHUP.
528
529 2) The new lwsws process owes nothing to the previous one.  It starts with fresh
530 plugins, fresh configuration, fresh root privileges if that how you start it.
531
532 The plugins may have been updated in arbitrary ways including struct size changes
533 etc, and lwsws or lws may also have been updated arbitrarily.
534
535 3) A root parent process is left up that is not able to do anything except
536 respond to SIGHUP or SIGTERM.  Actual serving and network listening etc happens
537 in child processes which use the privileges set in the lwsws config files.
538
539 @section lwswssysd Lwsws Integration with Systemd
540
541 lwsws needs a service file like this as `/usr/lib/systemd/system/lwsws.service`
542 ```
543 [Unit]
544 Description=Libwebsockets Web Server
545 After=syslog.target
546
547 [Service]
548 ExecStart=/usr/local/bin/lwsws 
549 ExecReload=/usr/bin/killall -s SIGHUP lwsws ; sleep 1 ; /usr/local/bin/lwsws
550 StandardError=null
551
552 [Install]
553 WantedBy=multi-user.target
554 ```
555
556 You can find this prepared in `./lwsws/usr-lib-systemd-system-lwsws.service`
557
558
559 @section lwswslr Lwsws Integration with logrotate
560
561 For correct operation with logrotate, `/etc/logrotate.d/lwsws` (if that's
562 where we're putting the logs) should contain
563 ```
564         /var/log/lwsws/*log {
565             copytruncate
566             missingok
567             notifempty
568             delaycompress
569         }
570 ```
571 You can find this prepared in `/lwsws/etc-logrotate.d-lwsws`
572
573 Prepare the log directory like this
574
575 ```
576         sudo mkdir /var/log/lwsws
577         sudo chmod 700 /var/log/lwsws
578 ```