A minimal, production-ready CUPS (Configuration and Update Server) implementation using Fastify and TypeScript.
This server parses raw binary requests and responds per the Semtech CUPS binary protocol, dynamically generating and serving gateway credentials, and storing them in S3-compatible object storage.
This server is one half of a two-part LoRaWAN credential management system:
- lorawan-cups-server (this repo) — the CUPS server that gateways connect to in order to receive updated credentials and configuration.
- lorawan-cert-renewer — the companion tool that periodically renews TLS certificates, deploys them to this server, and uploads fresh credential bundles to S3.
lorawan-cert-renewer is responsible for keeping the certificates and S3 credential bundles that this server depends on up to date.
- CUPS Binary Protocol: Handles
/update-infoPOST requests per Semtech's CUPS specification. - Dynamic Credential Generation: Generates gateway-specific credential bundles (CA, client cert, private key) on demand using OpenSSL.
- S3 Integration: Stores and retrieves credential bundles from S3-compatible storage.
- HTTPS by Default: Uses provided certificates for secure communication.
- TypeScript & Modern Tooling: Linting, type-checking, and pre-commit hooks for code quality.
.
├── certs/ # Certificates and credential bundles (gitignored except .gitkeep)
├── src/
│ ├── s3.ts # S3 client and helpers
│ └── utils.ts # Utility functions (ID parsing, cert generation, etc.)
├── index.ts # Main Fastify server and CUPS logic
├── package.json
├── README.md
└── ...
- Node.js 18+
- OpenSSL installed and available in your PATH
- Access to an S3-compatible object storage (e.g., AWS S3, MinIO)
- Gateway CA and server certificates (see below)
-
Install dependencies:
npm install
-
Environment variables:
Create a
.envfile based on.env.examplewith at least:S3_BUCKET_NAME=your-bucket S3_BUCKET_REGION=your-region S3_BUCKET_ENDPOINT=https://your-s3-endpoint S3_ACCESS_KEY_ID=your-access-key S3_SECRET_ACCESS_KEY=your-secret-key CERT_PATH=certs CERT_HOST_PATH= CREDENTIAL_MIN_VALID_DAYS= TC_URI=https://your-tc-uri CUPS_URI=https://your-cups-uri -
Certificates:
- Place your CUPS server key and certificate in the
certs/directory ascups.keyandcups.crt. - Place your CA key and certificate as
ca.keyandca.crtin the same directory. - When using Docker, the
certs/directory is mounted from the host. SetCERT_HOST_PATHin your environment to override the host-side path (defaults to./certsrelative todocker-compose.yml).
- Place your CUPS server key and certificate in the
npm run devRuns the server with ts-node for live TypeScript execution.
npm run build
npm startBuilds to dist/ and runs the compiled JavaScript.
- Accepts:
application/octet-stream(raw binary) - Responds: CUPS binary response with updated credentials and signature
- Lint:
npm run eslint - Type Check:
npm run check-types - Pre-commit: Husky and lint-staged block commits on lint/type errors
- The server dynamically generates gateway credential bundles if not found or expiring soon, and stores them in S3.
- Bundles are stored as binary files in the S3 bucket under the
cups/prefix. - The
certs/directory is gitignored except for.gitkeep.
TC stands for Trust Center. In the context of LoRaWAN and this project, the Trust Center is the secure endpoint (often the LNS—LoRaWAN Network Server) that gateways authenticate with using credentials provided by the CUPS server. The CUPS server manages and distributes both CUPS credentials (for itself) and TC credentials (for the Trust Center) to gateways. The TC credential bundle (e.g., tc_cred.bin) contains the certificates and keys required for secure gateway authentication with the Trust Center endpoint.
CUPS is the Configuration and Update Server. It provides gateways with configuration updates, new credentials, and firmware updates, enabling secure and automated device management in LoRaWAN networks.
LNS stands for LoRaWAN Network Server. It is the backend server responsible for managing LoRaWAN network traffic, device sessions, and security. Gateways typically connect to the LNS for data forwarding and authentication.
S3 refers to Amazon Simple Storage Service or any S3-compatible object storage. In this project, S3 is used to store and retrieve credential bundles and certificates as binary files.
DER is a binary encoding format for cryptographic certificates and keys. It is commonly used for efficient storage and transmission of X.509 certificates and private keys.
PEM is a text-based encoding format for cryptographic certificates and keys, using Base64 with header and footer lines. PEM files are human-readable and commonly used for configuration and transport.
CSR is a Certificate Signing Request. It is a file generated by an entity (such as a gateway) to request a digital certificate from a Certificate Authority (CA), containing the public key and identifying information.
A Gateway is a hardware device that bridges LoRaWAN end devices and the network server (LNS). It receives LoRa radio transmissions and forwards them to the backend over IP, and vice versa.
To generate client keys, certificate signing requests (CSRs), certificates, and the tc_cred.bin bundle for use with this CUPS server, you can use the following OpenSSL commands. These are useful for understanding or manually creating the credential bundles used by gateways.
openssl ecparam -name prime256v1 -genkey -noout -out client.keyReplace 0000000000000000 with your desired Common Name (CN), typically the gateway/router ID (EUI-64).
openssl req -new -key client.key -out client.csr -subj "/CN=0000000000000000"Create a file named cert_ext.cnf with the following content:
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuerReplace ca.crt and ca.key with your CA certificate and key. Adjust validity days as needed.
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out client.crt -days 365 -sha256 -extfile cert_ext.cnf -extensions v3_reqopenssl x509 -in ca.crt -outform DER -out ca.der
openssl x509 -in client.crt -outform DER -out client.crt.der
openssl ec -in client.key -outform DER -out client.key.derConcatenate the CA, client certificate, and client key in DER format to create the binary bundle:
cat ca.der client.crt.der client.key.der > tc_cred.binThis tc_cred.bin file can then be uploaded to S3 or used directly by the CUPS server as a credential bundle for a gateway.
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. See the LICENSE file distributed with this project for full text.