Deploy a standalone RMON Server
Use this guide to deploy a result receiver separately from the RMON web application. Plan access with network requirements and prepare a recovery set before replacing an existing service.
Standalone RMON Server: Docker and mTLS
RMON Server 7.0 and Agent 2.0 support HTTP, HTTPS without client certificates, and HTTPS with mutual TLS (mTLS). Private CAs and explicitly trusted self-signed server certificates are supported.
RMON Server processes check results and sends alerts. Set up RMON 1.4 and its database before starting RMON Server 7.0. When upgrading, complete the RMON database update before starting result servers.
Agents receive assignments from RMON and send results to one of the configured result servers. These are separate endpoints. Multiple result servers do not need to be registered as agent hosts in the RMON interface.
Configuration and backward-compatible upgrades
The server uses /etc/rmon/rmon-server.cfg. An explicitly set RMON_CONFIG_FILE takes priority. If neither is present, the server reads the existing /etc/rmon/rmon.cfg; old installations do not need to rename or create a config. The agent keeps /etc/rmon/rmon-agent.cfg, and database/log paths remain unchanged.
Only one configuration file is selected, not merged. When creating a dedicated server config, copy the existing [pgsql] or [mysql] settings unchanged, or set database_url. A malformed/unreadable new file causes an error, not a silent fallback. New settings belong to [rmon-server]; environment variables override file values. For secrets: ENV_FILE → ENV → config *_file → config value.
Set transport=http, transport=https, or transport=mtls. Without an explicit mode, no TLS files means HTTP, a server cert/key pair means HTTPS, and adding a client CA means mTLS. Existing env-only mTLS settings remain valid. New configuration is optional and is not automatically installed over existing setups.
Choose your version and database
Use the RMON images available for your installation: ghcr.io/roxy-wi/rmon-server:7.0 and ghcr.io/roxy-wi/rmon-agent:2.0. Confirm access to the selected version before starting. If the registry requires authentication, sign in on the deployment host. Pin the image digest to keep restarts on the same version.
Use PostgreSQL or MySQL for servers on different hosts. SQLite is supported on one host: mount its directory, including writable WAL/SHM files, and match the existing database owner's UID/GID. Do not share SQLite over NFS or make a production database world-writable.
Before migration, back up the database and native service configuration. Test the candidate on a database copy with RMON_SERVER_SCHEDULER_ENABLED=0. Stop the native result server before starting its production replacement. Keep its unit for rollback; do not restore an old database over newly received results.
Secrets and certificates
Create secrets/database_url, secrets/internal_api_token, and secrets/probe_token. The URL supports postgresql://, mysql://, and sqlite:///; URL-encode special characters in credentials. Use a dedicated account and database TLS for remote databases. Generate independent tokens:
umask 077
mkdir -p secrets
openssl rand -hex 32 > secrets/internal_api_token
openssl rand -hex 32 > secrets/probe_token
Write the database URL directly to its file and keep credentials out of shell history. Grant only administrators and the container account read access. Default image UID/GID is 10001:10001; Compose bind mounts retain host ownership.
Use a dedicated CA. Issue a separate clientAuth certificate/key for each agent, the probe, and the web interface. The server certificate requires serverAuth and SANs matching actual connection addresses, including IP SANs when using IP addresses without DNS. Transfer agent credentials through the existing SSH administration channel.
Keep the CA private key in a protected signing location, never on agents or in containers. The server's tls/server/ directory contains only ca.crt, server.crt, server.key, probe.crt, and probe.key. Restrict private-key access to the relevant service identity and administrators.
Start the container
Example compose.yaml for an existing external database. Replace the image with your tested release. For SQLite, also mount its writable directory and set the matching container UID/GID.
services:
server:
image: ghcr.io/roxy-wi/rmon-server:7.0
restart: unless-stopped
ports:
- "127.0.0.1:5100:5100"
environment:
RMON_DATABASE_URL_FILE: /run/secrets/database_url
RMON_INTERNAL_API_TOKEN_FILE: /run/secrets/internal_api_token
RMON_PROBE_TOKEN_FILE: /run/secrets/probe_token
RMON_SERVER_WORKERS: "1"
RMON_TLS_CERT_FILE: /run/tls/server.crt
RMON_TLS_KEY_FILE: /run/tls/server.key
RMON_TLS_CA_FILE: /run/tls/ca.crt
RMON_PROBE_SCHEME: https
RMON_PROBE_CA_FILE: /run/tls/ca.crt
RMON_PROBE_CLIENT_CERT_FILE: /run/tls/probe.crt
RMON_PROBE_CLIENT_KEY_FILE: /run/tls/probe.key
volumes:
- ./secrets:/run/secrets:ro
- ./tls/server:/run/tls:ro
read_only: true
tmpfs:
- /tmp:rw,noexec,nosuid,size=32m,mode=1777
cap_drop: [ALL]
security_opt:
- no-new-privileges:true
docker compose up -d
docker compose exec -T server python -m modules.common.probe live
docker compose exec -T server python -m modules.common.probe ready
The example publishes loopback only and configures mTLS. For remote agents, explicitly publish a private interface or configure a TLS-capable gateway. Account for Docker publishing in your firewall policy: published ports can bypass UFW. Do not expose HTTP mode to an untrusted network. HTTPS requires the server cert/key pair; mTLS additionally requires a client CA and a trusted client certificate on every connection. The minimum is TLS 1.2.
For config-only Docker deployments, mount the chosen config read-only at /etc/rmon/rmon-server.cfg, along with the files it references. Remove the example's environment entries only for settings you want to read from that config, because env takes priority. The file can also contain bind, workers, threads, scheduler_enabled, log_path, log_level, log_json, instance_id, tokens and probe options. Existing native unit command-line/env overrides retain their priority.
HTTPS with a self-signed certificate
Use a server certificate with SANs matching the actual IP/DNS name. To generate a new certificate for an IP (choose existing certificate locations and do not overwrite keys in use):
umask 077
openssl req -x509 -newkey rsa:3072 -sha256 -nodes -days 365 \
-keyout server.key -out server.crt -subj '/CN=RMON Server' \
-addext 'subjectAltName=IP:192.0.2.10,IP:127.0.0.1' \
-addext 'extendedKeyUsage=serverAuth'
Configure the server as follows, alongside its database and diagnostics settings:
[rmon-server]
transport = https
tls_cert_file = /etc/rmon/tls/server.crt
tls_key_file = /etc/rmon/tls/server.key
probe_ca_file = /etc/rmon/tls/server.crt
Copy only the public server.crt to agents. Set [master] scheme=https, tls_verify=true, and ca_file to that trusted certificate. Do not distribute the server key or disable verification. Unknown certificates, expired certificates and mismatched IP/DNS SANs are rejected. Trust the control endpoint's own certificate separately in its ca_file.
For self-signed mTLS, select transport=mtls, add tls_ca_file for the CA issuing client identities, and supply agent/probe client cert/key pairs. The probe's probe_ca_file still trusts the server certificate; it need not be the same CA used to trust clients. For a private CA deployment, clients trust that CA instead of each server leaf certificate.
Agent transport
Install and manage agents through RMON over SSH, as before. Certificate transport is an additional administrator configuration in /etc/rmon/rmon-agent.cfg, not a special local-agent deployment mode:
[master]
host = 192.0.2.10,192.0.2.11
port = 5100
scheme = https
tls_verify = true
ca_file = /etc/rmon/mtls/ca.crt
client_cert = /etc/rmon/mtls/agent.crt
client_key = /etc/rmon/mtls/agent.key
[control]
url = https://192.0.2.20:5444
ca_file = /etc/rmon/mtls/ca.crt
client_cert = /etc/rmon/mtls/agent.crt
client_key = /etc/rmon/mtls/agent.key
[master] identifies result receivers. The agent stops after one acknowledges the result; it does not broadcast to all servers. Undelivered results are retained locally for retry. [control] selects the RMON assignment endpoint, independently of result servers. Without it, legacy discovery remains. Client cert/key pairs require HTTPS; result transport also requires server verification. Redirects are not followed.
For certificate-protected assignment, configure a separate nginx TLS listener with ssl_client_certificate, ssl_verify_client on, and an exact /rmon/agent/hello proxy to RMON web. Return 404 on other paths. Close the legacy public HTTP/HTTPS assignment route after all agents migrate. Keep the browser UI on its normal TLS listener so users do not need agent certificates.
Start/stop/restart always use SSH, including for agents on the RMON host. The agent's read-only /health endpoint uses its Agent-UUID header and remains available when its scheduler administration API is disabled.
Diagnostics and multiple result servers
In addition to mTLS, all server diagnostics require a bearer token, even on loopback:
/internal/version: running version; internal API token only./internal/health: version, instance, uptime, DB readiness and alert-scheduler role; internal API token only./internal/health/live: responsive HTTP process; probe or internal token./internal/health/ready: database connectivity and required schema; probe or internal token.
Docker health checks use liveness. Check readiness separately before routing results. The probe infers HTTP/HTTPS from the server transport unless probe_scheme overrides it. The same python -m modules.common.probe live and ready commands can be used as Kubernetes exec probes with mounted credentials. A DB outage returns 503 for readiness while liveness remains successful. The probe token cannot read full health details or version.
Connect all result servers to the same database. If the server handling alerts becomes unavailable, another server takes over. Allow up to approximately 90 seconds for takeover; other servers continue to accept check results during this period. A notification may be repeated after a failure, so enable duplicate suppression in your notification provider when available.
To show a local container's version in RMON administration, configure the web service with RMON_SERVER_INTERNAL_URL and RMON_SERVER_INTERNAL_TOKEN_FILE. For a private CA/self-signed certificate, set RMON_SERVER_CA_FILE to the trusted CA/public certificate. Add RMON_SERVER_CLIENT_CERT_FILE and RMON_SERVER_CLIENT_KEY_FILE only for mTLS. Explicit HTTP URLs are supported on trusted networks; HTTPS verification remains enabled. Do not grant the web process access to the Docker socket. Update images through Docker, not the OS package updater.
Rotation and final verification
Check expiry with openssl x509 -in agent.crt -noout -enddate. Rotate before expiry and restart affected services. For CA rotation, distribute the trust bundle first, replace leaf certificates, verify traffic, then retire the old CA. Agent client certificates can be generated during installation or reconfiguration using the owning group's certificate settings. Receiver certificates and certificate renewal remain administrator-managed. Trusting a client certificate does not automatically bind its subject to an Agent-UUID or provide per-agent revocation; use a revocation-enforcing gateway or rotate the trust domain if an identity is compromised.
After switching, verify both probes, the current version in administration, several fresh check results, delivery of buffered results, and absence of container restart loops before removing rollback configuration. With mTLS, also verify that connections without a trusted client certificate are rejected.