WebSockets » History » Revision 3
« Previous |
Revision 3/6
(diff)
| Next »
gstrauss, 2023-12-14 08:46
WebSockets¶
- Table of contents
- WebSockets
WebSocket echo samples
Overview¶
What are websockets? The WebSocket API
lighttpd can facilitate WebSocket connections in numerous ways, including via mod_proxy, mod_cgi, mod_scgi, mod_fastcgi, mod_wstunnel.
- lighttpd supports HTTP/1.1 `Upgrade: websocket` from the HTTP/1.1 connection.
- lighttpd supports HTTP/2 extended CONNECT with `:protocol: websocket` on HTTP/2 streams over a single HTTP/2 connection.
For security reasons and supporting the principle of least surprise, lighttpd support for websockets is intentionally disabled by default. lighttpd dynamic modules may be configured to enable connection upgrade to the websocket protocol.
Since lighttpd 1.4.46, lighttpd mod_cgi, mod_proxy, and mod_wstunnel support websockets. Support in additional dynamic modules mod_scgi and mod_fastcgi has been added in lighttpd 1.4.74.
This document demonstrates multiple ways to configure lighttpd modules to run WebSocket "echo" sample applications.
Basic Configuration¶
websockets via mod_wstunnel¶
Configure mod_wstunnel
mod_wstunnel is a WebSocket tunnel endpoint, terminating the websocket tunnel from a client. mod_wstunnel decodes websocket frames and then passes data (without websocket frames) to a backend, and in the opposite direction encodes responses from backend into websocket frames before sending responses to client.
websockets via mod_proxy¶
Configure mod_proxy and enable proxy.header += ("upgrade" => "enable")
With lighttpd 1.4.74 and later, "upgrade" => "enable"
is also a host option in proxy.server
mod_proxy can act as a reverse proxy for websocket connections when upgrade is enabled.
websockets via mod_cgi¶
Configure mod_cgi and enable cgi.upgrade = "enable"
mod_cgi allows the target program to upgrade to use the websocket protocol.
websockets via mod_scgi¶
Configure mod_scgi and add "upgrade" => "enable"
to options for each host in scgi.server
(lighttpd 1.4.74 and later)
mod_scgi allows the target program to upgrade to use the websocket protocol.
websockets via mod_fastcgi¶
Configure mod_fastcgi and add "upgrade" => "enable"
to options for each host in fastcgi.server
(lighttpd 1.4.74 and later)
mod_fastcgi allows the target program to upgrade to use the websocket protocol.
While lighttpd does not currently multiplex multiple requests on a single FastCGI connection, the FastCGI protocol allows such. lighttpd mod_fastcgi sends and receives FastCGI packets from the backend, even after a request is upgraded to use the websocket protocol. websocket frames are again framed into FastCGI packets. As such, this may be less efficient than using other lighttpd modules which support upgrading to the websocket protocol.
Sample: ws_echo.py¶
ws_echo.py - simple "echo" websocket server CGI sample program
Install files under document root and ws/ subdirectory<docroot>/ws_echo.html
<docroot>/ws/ws_echo.py
Modify the URL in ws_echo.html to use wss:// instead of ws:// if using https.var host = "ws://" + window.location.hostname + "/ws/ws_echo.py";
Example: configure lighttpd to run CGI programs under /ws/¶
server.modules += ("mod_cgi") $HTTP["url"] =^ "/ws/" { cgi.assign = ("" => "") cgi.upgrade = 1 #cgi.limits = ( "read-timeout" => 60, "write-timeout" => 60 ) } #server.max-read-idle := 60 #server.max-write-idle := 60
Example: configure lighttpd to run SCGI programs under /ws/¶
Use scgi-cgi to run `ws_echo.py`
server.modules += ("mod_scgi") scgi.server = ("/ws/" => (( "socket" => "/tmp/scgi-ws.sock", # should use more secure location "bin-path" => "/usr/local/bin/scgi-cgi" # modify path to scgi-cgi "check-local" => "disable", "min-procs" => 1, "max-procs" => 1, "upgrade" => 1 #"read-timeout" => 60, #"write-timeout" => 60, )) ) #server.max-read-idle := 60 #server.max-write-idle := 60
Example: configure lighttpd to run FastCGI programs under /ws/¶
Use fcgi-cgi to run `ws_echo.py`
server.modules += ("mod_fastcgi") fastcgi.server = ("/ws/" => (( "socket" => "/tmp/fcgi-ws.sock", # should use more secure location "bin-path" => "/usr/local/bin/fcgi-cgi" # modify path to fcgi-cgi "check-local" => "disable", "min-procs" => 1, "max-procs" => 1, "upgrade" => 1 #"read-timeout" => 60, #"write-timeout" => 60, )) ) #server.max-read-idle := 60 #server.max-write-idle := 60
Sample: echo.pl¶
echo.pl - trivial "echo" script which reads and echoes line-by-line
This script knows nothing about websockets and could read/write JSON or anything else. This example reads and echoes line-by-line.
Install files under script location and document root/tmp/echo.pl
<docroot>/count.html
echo.pl
#!/usr/bin/perl -Tw $SIG{PIPE} = 'IGNORE'; for (my $FH; accept($FH, STDIN); close $FH) { select($FH); $|=1; # $FH->autoflush; print $FH $_ while (<$FH>); }
<docroot>/count.html
<!DOCTYPE html> <!-- modified from example in https://github.com/joewalnes/websocketd README.md --> <pre id="log"></pre> <script> // helper function: log message to screen var logelt = document.getElementById('log'); function log(msg) { logelt.textContent += msg + '\n'; } // helper function: send websocket msg with count (1 .. 5) var ll = 0; function send_msg() { if (++ll <= 5) { log('SEND: '+ll); ws.send(ll+'\n'); } } // setup websocket with callbacks var ws = new WebSocket('ws://'+location.host+'/ws/'); ws.onopen = function() { log('CONNECT\n'); send_msg(); }; ws.onclose = function() { log('DISCONNECT'); }; ws.onmessage = function(event) { log('RECV: ' + event.data); send_msg(); }; </script>
echo-incremental.pl
Here is an alternative sample "echo" script which is unbuffered -- instead of the simpler line-buffered example above -- and will sleep 1 second between reads so that you can visualize in the browser that multiple websocket messages are going back and forth to the server. This sample script will run for 5 seconds and then will close the websocket connection. (To run this example, use this script in place of echo.pl
and restart lighttpd running lighttpd-wstunnel.conf)
#!/usr/bin/perl -Tw $SIG{PIPE} = 'IGNORE'; for (my $FH; accept($FH, STDIN); close $FH) { foreach (1..5) { sleep 1; my $foo = ""; sysread($FH, $foo, 1024); if (length($foo)) { syswrite($FH, $foo); } } close $FH; }
Example: configure lighttpd to act as WebSocket endpoint for URLs under /ws/¶
This is a simple example showing lighttpd mod_wstunnel terminating a websocket tunnel and sending/receiving payloads to backend "echo" script. For this example, run lighttpd with mod_wstunnel on an alternate port, and this example will be reused below in an example using mod_proxy.
lighttpd-wstunnel.conf
(listening on port 8081; start with lighttpd -D -f /dev/shm/lighttpd-wstunnel.conf
; Ctrl-C to quit)
server.document-root = "/tmp" # place count.html here (better: use a more secure location) server.bind = "127.0.0.1" # comment out if accessing from remote machine server.port = 8081 server.modules += ("mod_wstunnel") wstunnel.server = ( "/ws/" => ( ( "socket" => "/tmp/echo.sock", # should use more secure location "bin-path" => "/tmp/echo.pl", # should use more secure location "max-procs" => 1 ) ) )
Load into local browser as http://localhost:8081/count.html and watch it count 1 .. 5. If you are connecting from a remote system, then modify lighttpd-wstunnel.conf to comment out
server.bind = "127.0.0.1"
and replace localhost
in the URL to count.html. Replace localhost
in the URL if accessing from remote machine.
Example: configure lighttpd to reverse proxy URLs under /ws/¶
This is a simple example showing lighttpd mod_proxy supporting websockets to another lighttpd instance using mod_wstunnel to terminate the websocket tunnel and send/receive payloads to backend "echo" script. It uses the mod_wstunnel example above, so be sure that is running, too.
lighttpd-proxy.conf
(listening on port 8080; start with lighttpd -D -f /dev/shm/lighttpd-proxy.conf
in another shell; Ctrl-C to quit)
server.document-root = "/tmp" # place count.html here (better: use a more secure location) server.bind = "127.0.0.1" # comment out if accessing from remote machine server.port = 8080 server.modules += ("mod_proxy") proxy.server = ( "/" => (( "host" => "127.0.0.1", "port" => "8081" ))) proxy.header = ( "upgrade" => "enable" )
Load into local browser as http://localhost:8080/count.html and watch it count 1 .. 5. If you are connecting from a remote system, then modify lighttpd-proxy.conf to comment out
server.bind = "127.0.0.1"
and replace localhost
in the URL to count.html. Replace localhost
in the URL if accessing from remote machine.
Please note in this example that the count.html target is now http://localhost:8080/count.html, using port 8080 (changed from 8081 in example above).
Updated by gstrauss 12 months ago · 3 revisions