WebSockets passthrough
WebSockets are two-way communication channels between a client device (such as a web browser) and a server, allowing the server to send messages to the client at any time without the client having to make a request.
Unlike the HTTP requests which make up the bulk of web traffic handled by Fastly, WebSockets are long-lived connections and do not have a request-response cycle, but instead can carry data in either direction at any time. As a result, WebSockets don't fit Fastly's normal processing model for edge traffic, but since WebSocket connections begin life as HTTP requests, you can pass the WebSocket connection directly to the origin server.
HINT: WebSocket passthrough creates one WebSocket connection to origin for every connection from a client device to Fastly. To have Fastly broker messages for you, with channels, and one-to-many publishing, consider using Fanout instead.
Enabling WebSocket passthrough
WebSockets passthrough is an optional upgrade to Fastly service plans. If you have not yet purchased access, contact sales, or start a free trial by enabling the toggle in the web interface on any service.
If your Fastly account has full access to WebSockets, it can be enabled on an individual service in the web interface or by enabling the websockets
product using the product enablement API.
To use WebSocket passthrough, you need a paid Fastly account containing a VCL service, or a Rust-based Compute service. A free trial can be enabled in the 'WebSockets' section of the service configuration options in the web interface.
Fastly Compute
You can create a Rust-based service, automatically populated with the code needed to perform WebSocket passthrough, using fastly compute init:
$ fastly compute init --from=https://github.com/fastly/compute-starter-kit-rust-websockets$ fastly compute publish
Compute programs are typically invoked for each client request and end when you deliver a response. To handle the WebSocket connection, the request must be handed off from the Compute program so that Fastly can continue to hold the connection and relay traffic in both directions.
This is performed by the handoff_websocket
method on the Request
struct. If you are expecting your service to handle more than just WebSockets traffic, it's a good idea to only do this when the request has an Upgrade: websocket
header:
use fastly::{Error, RequestHandle};
fn main() -> Result<(), Error> { let req = RequestHandle::from_client();
if let Some("websocket") = req.get_header_value("Upgrade") { return Ok(req.handoff_websocket("ws_backend_name")?); }
Ok(req.send("non_ws_backend_name")?.send_to_client())}
VCL
In a VCL service, your VCL is invoked for each inbound client request and the VCL workflow is designed to manage a conventional request/response cycle. To handle the WebSocket connection, you must hand off the request from VCL so that Fastly can continue to hold the connection and relay traffic in both directions. To do this, return(upgrade)
from vcl_recv
:
if (req.http.Upgrade) { return (upgrade);}
Tips
The following tips and best practices may help you get the most out of WebSockets passthrough:
- If you use the web interface or API to create the backend, ensure to set a host header override if your server's hosting is name-based. Learn more.
- Unlike most Rust-based Compute programs, you cannot use the
#[fastly::main]
macro in a program that doeshandoff_websocket
. This is becausehandoff_websocket
will immediately start a response to the client, making it impossible to return aResponse
from themain()
function without causing an error. - Client request headers that are added, removed, or modified on your
Request
(orreq.http
in VCL) will be reflected in the WebSocket handoff. - WebSocket connections, once handed off, are not subject to the
between_bytes_timeout
, and will only drop when either the client or server disconnects. - If either the client or server disconnects, Fastly will relay that disconnect to the other party.