Socket Server
The Sparkle socket server is a self-contained, high-performance HTTP server for Linux and Windows, implemented entirely in Delphi over raw sockets. It is the recommended way to deploy Sparkle-based servers (including TMS XData and TMS RemoteDB servers) on Linux: a single binary with no external web server (Apache, nginx) or third-party library required. On Windows it is an alternative to the Http.Sys-based server that needs no administrative setup and behaves identically across both platforms.
Main features:
- HTTP/1.1 with persistent (keep-alive) connections, chunked transfer encoding and pipelining.
- HTTPS via OpenSSL 3, including SNI (multiple certificates on one port) and zero-downtime certificate reload.
- WebSockets (ws and wss), using the standard Sparkle WebSocket middleware.
- Static file serving through TStaticModule.
- Built-in hardening: request size limits, header read timeout (slowloris protection), keep-alive idle timeout, connection limit and overload protection (503 responses when the request queue is full).
Internally, an event loop thread (based on epoll on Linux and WSAPoll on Windows) accepts connections and reads request heads, so slow clients never occupy a worker thread. Complete requests are then processed synchronously by a worker thread pool, following the same module and dispatcher contract as all other Sparkle servers - existing modules run unchanged.
Note
The socket server is available for the Linux 64-bit and Windows 32/64-bit platforms, on Delphi 11 or newer.
Choosing between the socket server and Http.Sys on Windows
On Windows, the Http.Sys-based server remains the recommended choice for high-load production servers: it is kernel-mode (requests are queued in the kernel before any user code runs), supports sharing a port with other applications, and integrates with the Windows certificate store for HTTPS. Prefer the socket server on Windows when:
- the application cannot register URL reservations or certificate bindings
(Http.Sys requires administrative
netshconfiguration, the socket server binds plain sockets and needs none); - you want the exact same server behavior and configuration on Windows and Linux (development on Windows, deployment on Linux, for example);
- you prefer PEM-file certificates with SNI and zero-downtime reload over the Windows certificate store.
Getting Started
The server class is TSocketHttpServer, declared in unit Sparkle.Socket.Server. Its API mirrors THttpSysServer: register server modules - XData, RemoteDB, static files or your own - and start the server.
uses {...}, Sparkle.Socket.Server;
var
Server: TSocketHttpServer;
begin
Server := TSocketHttpServer.Create;
try
Server.AddModule(TMyServerModule.Create('http://localhost:8080/myapplication'));
Server.Start;
// server runs until the user hits Return
ReadLn;
Server.Stop;
finally
Server.Free;
end;
end;
The server binds one listening socket per port used by the registered modules. Only the port of each module base URL is used for listening - requests are routed to modules by path, exactly as described in the server overview. Both IPv4 and IPv6 connections are accepted.
Note
The host part of the module base URL is ignored - the server always listens
on all local network interfaces. http://localhost:8080/myapplication,
http://0.0.0.0:8080/myapplication and http://myapp.com:8080/myapplication
are therefore equivalent, and a module base URL can be moved between
dispatchers unchanged: the
Http.Sys-based server also
replaces the host with the + wildcard by default, unless
TCustomHttpSysServer.KeepHostInUrlPrefixes is set to true.
The socket server has no equivalent option; to restrict which clients can
reach it, use a firewall rule or a reverse proxy.
TSocketHttpServer.Stop performs a graceful shutdown: listeners are closed, requests in progress are allowed to finish and active WebSocket sessions are terminated.
Configuration
All configuration properties of TSocketHttpServer take effect when the server starts. The defaults are production-ready; tune them only when needed (see the API reference for the exact default values).
- Concurrency: TSocketHttpServer.WorkerThreads sets the minimum number of worker threads that process requests (0, the default, means twice the processor count) and TSocketHttpServer.MaxWorkerThreads the maximum the server may reach under load (0, the default, means 256). See Worker threads and blocking handlers.
- Overload protection: TSocketHttpServer.MaxQueuedRequests caps how many requests may wait for a free worker (further requests are answered with 503 and the connection is closed); TSocketHttpServer.MaxConnections caps simultaneous connections (further connections are refused); and TSocketHttpServer.ListenBacklog sets the backlog of the listening sockets. A value of 0 means unlimited for the first two.
- Timeouts: TSocketHttpServer.HeaderReadTimeout bounds how long a client may take to send the complete request head (slowloris protection; it also bounds the TLS handshake); TSocketHttpServer.KeepAliveTimeout controls how long an idle keep-alive connection is kept open; and TSocketHttpServer.ReadTimeout / TSocketHttpServer.WriteTimeout bound the worker-side request body reads and response writes.
Server := TSocketHttpServer.Create;
Server.WorkerThreads := 32;
Server.KeepAliveTimeout := 30000;
Worker threads and blocking handlers
A worker thread is busy for as long as the handler runs. Handlers that return immediately need very few threads, but a handler that waits - a database query, a call to another server - holds its worker while it waits, doing nothing. With a fixed number of workers, throughput would then be capped at "workers divided by handler duration", no matter how idle the machine is.
The server avoids that by sizing the pool automatically: it starts TSocketHttpServer.WorkerThreads threads and, whenever requests are waiting for a worker, adds threads up to TSocketHttpServer.MaxWorkerThreads (256 by default). Threads above the minimum exit after 30 seconds without work, so the pool shrinks back when the load drops. Requests that are handled immediately do not grow the pool, so a CPU-bound server keeps running on its initial threads.
This means the defaults are usually the right choice and you do not need to measure a thread count. Set the properties when you want a different shape:
- Raise TSocketHttpServer.WorkerThreads to keep more threads ready for a steady blocking load, avoiding the small delay of creating them at the first burst.
- Lower TSocketHttpServer.MaxWorkerThreads when handlers compete for a limited resource - most often a database connection pool. Threads beyond the size of that pool only wait in line for it, so a ceiling close to that size (and a matching TSocketHttpServer.MaxQueuedRequests) fails fast under overload instead of piling up threads.
- Set both properties to the same value for a fixed-size pool.
// database-bound server with a pool of 50 connections
Server.WorkerThreads := 16;
Server.MaxWorkerThreads := 50;
Request limits
The TSocketHttpServer.Limits property (a TSocketServerLimits object) configures the request parser and protects the server from oversized or malformed requests. Requests violating a limit are rejected with the proper status code (413, 414, 431 or 400). You can bound the request line (TSocketServerLimits.MaxRequestLineLength), individual header lines (TSocketServerLimits.MaxHeaderLineLength), the number of headers (TSocketServerLimits.MaxHeaderCount), the total size of the request head (TSocketServerLimits.MaxHeadersLength) and the body size (TSocketServerLimits.MaxBodySize, where 0 means unlimited).
Server.Limits.MaxBodySize := 50 * 1024 * 1024; // reject bodies over 50 MB
Using HTTPS
To serve HTTPS, register modules with an https base URL and configure the
certificate in the TSocketHttpServer.Ssl property (a
TSslOptions object) before starting the server:
Server := TSocketHttpServer.Create;
Server.Ssl.CertificateFile := '/etc/myserver/cert.pem';
Server.Ssl.PrivateKeyFile := '/etc/myserver/key.pem';
Server.AddModule(TMyServerModule.Create('https://myserver.com:8443/myapplication'));
Server.Start;
Certificate and key must be PEM files. If the private key is stored in the certificate file, leave TSslOptions.PrivateKeyFile empty. For encrypted private keys, set TSslOptions.KeyPassword. The certificate file can contain the full chain (server certificate first, then intermediates).
You can mix http and https modules in the same server, as long as each port uses a single scheme.
TLS support is provided by OpenSSL 3, loaded dynamically at runtime.
On Linux (libssl.so.3/libcrypto.so.3), OpenSSL 3 is preinstalled on all
current distributions (Ubuntu 22.04+, Debian 12+, RHEL 9+); no OpenSSL
files need to be deployed with your application. On Windows
(libssl-3-x64.dll/libcrypto-3-x64.dll, or libssl-3.dll/
libcrypto-3.dll for 32-bit), deploy the OpenSSL 3 DLLs alongside your
application executable. TLS 1.2 and TLS 1.3 are supported.
Multiple certificates (SNI)
To serve several host names with different certificates on the same port,
add entries to TSslOptions.SniCertificates. The
certificate is selected by the server name the client requests (SNI). A host
name starting with *. matches exactly one additional label
(*.example.com matches www.example.com, but not example.com or
a.b.example.com). Clients that do not send a recognized server name get
the default certificate (TSslOptions.CertificateFile):
var
Cert: TSslCertificate;
begin
Cert := TSslCertificate.Create;
Cert.HostName := '*.example.com';
Cert.CertificateFile := '/etc/myserver/example-com.pem';
Cert.PrivateKeyFile := '/etc/myserver/example-com.key';
Server.Ssl.SniCertificates.Add(Cert);
end;
Certificate renewal without downtime
Call TSocketHttpServer.ReloadCertificates to re-read all configured certificate files and apply them to new connections, without dropping the listeners or the established connections. This makes automated renewals (for example with certbot / Let's Encrypt) straightforward: renew the PEM files on disk, then have the application call TSocketHttpServer.ReloadCertificates. If the new files cannot be loaded, an exception is raised and the current certificates remain in use.
WebSockets
WebSockets work on the socket server with no additional configuration, using the standard Sparkle upgrade mechanism described in the WebSockets chapter - including secure WebSockets (wss) on https listeners. Idle WebSocket sessions are not subject to the read/keep-alive timeouts, and a graceful TSocketHttpServer.Stop terminates active sessions cleanly.
Serving Static Files
Use the standard TStaticModule to serve static files:
uses {...}, Sparkle.Module.Static;
Server.AddModule(TStaticModule.Create('http://localhost:8080/', '/var/www/myapp'));
Design-Time Component
TSparkleSocketDispatcher (unit Sparkle.Comp.SocketDispatcher) is the dispatcher component that wraps TSocketHttpServer. Use it to build servers the RAD way: drop it in a form or data module, connect server components (TXDataServer, TSparkleStaticServer, etc.) to it through their Dispatcher property, and set Active to true.
The underlying TSocketHttpServer instance is available through the TSparkleSocketDispatcher.Server property, to configure TLS certificates, limits and timeouts from code before activation:
uses {...}, Sparkle.Comp.SocketDispatcher;
SparkleSocketDispatcher1.Server.Ssl.CertificateFile := '/etc/myserver/cert.pem';
SparkleSocketDispatcher1.Server.Ssl.PrivateKeyFile := '/etc/myserver/key.pem';
SparkleSocketDispatcher1.Active := True;
Deploying on Linux
A Sparkle socket server application is a single self-contained binary, which makes deployment simple: compile for the Linux 64-bit platform, copy the binary to the server and run it.
Running as a systemd service
For production, run the server as a systemd service. Build the server as
a console application that runs until terminated, and create a unit file
like /etc/systemd/system/myserver.service:
[Unit]
Description=My Sparkle server
After=network.target
[Service]
ExecStart=/opt/myserver/myserver
Restart=always
User=myserver
Group=myserver
[Install]
WantedBy=multi-user.target
Then enable and start it:
sudo systemctl daemon-reload
sudo systemctl enable --now myserver
Note
Binding to ports below 1024 (like 80 and 443) requires privileges. Either
run the service as root, grant the binary the required capability
(sudo setcap cap_net_bind_service=+ep /opt/myserver/myserver), or listen
on a high port behind a reverse proxy.
Using a reverse proxy (optional)
The socket server is designed to be exposed directly to the internet. Still, you can put a reverse proxy such as nginx or Caddy in front of it if you want features that are out of the socket server scope, such as HTTP/2 or HTTP/3, rate limiting, or centralized certificate management. In that case, use the forward middleware so the server sees the original client address and scheme.
Deploying on Windows
On Windows the deployment is equally simple: copy the executable (plus the
OpenSSL 3 DLLs when serving HTTPS) and run it. Unlike the Http.Sys-based
server, no URL reservation (netsh http add urlacl) or certificate binding
is required - the server binds regular sockets, so it runs under any user
account. For production, host the application as a Windows service. Note
that the Windows Firewall may prompt for (or require) an inbound rule for
the application when it first listens on a port.
Demo
A complete demo serving a dynamic endpoint, static files and a WebSocket
echo endpoint - with optional HTTPS - is available in the TMS Sparkle
distribution at demos/SocketServer.