TLS & PROXY protocol
Terminating TLS and reading real client addresses behind load balancers.
TLS
Pass standard node:tls server options and the server terminates TLS itself:
import fs from "node:fs";
const server = new SmppServer({
tls: {
key: fs.readFileSync("server.key"),
cert: fs.readFileSync("server.crt"),
// ca, requestCert, minVersion, … — anything node:tls accepts
},
});
await server.listen({ port: 3550 });Clients connect with ssmpp:// URLs (or tls: true). session.secure reports
whether a session came in over TLS.
PROXY protocol
When HAProxy, AWS NLB, or another L4 balancer fronts your server, the TCP source address you see is the balancer's — the client's real address arrives in a PROXY protocol header prepended to the stream. Enable the native parser (v1 text and v2 binary, IPv4 and IPv6):
const server = new SmppServer({ proxyProtocol: true });
server.on("session", (session) => {
session.remoteAddress; // the real client, from the header
session.remotePort;
session.proxyAddress; // { address, port } of the balancer, or undefined
});Behavior details:
- Connections without a header still work — direct connections bypass cleanly, so you can enable it before the balancer starts sending headers.
- v2 LOCAL commands (health checks) are skipped without addresses.
- Malformed or oversized headers destroy the connection and surface on
server.on("error")— nothing half-parsed reaches the SMPP layer.
PROXY + TLS together
The PROXY header is sent in plaintext before the TLS handshake. better-smpp handles the ordering natively — header first, then TLS, then SMPP:
const server = new SmppServer({
proxyProtocol: true,
tls: { key, cert },
});The original node-smpp delegated this to the unmaintained proxywrap package;
better-smpp implements the parser natively with zero dependencies, including the
edge case where the TLS ClientHello arrives in the same TCP segment as the header.