better-smpp
Server

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.

On this page