Lunar - Installation
This guide takes a fresh server to a running Lunar instance. It is written to be followed top to bottom, and it keeps the steps as simple as possible. The Configure Lunar step below shows the complete config file with every option documented inline.
Supported platforms
Lunar runs on Ubuntu Linux only, and only on Long Term Support (LTS) releases. We do not support non-LTS (interim) releases, other Linux distributions, or other operating systems.
Our support policy is straightforward:
We support an Ubuntu LTS release for as long as it remains in standard support from Canonical. As older LTS releases reach end of life, our support for them ends with Canonical's.
We do not necessarily publish a Lunar build for the newest LTS the moment it is released. We qualify each new LTS ourselves first, and publish a build for it once we are satisfied it is stable for production. Until then, stay on the most recent LTS for which we already provide a build.
If you are unsure which release to target, use the latest LTS for which a Lunar package is available on the downloads page below.
Licensing
Lunar requires a valid license to run. This applies to every deployment, including integration work and proof-of-concept evaluations. There is no unlicensed mode.
We are happy to support evaluations: we issue trial licenses and extend them as needed while you build your integration or run a proof of concept. Request one, or ask for an extension, by emailing support@interstellio.io.
The license is bound to the specific machine it is issued for, so a license issued for one host will not validate on another. You request it using that machine's machine-id, which you obtain once Lunar is installed (see Request your license below). Alongside the license, the Interstellio team will provide the server_id, secret and subscriber endpoint your server needs.
Download
Download the latest Lunar package for your Ubuntu LTS release from the Interstellio downloads page:
The package is named lunar-<version>-ubuntu-<release>-<arch>.tgz. Choose the one that matches your Ubuntu LTS version and architecture.
Server requirements
Lunar should run on a dedicated server (physical, VM or KVM). Dedicated processor resources are important: they keep latency low and predictable so it never impacts RADIUS packet processing.
Minimum Requirements:
Ubuntu LTS (see Supported platforms)
2 GB RAM
4 thread processor
100 GB disk space
Prepare the server
Set the hostname
Edit /etc/hosts and set a fully qualified hostname for the server (replace lunar-1.domain.com with yours):
127.0.0.1 localhost
127.0.1.1 lunar-1 lunar-1.domain.com
Apply it:
sudo hostnamectl set-hostname lunar-1.domain.com
Raise system limits
Add the following to /etc/security/limits.conf so the lunar user is not capped by the defaults:
lunar soft nofile 2000000
lunar hard nofile 2000000
lunar soft memlock unlimited
lunar hard memlock unlimited
On a physical or VM/KVM host (not LXC), add the following to /etc/sysctl.conf:
fs.aio-max-nr=1048576
fs.nr_open=2097152
fs.inotify.max_queued_events=1048576
fs.inotify.max_user_instances=8192
fs.inotify.max_user_watches=1048576
kernel.keys.maxkeys=2000
kernel.threads-max=262144
kernel.keys.maxbytes=2000000
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_fin_timeout=3
net.ipv4.tcp_max_syn_backlog=32768
net.ipv4.ip_local_port_range=11000 65535
net.ipv4.neigh.default.gc_thresh3=8192
net.ipv6.neigh.default.gc_thresh3=8192
net.core.netdev_max_backlog=250000
net.core.rmem_max=33554432
net.core.somaxconn=65535
vm.max_map_count=655300
vm.swappiness=0
These values raise kernel limits that a busy RADIUS server would otherwise hit, so the process can scale to high packet rates without the kernel throttling it. In short:
fs.* (aio-max-nr, nr_open, inotify.*): allow far more open file descriptors and async I/O slots per process, so Lunar can hold the many sockets and event handles a high-throughput server needs.
kernel.threads-max and kernel.keys.*: room for Lunar's worker thread pools and the kernel keyrings it uses, so thread and key creation never hits a ceiling under load.
net.ipv4.tcp_* and net.ipv4.ip_local_port_range: recycle closed connections quickly and widen the ephemeral port range, so many short-lived backend API connections do not exhaust available ports.
net.core.* (netdev_max_backlog, rmem_max, somaxconn) and the neigh.*.gc_thresh3 entries: deepen the network receive and accept queues and the ARP/neighbour tables, so bursts of RADIUS packets are absorbed instead of dropped.
vm.max_map_count and vm.swappiness=0: give the process plenty of memory mappings and keep it in RAM rather than swapping, which protects latency.
They are safe defaults for a dedicated Lunar server and rarely need adjusting.
Update and reboot
sudo apt update
sudo apt upgrade -y
sudo reboot
Install dependencies
Lunar ships as prebuilt binaries, so you only need the runtime libraries - no compiler, headers or build tools. Install nginx (used as the TLS proxy) and the runtime libraries:
sudo apt install -y \
nginx \
libjemalloc2 \
libmsgpackc2 \
libnghttp2-14 \
librdkafka1 \
libyaml-cpp0.8 \
libssl3t64 \
zlib1g
Install Lunar
Create the lunar user
sudo useradd lunar -s /usr/sbin/nologin -d /opt/lunar
Unpack Lunar
Unpack the downloaded package into /opt/lunar so the tree lives at /opt/lunar/bin, /opt/lunar/etc and so on:
sudo mkdir -p /opt/lunar
sudo tar -xzf lunar-*-ubuntu-*.tgz -C /opt/lunar --strip-components=1
We strongly recommend installing under /opt/lunar. This is the standard location assumed by our documentation, the systemd service, the default config paths and support procedures. Installing elsewhere is possible but unsupported.
Install the systemd service
sudo ln -s /opt/lunar/etc/systemd/system/lunar.service /etc/systemd/system/lunar.service
sudo systemctl enable lunar
Request your license
The license is bound to this machine. Read the machine-id and send it to us:
/opt/lunar/bin/lunar -m
Email the machine-id to support@interstellio.io to request a license (mention if it is for a trial or proof of concept). In return you receive your license, and the server_id, secret and subscriber endpoint for your deployment.
Configure Lunar
Lunar is configured from a single YAML file, /opt/lunar/etc/lunar.yaml. It is read once at start-up, so restart lunar (sudo systemctl restart lunar) after changing it. The complete file is shown below, with every option documented inline. The values shown are the shipped defaults; to go live set at least license, server_id, secret and subscriber.endpoint to the values Interstellio provided, and keep services.subscriber set to true so the RADIUS service starts.
lunar:
# Your license, which authorises this server to run and unlocks the
# services it is licensed for. lunar verifies it offline and binds it to
# this machine, so a license issued for one host will not validate on
# another.
#
# To request a license, contact the Interstellio IO team and provide this
# machine's machine-id. Get it by running:
#
# /opt/lunar/bin/lunar -m
#
# Paste the license you receive below. Without a valid license, licensed
# services (e.g. subscriber/RADIUS) will not be authorised.
license: <your_license>
# Log verbosity: DEBUG, INFO, WARNING, ERROR or CRITICAL. Best practice:
# INFO in production - DEBUG logs every packet and will flood under load.
log_level: INFO
# Optional text prepended to every log line, useful to tag the instance
# when multiple lunar servers log to the same collector. Empty = no prefix.
log_prefix: ""
# Debug mode enables printing logs to stdout. Best practice:
# False in production - it costs performance.
debug_mode: False
# Unique identity of this lunar server. Sent with every API request and
# stamped into every Kafka event (source.server-id), so downstream
# systems can tell which server handled the traffic. Provided by the
# Interstellio IO team and unique per server. Do not change it.
server_id: <your_lunar_server_id>
# Shared secret used to authenticate this server to the backend API.
# Provided by the Interstellio IO team and must match the secret
# configured in the backend. Do not change it.
secret: <your_lunar_secret_key>
# Threads serving lunar's own management/API listener below. The default
# is fine for most deployments; raise only if the management API itself
# is under heavy use.
api_threads: 32
# Port and address of lunar's management/API listener. This listener may
# face a public network; best practice is to run it behind a local nginx
# reverse proxy (for TLS termination and access control) rather than
# exposing it directly.
api_port: 1337
api_host: 127.0.0.1
services:
# Which lunar services run in this process. The subscriber service is
# the RADIUS engine. Set true to serve RADIUS. In the future we will
# support many more.
subscriber: true
subscriber:
# Backend API that processes RADIUS requests (authentication, accounting
# and CoA decisions are made there, not in lunar). Point this at your
# nearest Interstellio region, or your own backend implementing the same
# API.
endpoint: https://<region-endpoint>
# Verify the backend's TLS certificate. Best practice: True in production
# with an https endpoint; False only for local testing.
ssl_verify: True
protocol:
radius:
# Self-contained test mode. When true (with services.subscriber: true)
# lunar starts a built-in TEST virtual on 127.0.0.1 with a client-test
# client and secret testing123, and needs no backend - handy to prove
# the install works before your backend is ready. It does NOT validate
# credentials: every auth request is answered access-accept, so only
# PAP is meaningful with radtest. CHAP, MS-CHAP, MS-CHAPv2 and EAP need
# a real backend that runs the challenge/response, so they will not
# authenticate here. For local verification only; never enable it in
# production.
testing: false
# Interstellio RADIUS attribute dictionary shipped with lunar.
dictionary: /opt/lunar/share/lunar/radius/dictionary.yaml
# Maximum packets per second accepted per virtual server. 0 = unlimited.
# Best practice: set a ceiling in production so one misbehaving
# virtual radius cannot starve the others.
virtual_rate_limit: 0
# Depth of each internal processing queue. When a queue is full new
# packets are dropped (the NAS retransmits, so brief bursts are safe).
# Raise for high-throughput deployments; more depth = more memory and
# more latency under sustained overload.
queue_size: 8000
# Seconds to wait for the backend API before giving up on a request
# (maximum 5). Keep this BELOW the NAS retransmit timeout so lunar never
# answers a request the NAS has already given up on.
request_timeout: 2
# Thread pools for the processing stages, in packet order:
# udp_listen_threads - receive packets off the wire
# inbound_request_process_threads - parse/validate, submit to the API
# api_client_threads - drive HTTP requests to the API
# api_client_thread_inflight - max concurrent API requests PER
# api_client thread
# outbound_request_process_threads - build replies from API responses
# udp_reply_threads - send replies back to the NAS
# Best practice: scale these together with CPU core count; the API
# client threads and inflight limit set the ceiling on concurrent
# backend requests (threads x inflight).
#
# You should not need to change these values. The defaults comfortably
# sustain up to around 4000 requests in flight concurrently. If your
# machine is already out of resources, raising these will not help and
# will most likely make performance worse, because of the added thread
# context switching.
#
# If your system has capacity for more load and you need help tuning
# these values, contact our support at support@interstellio.io.
udp_listen_threads: 2
inbound_request_process_threads: 2
api_client_threads: 4
api_client_thread_inflight: 1000
outbound_request_process_threads: 2
udp_reply_threads: 2
kafka:
# Ship RADIUS events to Kafka. Enabled per event type by setting its
# topic; requires at least one broker. Remove a topic (or the
# brokers) to disable shipping for that event type.
#
# Events are JSON with a common envelope: timestamp, event type,
# source (hostname + server-id), metadata (virtual server, client and
# NAS identities) and data (the RADIUS record). Authentication events
# pair the request with its reply; accounting events carry the
# accounting record. Events for the same user/station/session stay on
# one partition, in order.
#
# Shipping is best-effort by design: RADIUS processing is never
# delayed or blocked by Kafka. If events cannot be buffered they are
# dropped and a warning is logged.
# authentication-topic: radius-authentication
# accounting-topic: radius-accounting
# Topics must already exist on the brokers. Lunar never creates them
# and refuses broker-side auto-creation: producing to a topic that
# does not exist fails per event (the event is dropped and a warning
# is logged). Have your Kafka administrator pre-create the topics with
# the right partitions, replication and retention for your cluster.
# Event buffering while brokers are slow or unreachable. Buffered
# events are delivered once brokers recover; when a limit is reached,
# new events are dropped (and a warning is logged) rather than held
# back. buffer_events_count_limit is the maximum buffered events;
# buffer_events_size_mb is the maximum buffered megabytes - whichever
# fills first applies. Both limits are per producer thread.
# Best practice: size for the outage you want to ride out - average
# events/second x seconds of outage, with size_mb to match (events
# are roughly 2-8 KB each). Memory is only consumed while brokers
# fall behind.
buffer_events_count_limit: 1000000
buffer_events_size_mb: 100
# Threads producing to Kafka. One comfortably handles most workloads;
# raise only if a single thread cannot keep up with your event rate.
# Note the buffer limits above are per thread.
producer_threads: 1
# Delivery tuning. batch_size = max events sent to a broker in one
# request; linger_ms = how long to wait for a batch to fill before
# sending (higher = better throughput, more delay); compression =
# none, gzip, snappy, lz4 or zstd. Best practice: the defaults
# (10000 / 100 / lz4) suit most deployments; lower linger_ms if
# consumers need events sooner.
batch_size: 10000
linger_ms: 100
compression: lz4
# TLS encryption to the brokers. Set ssl: True to encrypt all Kafka
# traffic (the brokers must have TLS listeners). ssl_ca is the CA
# certificate bundle used to verify the brokers (omit to use the
# system CA store). If the brokers require client certificates
# (mutual TLS), set ssl_cert and ssl_key. ssl_verify: False disables
# broker certificate verification - testing only. Best practice:
# always enable ssl when brokers are reached over any shared network,
# and keep ssl_verify: True.
# ssl: True
# ssl_ca: /etc/lunar/kafka-ca.pem
# ssl_cert: /etc/lunar/kafka-client.pem
# ssl_key: /etc/lunar/kafka-client.key
# ssl_verify: True
# Username/password authentication (SASL), enabled by setting a
# username. Enable ssl as well so credentials are encrypted in
# transit. sasl_mechanism must match the brokers' setup: PLAIN,
# SCRAM-SHA-256 or SCRAM-SHA-512 (the default). Best practice:
# SCRAM-SHA-512 with ssl, and a dedicated Kafka user for lunar with
# write access to these topics only.
# username: lunar
# password: secret
# sasl_mechanism: SCRAM-SHA-512
# Bootstrap brokers, used for the initial connection only: the full
# cluster is discovered from whichever broker answers first, and
# events are then delivered to the right brokers automatically -
# including brokers not listed here. If a broker fails, delivery
# moves to the remaining brokers on its own. Best practice: list 2-3
# brokers so startup survives one being down (no need to list the
# whole cluster); durability against broker loss comes from the
# topic's replication factor on the Kafka side, not from this list.
brokers:
- localhost:9092
Lock the file down so only the lunar user can read it - it holds your secret and license:
sudo chown lunar:lunar /opt/lunar/etc/lunar.yaml
sudo chmod 600 /opt/lunar/etc/lunar.yaml
Configure the TLS proxy
The management API listens locally on 127.0.0.1:1337. nginx sits in front of it to provide TLS. Generate a certificate (a self-signed one is fine to start; use a CA-signed certificate on a real FQDN for production):
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/private/lunar.key \
-out /etc/ssl/certs/lunar.crt
sudo chmod 640 /etc/ssl/private/lunar.key
sudo chown root:ssl-cert /etc/ssl/private/lunar.key
Replace /etc/nginx/sites-enabled/default with a proxy to Lunar:
upstream LUNAR {
keepalive 128;
keepalive_requests 128;
keepalive_timeout 30;
server 127.0.0.1:1337;
}
server {
listen 443 default_server ssl;
ssl_certificate /etc/ssl/certs/lunar.crt;
ssl_certificate_key /etc/ssl/private/lunar.key;
ssl_protocols TLSv1.2 TLSv1.3;
root /var/www;
location / {
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_set_header Connection "";
proxy_buffering on;
proxy_pass http://LUNAR;
}
}
Start Lunar
Please ensure you have added license to config file before starting. Review Next Steps below.
sudo systemctl enable nginx
sudo systemctl restart nginx
sudo systemctl start lunar
Next steps
RADIUS Quickstart - get a virtual and client serving RADIUS end to end.
RADIUS Integration - the full reference for how lunar talks to your backend, and how to configure virtuals and clients.