Skip to content

Services: HTTP, TCP, DNS, ping, TLS, NTP, UDP, SSH, SMTP, IMAP, POP3, SQL, MQTT, WebSocket

This content is not available in your language yet.

Fifteen monitors watch services rather than equipment, Uptime Kuma style: a web page, a port, a DNS name, a host, a certificate, a time server, a mail relay or mailbox, a database, an MQTT broker, a WebSocket endpoint, a UDP port, an SSH server. Each service gets a history bar, a response time and an availability percentage on its monitor page.

The last five go further than opening a connection: they begin a real session in the service’s own protocol. That is the difference between “port 5432 is open” and “the database still accepts my account and answers a query”. NTP sits between the two: a single request and reply, in NTP’s own protocol, enough to read the server’s clock without a session.

Monitors > ⋯ > Import from Uptime Kuma, also on Monitors > Add a monitor > Import (administrators), reads the database of Uptime Kuma 1.x or 2.x, or the JSON backup of 1.x. Nothing is created before you have seen the preview: what will be created, and what is skipped with the reason. Tick the monitors you want, then import them in one click.

Uptime Kuma 2.x has no backup export any more, so export its database instead: stop the container (so the file is complete), then copy kuma.db out of the data folder and choose it in the dialog.

Terminal window
docker stop uptime-kuma
docker cp uptime-kuma:/app/data/kuma.db .
docker start uptime-kuma
  • The file is uploaded, read once in read-only mode from a temporary copy that is never attached to DumbMonit’s own database, and deleted straight away. It can be up to 512 MB (it holds the whole heartbeat history); only monitors, groups, tags, intervals and the number of notifications are read from it.
  • Uptime Kuma 2 installed on MariaDB is not supported: only the SQLite file kuma.db can be imported.
  • The JSON backup of 1.x (Settings > Backup > Export, at most 4 MB) still works, with the same preview.
Uptime KumaDumbMonit
HTTP(s), HTTP(s) - Keyword, HTTP(s) - Json QueryHTTP: accepted status codes, method, keyword (and its inverse), JSON path and expected value, redirects, timeout, ignore TLS errors
PingPing
TCP PortTCP, as host:port
DNSDNS: record type and resolver
PushHeartbeat, expected interval = the monitor’s interval. It gets a new push URL: update the job that calls it
GroupA folder (nested groups become Group/Subgroup)
TagsMonitor tags: name=value, or name=true for a tag without a value
PausedCreated disabled

The name and interval are kept (10 s minimum). Everything else is skipped and listed: Docker and the other types without an equivalent, and monitors in upside-down mode. An entry already monitored (same type and address) is skipped too, so the same file can be imported twice safely.

Not imported: notifications (set up your channels in Notifications; the preview tells you how many the file held), and credentials, custom headers and request bodies, which are never read into DumbMonit. If a monitored site needs a login or a header, add it on the monitor afterwards.

A service can answer and still be down: a 500, a missing keyword, an expired certificate. So these monitors write a point on every check, probe_success being 1 or 0, instead of going silent like a hardware device. That is what makes an availability percentage possible: avg_over_time(dumbmonit_probe_success[30d]).

SituationWhat happens
Invalid option or address, ICMP sockets not allowed (see Ping)Configuration error: nothing is written, the monitor page shows the error, no “down” alert.
Connection refused, timeout, TLS refused, 500, keyword absent, total packet loss, password refused, query failedprobe_success = 0: the outage is recorded, dated and counted.
All goodprobe_success = 1.

Every monitor has its own timeout (timeout_seconds, 5 s by default, 60 s at most), shorter than the server’s DUMBMONIT_PROBE_TIMEOUT_SECS: interrupted by the scheduler, it could not write its zero.

Built-in rules that apply to all fifteen: Service down (3 minutes), Service flapping (more than six state changes in thirty minutes), Slow service (more than 3 s for ten minutes, successful checks only: a failing check lasts its timeout and is Service down, not slowness). For every check that reads a certificate — http, tls, smtp, imap, pop3, mqtt, websocket: Certificate expiring soon (14 days) and Certificate expired.

A refused password is never an outage of the service: it is recorded as reason="auth", so the alert says what to fix.

All gauges, all prefixed dumbmonit_, all labelled probe="http|tcp|dns|ping|tls|smtp|postgres|mysql|mqtt|websocket|ntp|udp|ssh|imap|pop3|snmp_oid|radius|grpc" in addition to target, host and tag_*.

MetricMonitorsMeaning
probe_successall1 if the service answers correctly, 0 otherwise.
probe_duration_secondsallTotal duration of the check.
probe_failure_infoallPresence (1) with a reason label: dns, connect, timeout, tls, cert_expired, status, keyword, json, body, packet_loss, record, auth, protocol, query, payload, unsynchronized, clock_offset, host_key, threshold, not_found, bad_secret, unhealthy.
probe_http_status_codehttp, websocketStatus code obtained.
probe_http_first_byte_secondshttpTime to the response headers.
probe_http_phase_seconds{phase}httpTime of the measured request split into dns, connect, tls, processing and transfer; the five always sum to the request time (see Response time breakdown).
probe_http_content_byteshttpBody size.
probe_http_security_header{header}http0/1 per header label (https only): HSTS, nosniff, CSP, X-Frame-Options, frame-ancestors.
probe_connect_secondsall but dns, ping, ntp and udpConnection establishment (login included for databases).
probe_tls_handshake_secondstls, http, smtp, imap, pop3, mqtt, websocketTLS negotiation alone.
probe_tls_version_infotls, http, smtp, imap, pop3, mqtt, websocketPresence; version label.
probe_ssl_cert_expiry_daystls, http, smtp, imap, pop3, mqtt, websocketDays before expiry, negative if expired.
probe_ssl_cert_validtls, http, smtp, imap, pop3, mqtt, websocket1 if the chain leads to a known authority.
probe_ssl_cert_issuer_infotls, http, smtp, imap, pop3, mqtt, websocketPresence; issuer label.
probe_dns_lookup_secondsdnsResolution time.
probe_dns_answer_recordsdnsRecords of the requested type.
probe_dns_answer_fingerprintdnsWith “Alert when the answer changes”: a 32-bit fingerprint of the sorted answer. Its value means nothing; only its changes do.
probe_icmp_rtt_seconds, _min_seconds, _max_secondspingAverage, shortest and longest round trip.
probe_icmp_packet_loss_ratiopingLoss between 0 and 1.
probe_icmp_packets_sent, probe_icmp_packets_receivedpingEchoes sent and received.
probe_smtp_greeting_secondssmtpTime to the 220 banner.
probe_smtp_ehlo_secondssmtpRound trip of the EHLO command.
probe_smtp_capabilitiessmtpExtensions advertised.
probe_smtp_authenticatedsmtp1 when AUTH succeeded.
probe_sql_query_secondspostgres, mysqlQuery execution alone.
probe_sql_rowspostgres, mysqlRows returned.
probe_sql_valuepostgres, mysqlFirst column of the first row, when it is a number.
probe_mqtt_connack_secondsmqttTime to the CONNACK.
probe_mqtt_suback_secondsmqttTime to the SUBACK.
probe_mqtt_message_bytesmqttSize of the retained message.
probe_mqtt_message_valuemqttIts content, when it is a number.
probe_ws_handshake_secondswebsocketOpening handshake.
probe_ntp_offset_secondsntpOffset between the local clock and the server.
probe_ntp_delay_secondsntpNetwork round-trip delay.
probe_ntp_stratumntpDistance to a reference clock (16: not synchronized).
probe_ntp_leap_indicatorntp0 to 3 (leap second warning, 3 = clock unsynchronized).
probe_ntp_root_delay_secondsntpCumulated delay up to the root of the hierarchy.
probe_ntp_root_dispersion_secondsntpCumulated dispersion up to the root.
probe_ntp_reference_infontpPresence; reference_id label.
probe_udp_response_seconds, probe_udp_response_bytesudpTime to the reply, and its size (only when a reply arrives).
probe_ssh_banner_secondssshTime to the SSH-2.0-... banner.
probe_ssh_protocol_info{version}sshPresence; protocol version in the version label.
probe_ssh_software_info{software}sshPresence; server software in the software label (OpenSSH_9.6p1).
probe_ssh_kex_secondssshDuration of the start of the key exchange (only when the host key is read).
probe_ssh_host_key_fingerprintsshWith an expected host key or “Alert when the host key changes”: a 32-bit fingerprint of the host key. Its value means nothing; only its changes do.
probe_ssh_host_key_info{fingerprint}sshPresence; the SHA256:... fingerprint, as ssh-keygen -lf prints it.
probe_ssh_host_key_matchssh1 if the host key is the expected one, 0 otherwise. Only with an expected host key.
probe_imap_greeting_seconds, probe_imap_login_secondsimapTime to the * OK banner, and round trip of LOGIN.
probe_imap_authenticatedimap1 when LOGIN succeeded.
probe_pop3_greeting_seconds, probe_pop3_login_secondspop3Time to the +OK banner, and duration of USER + PASS.
probe_pop3_authenticatedpop31 when the login succeeded.
probe_ws_message_byteswebsocketSize of the first frame received. Only present when the check sends a message or expects a reply (send / expect options).
probe_snmp_query_secondssnmp_oidRound trip of the read.
probe_snmp_valuesnmp_oidValue of the object, when it is a number.
probe_radius_response_secondsradiusRound trip of the Access-Request.
probe_radius_response_coderadiusCode of the reply: 2 accepted, 3 rejected, 11 challenge.
probe_grpc_check_secondsgrpcDuration of the Health/Check call.
probe_grpc_serving_statusgrpcServingStatus returned: 1 SERVING, 2 NOT_SERVING, 3 SERVICE_UNKNOWN.
probe_grpc_status_codegrpcgrpc-status code of the reply (0: OK).

A monitor can be probed from several places at once, so that a problem on one network is not mistaken for an outage. In the monitor’s form, under “More options”, turn on Probe from several locations and tick the locations: This server and any relay agent. At least two locations are needed. It works for HTTP, TCP, DNS, ping, TLS, SMTP, PostgreSQL, MySQL, MQTT, WebSocket and NTP monitors, and cannot be combined with “Reached through” (a monitor is probed either by one relay, or by several locations).

Every location runs the probe on the usual interval. The result is a decision:

  • Down when at least N of the M counted locations fail. N is the quorum: by default a majority of the locations (3 locations: 2; 2 locations: both), or any number from 1 to the number of locations.
  • Degraded when some locations fail but fewer than the quorum. The monitor page shows “Degraded at one location” and which place fails, but no service_down alert is raised and status pages stay up.
  • Up when no counted location fails.

Confirmation. When a monitor goes from up to degraded or down, the server immediately probes again from every location and only publishes the decision of that confirmation round. A blip seen once never alerts.

Silent locations are left out. A location that does not answer in time (a relay that is offline), whose agent has not enabled relay mode, that has too many probes queued, or that cannot run this probe is excluded from the count, shown as “Not counted” with the reason, and the quorum adapts to the locations that remain (it never exceeds their number). A relay agent holds at most 32 multisite probes at a time; beyond that the location is excluded as busy. A relay agent that is too old to know a monitor type answers with an error: that location is excluded and flagged, with no need to update the agent.

The monitor page shows a Probe locations card: the decision, how many locations fail against the quorum, and per location its state, response time, last check and the reason it is left out. Locations placed on the world map also show on a small map.

Per location: dumbmonit_probe_location_success{location} and dumbmonit_probe_location_duration_seconds{location}, where location is server or agent-<id>. The usual dumbmonit_probe_success carries the quorum decision, so alerts, uptime figures and status pages follow it. In addition, dumbmonit_probe_degraded is 1 while only a minority of locations fail, and dumbmonit_probe_locations_failing and dumbmonit_probe_locations_counted give the figures behind the decision. See Metrics.

A degraded monitor never raises service_down. To hear about it anyway, create a custom alert rule (Alerts, New rule) with severity info, the query dumbmonit_probe_degraded == bool 1, the operator > and the threshold 0, for 5 minutes.

Website or web API (HTTP) — checks that a page or an API answers, with the right status code, the right content, and a valid certificate. Examples: a website, an application health page, a REST API, a self-hosted service interface.

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
443TCPWeb page or API over HTTPS (default port)
80TCPOnly with an http:// address (default port)
  1. In the address, paste the full URL of the page to monitor.

  2. Prefer a light page such as “/health” or “/status” over the home page.

  3. If the page needs a login, choose a credential: username and password (basic) or a token (Bearer).

  4. Optionally require a keyword in the page or a value in a JSON response, in the options.

Required permissions

  • Read access to the monitored URL: Only if the page requires a login

Without “http://” or “https://”, HTTPS is assumed. By default, any status code between 200 and 299 is fine. Over HTTPS, the certificate is read automatically: you will be warned before it expires. A password or token written in the options is copied in clear text on every measurement.

Credentials: none, username / password (basic authentication) or API token (Authorization: Bearer).

KeyLabelDefaultHelp
methodHTTP methodGETGET fits almost every case. HEAD avoids downloading the page when only the status code matters. Choices: GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS.
accepted_statusAccepted status codes200-299Codes or ranges considered normal, separated by commas. Any other code counts as down. Example: 200-299,301,404.
keywordExpected keyword(empty)Text that must appear in the page. If it is missing, the service is reported down even though the page answers.
keyword_absentKeyword must be absentfalseInverts the check: the presence of the keyword signals a failure. Useful for an error page that answers 200.
keyword_case_sensitiveMatch keyword casefalseBy default, upper and lower case are treated the same.
json_pathJSON path to check(empty)For a JSON response: path of the value to check. Fill it in together with the expected value, never one without the other. Example: $.status.
json_expectExpected JSON value(empty)Value the JSON path above must have, for example “ok” or “true”.
headersExtra headers(empty)One or more “Name: value” headers, separated by ”|”. Do not put secrets here: options are visible in the charts.
bodyRequest body(empty)Content sent with the request, for methods that expect one (POST, PUT…).
follow_redirectsFollow redirectstrueDisable to monitor the redirect itself, for example a 301 to HTTPS.
max_redirectsMaximum redirects followed10Between 1 and 20. No effect if redirects are not followed.
insecure_tlsAccept an unverifiable certificatefalseThe check no longer fails on a self-signed certificate or one issued by a private authority.
allow_private_targetsAllow loopback and link-local targetsfalseBy default the check refuses addresses only the DumbMonit host itself can reach (127.0.0.1, ::1, 169.254.x.x). Enable this to monitor a service running on the DumbMonit host. Private LAN addresses (10.x, 192.168.x) are always allowed.
check_certificateRead the certificatetrueOver HTTPS, also records the certificate expiry date so you can be warned before it expires.
max_body_bytesMaximum bytes read524288Beyond this, the rest of the page is not downloaded. The keyword and JSON path are only searched in this part.
user_agentAnnounced identity (User-Agent)DumbMonit/<version>Name the check gives to the server. Change it if the server filters robots.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.

On the monitor page, the Time breakdown panel shows where each check spends its time, as stacked areas over the selected range, with a proportional bar and a legend (name, time, share) for the last check. The same numbers are in the metric probe_http_phase_seconds, one series per phase label:

PhaseWhat it covers
dnsResolving the host name. Zero for an IP address.
connectOpening the TCP connection.
tlsTLS handshake (HTTPS only).
processingServer wait: from the request sent to the response headers.
transferReading the response body. Zero unless a keyword or JSON path needs the body.

The five series always exist and always add up to the time from sending the request to the end of the body read, for the last request of the check (the final hop when redirects are followed). Each check opens a fresh connection, so dns, connect and tls are measured on every check rather than staying at zero on a reused connection.

How to read the graph: a tall dns band points at the resolver, connect at the network path or a firewall, tls at the certificate chain or handshake cost, and processing at the application itself. The TCP and TLS split uses the handshake time measured by the certificate read just before the request, capped to the connection time observed; with Read the certificate off, the TLS handshake stays inside connect. Failed checks publish no phases, so the graph shows a gap.

Network port (TCP) — checks that a port accepts connections: SSH, database, file share, game server, network printer.

The port is the one you write in the address or in the “Port” option; there is no default. From the DumbMonit server (or its relay agent) to the device, open that TCP port.

  1. In the address, write the host and the port separated by a colon: “nas.home.lan:22”, or “[fd00::1]:445” for IPv6.

  2. Or leave the port out of the address and fill in the “Port” option.

Only the opening of the connection is tested: no data is sent to the service, so it has no effect on it.

KeyLabelDefaultHelp
portPort(empty)Port to open, if the address does not already give it as “host:port”. One of the two is required.
allow_private_targetsAllow loopback and link-local targetsfalseBy default the check refuses addresses only the DumbMonit host itself can reach (127.0.0.1, ::1, 169.254.x.x). Enable this to monitor a service running on the DumbMonit host. Private LAN addresses (10.x, 192.168.x) are always allowed.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.

Domain name (DNS) — checks that a name resolves, and that it points to the right address. Examples: your domain name, an internal name served by your Pi-hole or AdGuard, an MX record.

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
53UDPDNS query (default port)
53TCPDNS query too large for UDP (default port)
  1. In the address, write the name to resolve, without “http://”: “www.example.com”.

  2. Pick another record type in the options if you do not want an IPv4 address (A record).

  3. To monitor your own DNS server, enter its IP address in “DNS server to query”.

  4. To detect hijacking, list the addresses the answer must contain in “Expected values”.

By default, the check asks the system resolver. If the server you query stops answering, the check fails.

KeyLabelDefaultHelp
record_typeRecord typeAA for an IPv4 address, AAAA for IPv6, MX for mail, CNAME for an alias… Choices: A, AAAA, CNAME, MX, TXT, NS, SOA, SRV, PTR, CAA.
resolverDNS server to query(empty)IP address of a resolver, port optional. Empty: the system resolver. Handy to check your own DNS server. Example: 1.1.1.1 or 10.0.0.1:5353.
expectExpected values(empty)Values that must all appear in the answer, separated by commas. Empty: only the resolution is checked.
expect_modeComparisoncontainscontains: each expected value must appear somewhere in the answer. exact: the answer must hold those values and nothing else.
forbidForbidden values(empty)Values that must never appear in the answer, separated by commas. Checked before the expected ones.
alert_on_changeAlert when the answer changesfalseRecords a fingerprint of the sorted answer and alerts whenever it changes, without having to write the expected values.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.

expect alone catches the record that disappeared. It does not catch the record that was added: a hijacked zone often keeps the legitimate A and puts a second one beside it, and a client then reaches either one at random.

  • expect_mode = exact refuses any value the expectation does not cover. Order does not matter — DNS does not keep one.
  • forbid names values that must never come back: the address of a former host, an expired validation TXT, a mail server you decommissioned. It is checked first, so it wins over expect.

Both compare case-insensitively, ignore the trailing dot of a name and the quotes around a TXT, and treat an expected value as found when it appears inside a record — so an MX matches on mail.example.com without you having to copy its priority.

Writing the expected values is not always practical: a name served by a CDN, records someone else manages, or simply a zone you want to hear about whenever it moves. Tick Alert when the answer changes: every check then records a fingerprint of the answer, and the built-in rule DNS answer changed fires when it differs from the one before. The alert resolves by itself an hour later; the new answer is the reference from then on.

The fingerprint covers the values of the answer, sorted and without duplicates, with the CNAME chain included: a round-robin that returns the same addresses in another order does not change it, nor does a TTL. A name whose answer changes on every query (a large pool such as pool.ntp.org, or geographic DNS that answers differently from one resolver to the next) would alert all the time: leave the option off for those, or query one fixed resolver.

Reachable host (ping) — sends a few ICMP echoes and measures response time and packet loss. Examples: home router or gateway, Wi-Fi access point, printer, machine without agent or SNMP, remote host.

Ping uses ICMP echo, which has no port: allow ICMP echo request and reply from the DumbMonit server (or its relay agent) to the device.

  1. In the address, write the host name or IP address: “192.168.1.1” or “router.home.lan”.

  2. Lower “Tolerated loss” in the options to be warned before the loss is total.

On each poll, the check sends four echoes and measures the response time and the share of lost packets. By default, only a total loss counts as down; partial loss stays visible in the charts. Some devices ignore pings on purpose.

services:
dumbmonit:
sysctls:
net.ipv4.ping_group_range: "0 2147483647"

Outside Docker, sysctl -w net.ipv4.ping_group_range="0 2147483647" on the host does the same, and a raw socket (NET_RAW, root) works too.

KeyLabelDefaultHelp
countNumber of echoes4Packets sent on each poll, from 1 to 20.
packet_timeout_msWait per packet (ms)1000Time allowed for each reply, from 50 to 10,000 ms.
interval_msGap between two echoes (ms)100Pause between two echoes, from 0 to 5,000 ms.
payload_bytesPayload size (bytes)56Data carried by each echo, from 0 to 1,400 bytes.
ip_versionIP versionauto“auto” takes the first resolved address; force 4 or 6 if the host has both and one does not answer. Choices: auto, 4, 6.
loss_threshold_percentTolerated loss (%)100Above this percentage of lost packets, the host is reported down. 100: only a total loss counts, partial loss stays visible in the charts.
timeout_secondsTimeout (seconds)5Total budget for the poll, from 1 to 60. Refused if it does not cover “number of echoes × wait per packet”.

TLS certificate — checks that a certificate is valid and warns before it expires, on any encrypted port. Examples: mail server (IMAPS, SMTPS), reverse proxy, LDAPS directory, MQTT broker, administration interface.

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
443TCPTLS handshake (default port, the one in the address)
  1. In the address, write the host and the port of the encrypted service: “mail.example.com:993” (443 if omitted).

  2. If you reach the service by its IP address, enter the certificate’s name in “Server name (SNI)”.

  3. For a certificate from your own authority, tick “Accept an unverifiable certificate”.

The check opens an encrypted connection, reads the presented certificate and closes right away: no data is exchanged with the application. It records the number of days before expiry, the issuer and the TLS version. The bundled alert rules warn at fourteen days, then at expiry.

The handshake completes even when the certificate is refused: that is what allows reading the expiry date of a certificate that has already expired. The verdict of the verification is in probe_ssl_cert_valid.

KeyLabelDefaultHelp
server_nameServer name (SNI)(empty)Domain name announced to the server and checked in the certificate. Set it when the address is an IP behind a reverse proxy.
insecure_tlsAccept an unverifiable certificatefalseAn unverifiable chain no longer counts as a failure: the expiry date is still recorded.
allow_private_targetsAllow loopback and link-local targetsfalseBy default the check refuses addresses only the DumbMonit host itself can reach (127.0.0.1, ::1, 169.254.x.x). Enable this to monitor a service running on the DumbMonit host. Private LAN addresses (10.x, 192.168.x) are always allowed.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
587TCPSubmission with STARTTLS (default)
465TCPOnly with TLS encryption (SMTPS)
25TCPOnly with no encryption (relay on port 25)

Mail relay (SMTP) — opens a real session on a mail server: greeting, EHLO, STARTTLS, and the login if you give one. Examples: your provider’s SMTP relay, a local Postfix or msmtp, Proxmox Mail Gateway, the submission port of a mail server.

  1. In DumbMonit, enter the mail server, for example smtp.example.com:2525 (the usual port for the encryption by default).

  2. Pick the encryption: STARTTLS for port 587, TLS for port 465, None for a relay on your own network on port 25.

  3. Optional: fill in an account, to check that the relay still accepts it (a refused password is not reported as an outage).

  4. Optional: name an Expected extension, such as STARTTLS, to be warned when the relay stops advertising it.

  • A mail account that may log in (AUTH): Only if you fill in a credential

Nothing is ever sent: the check stops after the greeting, the extensions and the optional login, then hangs up. No message enters the queue. A relay that stops advertising STARTTLS is a relay that would send your mail in clear text. A relay that accepts everything and queues it forever answers perfectly here.

Credentials: none, or a username and password sent with AUTH PLAIN (or AUTH LOGIN when the server offers only that). They are sent after the connection is encrypted and after the certificate has been judged: a relay whose chain cannot be verified never receives them.

Over TLS or STARTTLS, the certificate is read like the TLS check reads it — expiry, issuer, protocol version — so a mail relay is also a certificate you are warned about.

That mail actually leaves. A relay that accepts every session and then defers everything answers perfectly here; watch its queues instead (see the Proxmox Mail Gateway page). It also never sends a message, so it says nothing about recipient filtering, SPF or DKIM.

KeyLabelDefaultHelp
securityEncryptionstarttlsSTARTTLS starts in clear text and upgrades (port 587), TLS encrypts from the first byte (port 465), None never encrypts (port 25) and only suits a relay on your own network.
portPort(empty)Used if the address does not give one. Empty: 587 with STARTTLS, 465 with TLS, 25 without encryption.
helo_nameName announced (EHLO)dumbmonitName the check gives when it introduces itself. A strict relay refuses a name it cannot resolve.
expect_capabilityExpected extension(empty)Extension the server must advertise in its EHLO answer, for example STARTTLS or AUTH. Empty: no expectation.
server_nameServer name (SNI)(the host)Domain name announced to the server and checked in the certificate. Set it when the address is an IP.
insecure_tlsAccept an unverifiable certificatefalseAn unverifiable chain no longer counts as a failure: the expiry date is still recorded.
allow_private_targetsAllow loopback and link-local targetsfalseSee “Addresses the checks refuse” below.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.
reasonWhat happened
connectThe port is closed or the relay is unreachable.
protocolSomething answered, but not SMTP — or it refused the connection, EHLO, or STARTTLS it had advertised.
authThe account was refused (535, 530, 534). The relay is fine; the credential is not.
payloadThe extension named in “Expected extension” is not advertised.
tls, cert_expiredSame meaning as for the TLS check.

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
5432TCPPostgreSQL (default port)

PostgreSQL database — connects, authenticates and runs one query: the signal for a database that is up but no longer answering. Examples: the database behind Nextcloud or Immich, a Home Assistant recorder, an application database, a TimescaleDB instance.

  1. In psql, create a role that may only log in.

    CREATE ROLE dumbmonit LOGIN PASSWORD 'a-long-password';
  2. Allow it to connect from the DumbMonit host with this line in pg_hba.conf (adjust the address), then reload PostgreSQL.

    host all dumbmonit 10.0.0.5/32 scram-sha-256
  3. In DumbMonit, enter the server, for example db.home.lan:5433 (port 5432 by default), then the role’s user and password.

  4. Optional: replace the default query SELECT 1 with one that returns a single number, to chart it.

  • LOGIN (role attribute): Connect only, no other privilege

The default query is SELECT 1, which reads no table: nothing else has to be granted. Connection time and query time are recorded separately. A query of your own that reads a table needs SELECT on that table.

Credentials: a username and password, required. A database is never monitored anonymously, so the form offers nothing else.

Replication lag, a lock that drags on, a table that keeps growing. All of those live in the engine’s own administration views — write the query yourself, and the number it returns becomes probe_sql_value, a chart you can alert on.

KeyLabelDefaultHelp
portPort5432Used if the address does not give one.
databaseDatabasepostgresDatabase opened on connection. The monitoring account must be allowed to connect to it.
queryQuerySELECT 1Run on every check. The default reads no table, so the account needs no privilege beyond connecting. A query returning one number turns it into a chart.
expectExpected value(empty)Value the first column of the first row must hold. Empty: only the query succeeding is checked.
sslmodeEncryptionpreferprefer encrypts when the server offers it, require refuses to connect without it, verify-full also checks the certificate and the name, disable never encrypts.
allow_private_targetsAllow loopback and link-local targetsfalseSee “Addresses the checks refuse” below.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
3306TCPMySQL or MariaDB (default port)

MySQL or MariaDB database — connects, authenticates and runs one query: the signal for a database that is up but no longer answering. Examples: the database behind a WordPress, a Nextcloud or a Kimai, an application database, a MariaDB in Docker.

  1. In the mysql client, create an account with no privilege (adjust the host part to the DumbMonit machine).

    CREATE USER 'dumbmonit'@'%' IDENTIFIED BY 'a-long-password';
  2. In DumbMonit, enter the server, for example db.home.lan:3307 (port 3306 by default), then the account’s user and password.

  3. Optional: replace the default query SELECT 1 with one that returns a single number, to chart it.

  • USAGE (no privilege): Connect and run SELECT 1, nothing more

The default query is SELECT 1, which reads no table: nothing else has to be granted. Connection time and query time are recorded separately. A host pattern of localhost would only accept connections made on the server itself. A query of your own that reads a table needs SELECT on that table.

KeyLabelDefaultHelp
portPort3306Used if the address does not give one.
databaseDatabase(empty)Database opened on connection. Empty: none, which is enough for the default query.
queryQuerySELECT 1Run on every check. The default reads no table, so the account needs no privilege beyond connecting. A query returning one number turns it into a chart.
expectExpected value(empty)Value the first column of the first row must hold. Empty: only the query succeeding is checked.
sslmodeEncryptionpreferprefer encrypts when the server offers it, require refuses to connect without it, verify-full also checks the certificate and the name, disable never encrypts.
allow_private_targetsAllow loopback and link-local targetsfalseSee “Addresses the checks refuse” below.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.
reasonWhat happened
connectThe port is closed, the server is unreachable, or it refused the connection for a reason other than the account (starting up, too many connections).
authThe account was refused: wrong password, no pg_hba.conf line, host pattern that does not cover the DumbMonit machine.
queryConnected and authenticated, but the query failed: missing table, database in read-only, syntax error.
payloadThe query worked but returned something other than the expected value.
timeoutThe connection or the query did not finish in time — the “up but slow” case.

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
1883TCPMQTT (default port)
8883TCPOnly with the Encrypted connection option (MQTT over TLS, default)

MQTT broker — connects to the broker, subscribes to a topic, and can wait for a retained message. Examples: Mosquitto, the broker behind Home Assistant, Zigbee2MQTT, ESPHome sensors.

  1. In DumbMonit, enter the broker, for example broker.home.lan:1884 (port 1883 by default).

  2. Tick Encrypted connection for a broker listening on 8883.

  3. If the broker requires an account, fill in its user and password.

  4. Optional: name a topic, to check that the account may still subscribe to it.

  5. Optional: tick Expect a retained message only for a topic that carries one, typically an availability topic.

  • Subscribe (read) on the topic you name: Only if you name a topic

Connecting is already worth monitoring: a broker that refuses your account, or that has stopped answering, is the reason the whole house went quiet. When you name a topic, a broker that refuses the subscription tells you the account lost its access rights. A topic published to now and then looks silent to a client that has just connected, so expect a retained message only for a topic that carries one. A value frozen three weeks ago still counts as present.

That a given sensor stopped emitting. The retained message the check reads is whatever the broker kept, possibly three weeks old — MQTT does not timestamp it. For freshness, watch the automation that consumes it, or use a heartbeat.

KeyLabelDefaultHelp
tlsEncrypted connectionfalseEncrypts the session from the first byte, as brokers do on port 8883.
portPort(empty)Used if the address does not give one. Empty: 1883 in clear text, 8883 encrypted.
topicTopic(empty)Topic the check subscribes to. Empty: it only connects, which already tells you the broker is alive and accepts your account.
expect_messageExpect a retained messagefalseA message must arrive on that topic before the timeout. Only retained messages arrive right away: a topic that is merely published to from time to time will look silent.
expectExpected content(empty)Text that message must contain. Filling it in implies expecting a message.
client_idClient identifier(derived)Name announced to the broker. The default derives from the monitor, so two checks never disconnect each other.
server_nameServer name (SNI)(the host)Domain name announced to the broker and checked in the certificate. Set it when the address is an IP.
insecure_tlsAccept an unverifiable certificatefalseAn unverifiable chain no longer counts as a failure: the expiry date is still recorded.
allow_private_targetsAllow loopback and link-local targetsfalseSee “Addresses the checks refuse” below.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.
reasonWhat happened
connectThe port is closed or the broker is unreachable.
authThe CONNACK refused the account, or the broker refused the subscription — an access-control list no longer covers this topic.
protocolSomething answered but does not speak MQTT 3.1.1, or the broker rejected the client identifier.
payloadNo retained message arrived on the topic, or its content does not contain the expected text.

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
443TCPWSS (default)
80TCPOnly with a ws:// address

WebSocket endpoint — runs the upgrade handshake, and can send a frame and wait for one: a different failure from a plain HTTP page. Examples: the Home Assistant API, a live dashboard, a log stream, an endpoint behind a reverse proxy.

  1. In DumbMonit, paste the full endpoint, for example wss://home.example.com/api/websocket (wss is assumed without a scheme).

  2. Optional: fill in Expected content with a fragment of the first frame the server sends by itself.

  3. Optional: if the endpoint says nothing until spoken to, put a message in Frame to send, and what the answer must contain in Expected content.

The check runs the whole opening handshake and verifies the answer the server computes from the key it was sent: a reverse proxy that has lost the Upgrade header is caught here, where an HTTP check would still see a healthy 200. A status other than 101 is reported with its code, so a 401 from an expired token is not mistaken for an outage. For the first frame, think of the greeting of the Home Assistant API.

Credentials: none, a username and password (sent as HTTP basic authentication in the opening request) or a token (sent as Authorization: Bearer).

KeyLabelDefaultHelp
pathPath(from the address)Path of the opening request. Taken from the address when it carries one.
portPort(empty)Used if the address does not give one. Empty: 443 for wss, 80 for ws.
sendFrame to send(empty)Text frame sent once the connection is open. Empty: nothing is sent.
expectExpected content(empty)Text a received frame must contain. Empty and with nothing to send, only the opening handshake is checked.
subprotocolSubprotocol(empty)Value of Sec-WebSocket-Protocol. The check fails if the server picks a different one.
originOrigin(empty)Value of the Origin header, which some servers require before upgrading.
server_nameServer name (SNI)(the host)Domain name announced to the server and checked in the certificate. Set it when the address is an IP.
insecure_tlsAccept an unverifiable certificatefalseAn unverifiable chain no longer counts as a failure: the expiry date is still recorded.
allow_private_targetsAllow loopback and link-local targetsfalseSee “Addresses the checks refuse” below.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.
reasonWhat happened
connectThe port is closed or the host is unreachable.
statusThe endpoint answered something other than 101; probe_http_status_code carries the code.
protocolIt answered 101 but its Sec-WebSocket-Accept does not match the key sent, it picked another subprotocol, or it closed the connection at once.
payloadNo frame arrived, or it does not contain the expected text.

NTP time server — sends a single SNTP request and reads the reply: offset, round-trip delay, stratum and leap indicator. Examples: a router or NAS acting as a local time server, an internal NTP server (chrony, ntpd), a public pool server used as a reference.

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
123UDPNTP request (default port)
  1. In the address, write the server’s name or IP address: “pool.ntp.org” or “192.168.1.1”.

  2. Lower “Tolerated offset” in the options to be warned earlier than 100 ms.

UDP port 123 is used unless the “Port” option says otherwise. The check sends a single SNTP request and records the offset, the round-trip delay, the stratum and the leap indicator. A server at stratum 16, or whose leap indicator reads “unsynchronized”, is reported down whatever the offset.

Credentials: none.

KeyLabelDefaultHelp
portPort123UDP port of the NTP server.
offset_threshold_msTolerated offset (ms)100Above this clock offset, the server is reported down. An unsynchronized server (stratum 16) always fails, whatever this value.
allow_private_targetsAllow loopback and link-local targetsfalseSee “Addresses the checks refuse” below.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.
reasonWhat happened
connectThe UDP socket could not be opened, or the reply came from an unexpected address.
timeoutNo reply arrived within the timeout.
protocolThe reply was not a valid NTP packet, or did not come from a server (wrong mode).
unsynchronizedThe server answered stratum 16 or 0 (a “kiss-o’-death”, which also names the reason in the log), or its leap indicator reads “unsynchronized”.
clock_offsetThe measured offset exceeds “Tolerated offset”.

UDP service — sends one datagram to a UDP port and checks the reply, or that nobody refuses it. Examples: a game or VoIP server, a syslog or SNMP listener, a WireGuard endpoint, a custom service that answers a ping message.

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
161UDPThe service’s UDP port, as written in the address (161 is only an example)
  1. In the address, write the host and the UDP port: “192.168.1.20:5060”. The port is required.

  2. To check that the service really answers, fill in “Datagram to send” and “Expected reply”.

  3. Without an expected reply, the check only fails when the host answers that the port is closed.

There is no default port. With an expected reply, the check waits for a datagram back for the whole timeout and looks for the text in it; without one, it waits about a second and a half for the host to answer with an ICMP “port unreachable” (reported as connect). Text and hexadecimal datagrams are supported; in text, \n, \r, \t, \0, \\ and \xNN are read as escapes. The reply is searched as plain text: there is no regular expression form.

Credentials: none.

KeyLabelDefaultHelp
portPort(empty)Used if the address does not give one. There is no default: UDP has no standard port to fall back on.
payloadDatagram to send(empty)Sent as one datagram, 1400 bytes at most. In text, \n \r \t \0 \ and \xNN are read as escapes. Empty: an empty datagram.
payload_encodingDatagram encodingtextText sends the characters as typed, Hex reads pairs of hexadecimal digits (spaces allowed).
expect_responseExpected reply(empty)Text the reply must contain. Empty: the check succeeds unless the host answers that the port is closed, and silence counts as success.
allow_private_targetsAllow loopback and link-local targetsfalseSee “Addresses the checks refuse” below.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.
reasonWhat happened
dnsThe name does not resolve.
connectThe host answered that the port is closed (ICMP), or the socket could not be opened.
timeoutAn expected reply did not arrive within the timeout.
payloadA reply arrived but does not contain the expected text.

SSH server — reads the SSH banner and, if you ask, checks that the host key is still the one you know. Examples: a Linux server or a Raspberry Pi, a NAS or a hypervisor with SSH enabled, a bastion host, a Git server over SSH.

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
22TCPSSH (default port, the one in the address)
  1. In the address, write the host name or IP address, with the port if it is not 22: “server.home.lan:2222”.

  2. To be warned when the server’s identity changes, read its fingerprint with ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub.

  3. Paste that fingerprint (SHA256:…) in “Expected host key”, or tick “Alert when the host key changes” to record it without choosing one.

The check always reads the banner (SSH-2.0-OpenSSH_9.6p1 ...): the protocol version and the server software are recorded as labels. When an expected host key is set, or “Alert when the host key changes” is ticked, it also starts the key exchange (curve25519-sha256) far enough for the server to show its public host key, computes its SHA-256 fingerprint and hangs up. No credential is ever sent.

A server holding several host keys shows the first it has among ssh-ed25519, ecdsa-sha2-nistp256, rsa-sha2-512 and rsa-sha2-256. The fingerprint you expect must be the one of that key: use “Host key type” to pick the family when you read it from another file than the ed25519 one.

Credentials: none.

A host key that changes without you having reinstalled the machine is worth a look: a rebuilt server restored without its keys, or something answering in its place. With an expected host key, the check fails with reason="host_key" and the Service down rule fires after three minutes. Without one, tick “Alert when the host key changes” and create a rule on the fingerprint, in Alerts > Rules:

changes_prometheus(dumbmonit_probe_ssh_host_key_fingerprint[1h]) > 0

It fires when the fingerprint differs from the one before and resolves by itself an hour later, like the built-in DNS answer changed rule. The readable fingerprint is in probe_ssh_host_key_info.

KeyLabelDefaultHelp
portPort22Used if the address does not give one.
expected_host_keyExpected host key(empty)SHA256 fingerprint of the server’s host key, as printed by ssh-keygen -lf. If the key differs, the server is reported down with the reason host_key. Empty: the key is not checked.
alert_on_changeAlert when the host key changesfalseRecords a fingerprint of the host key on every check, so that a rule can fire when it changes. Implied by an expected host key.
host_key_typeHost key typeautoA server may hold several host keys. Auto reads the first one it offers in this order: ed25519, ecdsa, rsa. Pick the family of the fingerprint you expect.
allow_private_targetsAllow loopback and link-local targetsfalseSee “Addresses the checks refuse” below.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.
reasonWhat happened
dns, connect, timeoutThe name does not resolve, the port is closed, or the server did not answer in time.
protocolSomething answered, but not SSH 2.0 — or the server offers no curve25519-sha256 or none of the host key types asked for, or it disconnected during the key exchange.
host_keyThe host key does not match “Expected host key”. The log names the key type and both fingerprints.

Mailbox (IMAP) — an IMAP server greets, offers TLS and accepts a login, like a real mail client. Examples: Dovecot, your provider’s IMAP server, a mailbox behind Mailcow or Mailu, Proxmox Mail Gateway’s mail host.

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
993TCPIMAP over TLS (default)
143TCPOnly with STARTTLS or no encryption
  1. In DumbMonit, enter the mail server, for example imap.example.com:1993 (port 993 with the default encryption).

  2. Pick the encryption: TLS for port 993, STARTTLS for port 143, None for a server on your own network.

  3. Optional: fill in a mailbox account, to check that the server still accepts logins (a refused password is not reported as an outage).

  • A mailbox account that may log in: Only if you fill in a credential

The check reads the * OK greeting, upgrades the connection if asked (STARTTLS), sends LOGIN if the target has a credential, then LOGOUT. It never selects a mailbox nor reads a message.

Credentials: none, or a username and password sent with LOGIN. They are sent after the connection is encrypted and after the certificate has been judged: a server whose chain cannot be verified never receives them. The only exception is the encryption “None”, which you must choose explicitly and which sends them in clear text.

Over TLS or STARTTLS, the certificate is read like the TLS check reads it, so a mailbox is also a certificate you are warned about.

KeyLabelDefaultHelp
securityEncryptiontlsTLS encrypts from the first byte (port 993), STARTTLS starts in clear text and upgrades (port 143), None never encrypts (port 143) and sends the password in clear text: only for your own network.
portPort(empty)Used if the address does not give one. Empty: 993 with TLS, 143 with STARTTLS or without encryption.
server_nameServer name (SNI)(the host)Domain name announced to the server and checked in the certificate. Set it when the address is an IP.
insecure_tlsAccept an unverifiable certificatefalseAn unverifiable chain no longer counts as a failure: the expiry date is still recorded.
allow_private_targetsAllow loopback and link-local targetsfalseSee “Addresses the checks refuse” below.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.
reasonWhat happened
connectThe port is closed or the server is unreachable.
protocolSomething answered, but not IMAP — or the server hung up, or answered BAD or [UNAVAILABLE] to the login.
authThe account was refused (NO). The server is fine; the credential is not.
tls, cert_expiredSame meaning as for the TLS check. STARTTLS refused is reported as tls.

Mailbox (POP3) — a POP3 server greets, offers TLS and accepts a login, like a real mail client. Examples: Dovecot, your provider’s POP3 server, an old mail server that only speaks POP3.

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
995TCPPOP3 over TLS (default)
110TCPOnly with STARTTLS or no encryption
  1. In DumbMonit, enter the mail server, for example pop.example.com:1995 (port 995 with the default encryption).

  2. Pick the encryption: TLS for port 995, STARTTLS for port 110 (STLS command), None for a server on your own network.

  3. Optional: fill in a mailbox account, to check that the server still accepts logins (a refused password is not reported as an outage).

  • A mailbox account that may log in: Only if you fill in a credential

The check reads the +OK greeting, upgrades the connection if asked (STLS), sends USER and PASS if the target has a credential, then QUIT. Neither STAT nor RETR is ever sent, and nothing is deleted.

Credentials: none, or a username and password. Same rule as IMAP: they are sent after the connection is encrypted and the certificate judged, unless you explicitly chose the encryption “None”.

KeyLabelDefaultHelp
securityEncryptiontlsTLS encrypts from the first byte (port 995), STARTTLS starts in clear text and upgrades with STLS (port 110), None never encrypts (port 110) and sends the password in clear text: only for your own network.
portPort(empty)Used if the address does not give one. Empty: 995 with TLS, 110 with STARTTLS or without encryption.
server_nameServer name (SNI)(the host)Domain name announced to the server and checked in the certificate. Set it when the address is an IP.
insecure_tlsAccept an unverifiable certificatefalseAn unverifiable chain no longer counts as a failure: the expiry date is still recorded.
allow_private_targetsAllow loopback and link-local targetsfalseSee “Addresses the checks refuse” below.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.
reasonWhat happened
connectThe port is closed or the server is unreachable.
protocolSomething answered, but not POP3 — or the mailbox is locked ([IN-USE]) or the system is in trouble ([SYS/...]).
authUSER or PASS was refused (-ERR). The server is fine; the credential is not.
tls, cert_expiredSame meaning as for the TLS check. STLS refused is reported as tls.

SNMP value (single OID) — reads one SNMP object and checks its value against a range or a text. Examples: a temperature or humidity sensor, a UPS status or battery level, a version string or a firmware flag, a counter exposed by a Net-SNMP extend script.

Where the SNMP device type describes a whole machine with a profile, this one asks a narrow question: does this object hold what I expect?

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
161UDPSNMP request (default port)
  1. On the device, enable SNMP and check that the community or the v3 user may read the object (the SNMP view must grant its branch).

  2. In DumbMonit, enter the device address, then the community or the v3 user.

  3. Fill in the object (OID) with its instance suffix, for example 1.3.6.1.2.1.1.3.0.

  4. Optional: set a minimum and a maximum, or an expected text, to be warned when the value drifts.

  • Read access to the object: A read-only community or v3 user is enough

The check reuses the SNMP session of the SNMP device type: same communities (v1/v2c) and v3 users, same retries. Without any bound or expected text, it succeeds as soon as the object exists. A numeric value is charted in probe_snmp_value (a text that holds a number, such as 42,5, counts too). The bounds are inclusive; a value that is not a number fails when a bound is set. The expected text is searched case-insensitively in the value read as text.

KeyLabelDefaultHelp
oidObject (OID)(empty)The SNMP object to read, in numeric form. Add the instance suffix, usually .0 for a single value.
portPort161Used if the address does not give one.
minMinimum value(empty)A numeric value below this fails. Empty: no lower bound.
maxMaximum value(empty)A numeric value above this fails. Empty: no upper bound.
expectExpected text(empty)Text the value must contain, whatever its case. Empty: any value is accepted.
snmp_versionSNMP version2cVersion used with a community. Pick 1 only for an old agent that ignores version 2c; SNMP v3 users ignore it.
allow_private_targetsAllow loopback and link-local targetsfalseSee “Addresses the checks refuse” below.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.
reasonWhat happened
connectThe device is unreachable.
timeoutThe agent did not answer in time: wrong address, wrong community (agents stay silent), or a firewall.
authThe agent rejected the community or the v3 credentials.
protocolThe agent answered something that is not a valid SNMP reply, or refused the request.
not_foundThe agent does not know the object (noSuchObject, noSuchInstance): check the OID, its instance suffix and the SNMP view.
thresholdThe numeric value is outside min / max.
payloadThe value is not a number although a bound is set, or does not contain the expected text.

RADIUS server — authenticates a test account (Access-Request) and expects an Access-Accept: it catches a server that is up but no longer accepts logins. Examples: FreeRADIUS, Windows NPS, the RADIUS behind a WPA-Enterprise Wi-Fi, behind a VPN or behind a 802.1X switch.

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
1812UDPAuthentication requests (default port)
  1. On the RADIUS server, declare the DumbMonit host as a client, with a shared secret (clients.conf on FreeRADIUS, RADIUS Clients on Windows NPS).

  2. Create a test account without a second factor, and note its name and password.

  3. In DumbMonit, enter the server (UDP port 1812 by default), the shared secret and the test account.

  4. Optional: change the NAS identifier if the server filters requests by it.

  • A test account that may authenticate: No network access or admin right is needed

The check sends one Access-Request per run, with the account’s name, its password hidden with the shared secret (RFC 2865) and a signature (Message-Authenticator, RFC 3579, placed first as the BlastRADIUS mitigation asks). It never retries: a lost datagram shows as an outage.

The shared secret and the password are stored encrypted and never come back through the API. Leaving them blank when you edit the monitor keeps the saved ones; changing the account name asks for its password again.

The reply is verified with the shared secret. A server answering with a signature that does not match is reported as bad_secret rather than as an outage, so that the alert says what to fix. A server that does not know the secret usually does not answer at all: see the failure reasons.

KeyLabelDefaultHelp
portPort1812UDP port of the authentication service.
nas_identifierNAS identifierdumbmonitValue of the NAS-Identifier attribute sent with the request. Change it if the server filters requests by NAS.
allow_private_targetsAllow loopback and link-local targetsfalseSee “Addresses the checks refuse” below.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.
reasonWhat happened
connectThe UDP socket could not be opened.
timeoutNo valid reply in time: the server is down, the port is filtered, the shared secret is wrong or this host is not declared as a client (servers drop such requests silently).
authAccess-Reject: the server works and refuses the test account (locked, expired, wrong password). Its Reply-Message, if any, is in the log.
bad_secretThe reply’s signature does not match: the shared secret is probably wrong.
protocolAccess-Challenge (the account asks for a second step), another unexpected code, or a reply that is not valid RADIUS.

gRPC service — calls the standard gRPC health check (grpc.health.v1.Health/Check): it catches a service that is up but reports itself unhealthy. Examples: a gRPC microservice, etcd, a service behind Envoy or a service mesh, any server that registers grpc.health.v1.

An HTTP check cannot do this: gRPC needs HTTP/2, often without TLS (h2c), and the answer is a protobuf message plus a grpc-status in the trailers.

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
50051TCPgRPC over HTTP/2 (default port)
443TCPOnly with the Encrypted connection option (default port)
  1. Check that the server registers the standard health service (grpc.health.v1.Health): most gRPC frameworks have a one-line helper for it.

  2. In DumbMonit, enter the server with its port, for example grpc.home.lan:50051.

  3. Tick Encrypted connection (TLS) for a server that requires it; the port then defaults to 443.

  4. Optional: name a Service, to check its own health instead of the whole server’s.

Without TLS the check speaks HTTP/2 in clear text from the first byte (“prior knowledge”), which is what gRPC servers inside a network expect. With TLS it offers ALPN h2 and fails with protocol if the server does not accept it, and it reads the certificate like the other encrypted checks (expiry, issuer, “Accept an unverifiable certificate”).

The reply is judged in two steps. The grpc-status first, read from the trailers or, for a “Trailers-Only” reply, from the headers: anything but OK fails. Then the status field of the health message: only SERVING succeeds.

Credentials: none.

KeyLabelDefaultHelp
serviceService(empty)Name of the service whose health is asked, for example my.package.MyService. Empty: the health of the server as a whole.
tlsEncrypted connection (TLS)falseConnect with TLS and HTTP/2 (ALPN h2). Unticked, the check speaks HTTP/2 in clear text (h2c), as most services inside a network do.
portPort(empty)Used if the address does not give one. Empty: 50051, or 443 with TLS.
server_nameServer name (SNI)(the host)Domain name announced to the server and checked in the certificate. Set it when the address is an IP.
insecure_tlsAccept an unverifiable certificatefalseAn unverifiable chain no longer counts as a failure: the expiry date is still recorded.
allow_private_targetsAllow loopback and link-local targetsfalseSee “Addresses the checks refuse” below.
timeout_secondsTimeout (seconds)5Time after which the service is reported down if it has not answered. Between 1 and 60.
reasonWhat happened
dns, connect, timeout, tls, cert_expiredAs for the other checks: name, port, delay, TLS handshake, certificate.
unhealthyThe server answers but reports NOT_SERVING, UNKNOWN or SERVICE_UNKNOWN, or replies UNAVAILABLE. probe_grpc_serving_status carries the value.
protocolNot HTTP/2, not gRPC, or a grpc-status other than the ones below. UNIMPLEMENTED means the server does not expose the standard health service; NOT_FOUND, that it does not know the name given in service.
statusThe endpoint answered an HTTP status other than 200 (a proxy, another service); probe_http_status_code carries it.
authUNAUTHENTICATED or PERMISSION_DENIED: the server, or a proxy in front of it, wants credentials the health protocol does not send.

The checks that connect to an address you give them — HTTP, TCP, TLS, NTP, UDP, SSH, SMTP, IMAP, POP3, PostgreSQL, MySQL, MQTT, WebSocket — report what they see — which is also, word for word, what a server-side request forgery does. To keep a monitoring admin from reading services that only the DumbMonit host can reach (the embedded metrics database on 127.0.0.1:8428, a cloud provider’s metadata service on 169.254.169.254), the checks refuse by default:

  • loopback addresses (127.0.0.0/8, ::1);
  • link-local addresses (169.254.0.0/16, fe80::/10), including the cloud metadata address, and the unspecified address (0.0.0.0, ::).

Private LAN ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7) are always allowed: monitoring them is the point of a homelab.

The rule applies to the address you typed, to every address a host name resolves to (checked again at connection time, so a name that changes its answer cannot slip through), and to every redirect the HTTP check follows. A refused address shows as a configuration error on the target — no down alert is sent — naming the option to enable: allow_private_targets. Turn it on for a target that really monitors a service on the DumbMonit host itself.

A redirect to a refused address is reported as a failed measurement (reason="connect"), because it is the monitored service that changed, not the configuration.

Values found at a json_path are never echoed beyond 32 characters in a failure message.

SymptomLikely cause
Ping shows a configuration errorThe net.ipv4.ping_group_range sysctl is missing from the Compose file. See above.
HTTP down with reason="keyword"The keyword is searched in the first max_body_bytes only, case-insensitively unless keyword_case_sensitive is set.
HTTP down with reason="tls"Self-signed or private authority: set insecure_tls.
A check shows a configuration error naming allow_private_targetsThe address is loopback or link-local. See “Addresses the checks refuse” above.
TCP down although telnet host port works from your laptopThe DumbMonit container cannot reach the host (Docker network, firewall). Test from inside the container’s network.
DNS down with reason="record"The answer does not contain every value listed in expect.
Ping down with reason="packet_loss"Loss above loss_threshold_percent; some devices rate-limit ICMP.
DNS down with reason="record" although expect matchesexpect_mode is exact and the answer holds an extra value, or forbid matched.
SMTP down with reason="protocol" on security = starttlsThe relay does not advertise STARTTLS on this port. Use tls for 465, none for a plain local relay.
A database check down with reason="auth"The account exists but may not connect from the DumbMonit machine: check pg_hba.conf, or the host part of the MySQL user.
A database check down with reason="query"Connection and login worked. The database is up and refusing to work: read-only, missing table, recovery.
MQTT down with reason="payload" on a topic that clearly has trafficOnly retained messages reach a client that has just subscribed. Publish that topic with the retain flag, or untick “Expect a retained message”.
WebSocket down with reason="protocol" after a 101Something on the path answers the upgrade without speaking WebSocket — usually a reverse proxy rule that swallows the Upgrade header.