Check the security level of your Nextcloud instance with the Nextcloud Security API
Project description
- check-nextcloud-security
- Quick start
- Features
- Prerequisites
- Installation
- CLI Usage
- Options:
- Environment variables
- Retries and backoff
- Performance data
- Rescan
- Example output
- Icinga Director
- Scheduling without Icinga2 / Nagios (systemd timer / cron)
- Troubleshooting
- License
- More
check-nextcloud-security
Check the security level of your Nextcloud instance with the Nextcloud Security API
This check uses Nextcloud's own security scan at scan.nextcloud.com to check if your Nextcloud instance has any known vulnerabilities/risks.
Quick start
No clone, no Python, no dependency install - just Docker. This builds the image straight from the Git repository and runs a single check:
docker run --rm $(docker build -q https://github.com/sowoi/check-nextcloud-security.git) --host nextcloud.example.com
For a permanent setup (Icinga2, systemd timer, cron, ...) see Installation below.
Features
- Debugging
- Web proxy support
- Trigger a fresh rescan on demand
- Standard Nagios/Icinga exit codes (OK, WARNING, CRITICAL, UNKNOWN)
- Ready-to-use Docker image - no local Python setup required
- Fully configurable via environment variables (great for Docker, systemd, cron)
- Automatic retry with exponential backoff on transient network errors
- Nagios/Icinga performance data (rating, vulnerability count, scan duration)
Prerequisites
- Either Python 3.10+ or Docker - pick whichever installation method you use below.
requests(installed automatically with any of the Python-based methods below)
Installation
Pick whichever method fits your workflow best.
Docker
No Python, pip, or dependency management required on the host - only Docker.
Build the image once from a local checkout of this repository:
git clone https://github.com/sowoi/check-nextcloud-security.git
cd check-nextcloud-security
docker build -t check-nextcloud-security .
Run a check:
docker run --rm check-nextcloud-security --host nextcloud.example.com
Or configure it entirely through environment variables
(handy since you don't need to edit the docker run command per host):
docker run --rm -e CNS_HOST=nextcloud.example.com check-nextcloud-security
The container has no network ports and needs only outbound HTTPS access to
scan.nextcloud.com. It runs as an unprivileged nagios user and exits with
the same Nagios-style codes (0/1/2/3) as the native script, so it can
be dropped straight into any monitoring pipeline that already understands
docker run as a check command (see Icinga2 / Nagios and
Icinga Director below).
If you'd rather not build locally, push the built image to your own registry
(e.g. docker tag check-nextcloud-security registry.example.com/check-nextcloud-security followed by docker push ...) and reference that image on your monitoring host(s) instead.
Using pipx / uv / pip
All of these expose a check-nextcloud-security command on your PATH.
The package is published on PyPI, so a plain
pip install check-nextcloud-security (or the pipx/uv equivalents below) is
the quickest way to get started. If you need the latest unreleased changes,
install directly from git instead by using the git+https://... URLs shown
below.
Using pipx (recommended for CLI tools):
pipx install check-nextcloud-security
# or, to install the latest unreleased changes from git:
pipx install git+https://github.com/sowoi/check-nextcloud-security.git
Using uv:
uv tool install check-nextcloud-security
# or, to install the latest unreleased changes from git:
uv tool install git+https://github.com/sowoi/check-nextcloud-security.git
Using pip:
pip install check-nextcloud-security
# or, to install the latest unreleased changes from git:
pip install git+https://github.com/sowoi/check-nextcloud-security.git
Upgrade an existing pip installation with:
pip install --upgrade check-nextcloud-security
Manual / air-gapped install:
- Clone or download this repository to your local Nextcloud server (or wherever you want to run the check).
- Install the runtime dependency:
pip install -r requirements.txt
- Run the script directly with
python3 check_nextcloud_security.py ...instead of thecheck-nextcloud-securitycommand.
Icinga2 / Nagios:
- If you installed the package with pipx/uv/pip, locate the installed
check-nextcloud-securityexecutable (e.g.which check-nextcloud-security) and reference that path inPluginDir, or copy/symlink it into your plugin folder (usually/usr/lib/nagios/plugins/). - If you're running the script manually, put
check_nextcloud_security.pyinto your plugin folder instead. - Create a new command custom command:
object CheckCommand "check_nextcloud_security" {
import "plugin-check-command"
command = [ PluginDir + "/check-nextcloud-security" ]
arguments += {
"--host" = {
description = "Nextcloud hostname or URL"
required = true
value = "$address$"
}
"--proxy" = {
description = "HTTP/HTTPS proxy (optional)"
required = false
}
"--rescan" = {
description = "Trigger a new scan on each check (optional)"
set_if = "$nextcloud_rescan$"
}
"--debug" = {
description = "Enable debugging output (optional)"
set_if = "$nextcloud_debug$"
}
}
}
- Create a new Service object.
- Please do not run the query too often, or you will be banned. In the template below 24 hours are given. Normally, one check every 24 hours is sufficient.
object Service "Service: Nextcloud Security Scan" {
import "generic-service"
host_name = "YOUR NEXTCLOUD HOST"
check_command = "check_nextcloud_security"
check_interval = 24h
}
Using the Docker image instead
If you installed via Docker, point the CheckCommand at docker
and let it run the container on demand instead of a local binary:
object CheckCommand "check_nextcloud_security_docker" {
import "plugin-check-command"
command = [ "/usr/bin/docker" ]
arguments += {
"run" = {
order = -5
value = "run"
}
"--rm" = {
order = -4
value = "--rm"
}
"image" = {
order = -3
skip_key = true
value = "check-nextcloud-security"
}
"--host" = {
description = "Nextcloud hostname or URL"
required = true
value = "$address$"
}
"--proxy" = {
description = "HTTP/HTTPS proxy (optional)"
required = false
}
"--rescan" = {
description = "Trigger a new scan on each check (optional)"
set_if = "$nextcloud_rescan$"
}
"--debug" = {
description = "Enable debugging output (optional)"
set_if = "$nextcloud_debug$"
}
}
}
This assumes the check-nextcloud-security image has already been built (or
pulled) on the Icinga2 host, and that the user running the Icinga2 daemon has
permission to talk to the Docker socket.
CLI Usage
check-nextcloud-security -hwill show you a manual.
Command
check-nextcloud-security --host <Hostname> --rescan
Options:
| Option | Description | Default | Environment variable |
|---|---|---|---|
-H, --host |
Nextcloud server address(es) (hostname or URL). Accepts a comma-separated list to check multiple hosts in one run | required | CNS_HOST |
-P, --proxy |
Proxy server address | None | CNS_PROXY |
-r, --rescan |
Trigger a fresh scan each time (slower, more accurate) | False | CNS_RESCAN |
-d, --debug |
Enable verbose debugging output | False | CNS_DEBUG |
--retries |
Retry attempts for transient network errors | 2 |
CNS_RETRIES |
--backoff-factor |
Exponential backoff factor (seconds) between retries | 0.5 |
CNS_BACKOFF_FACTOR |
-V, --version |
Show the installed version and exit | — | — |
-h, --help |
Show help and exit | — | — |
Checking multiple hosts
--host (and CNS_HOST) accepts a comma-separated list of hostnames, e.g.:
check-nextcloud-security --host nextcloud1.example.com,nextcloud2.example.com
Hosts are processed one by one. The output starts with a one-line summary
(e.g. Checked 2 host(s): overall CRITICAL (1 CRITICAL, 1 OK)), followed by
one result block per host. The plugin exits with the worst status found
across all hosts, using the usual Nagios/Icinga priority: CRITICAL >
WARNING > UNKNOWN > OK. A single host still produces the original,
single-block output and exit code, so existing single-host setups are
unaffected.
Whitespace around each hostname is ignored, and empty entries (e.g. from a trailing comma) are dropped.
Environment variables
Every option has a CNS_-prefixed environment variable equivalent (see the
table above). This is especially useful for Docker, systemd, and cron, where
setting environment variables is often more convenient than editing a command
line. An explicit command-line flag always takes precedence over its
environment variable.
export CNS_HOST=nextcloud.example.com
export CNS_PROXY=http://proxy.example.com:3128
check-nextcloud-security
Boolean variables (CNS_DEBUG, CNS_RESCAN) accept 1, true, yes, or
on (case-insensitive) to enable the corresponding flag; any other value
(including unset/empty) is treated as disabled.
Retries and backoff
Transient network errors (timeouts, connection resets, 5xx responses from
scan.nextcloud.com) are retried automatically with exponential backoff before
the check gives up and reports UNKNOWN.
--retries/CNS_RETRIES(default2) - number of retry attempts after the initial try (so the default performs up to 3 attempts total).--backoff-factor/CNS_BACKOFF_FACTOR(default0.5) - base delay in seconds; the wait before each retry doubles (backoff_factor * 2^attempt), e.g.0.5s,1s,2s, ...
Set --retries 0 to disable retries entirely and fail fast.
Performance data
Output includes standard Nagios/Icinga performance data after a |
character, so Icinga2/Grafana/etc. can graph results over time:
rating=5;;;0;5 vulnerabilities=0;;;0; time=1.234s;;;0;
| Metric | Meaning |
|---|---|
rating |
Numeric scan rating, 0-5 (5=A+ ... 0=F), U if unknown |
vulnerabilities |
Number of known vulnerabilities reported for the scanned version |
time |
Time spent querying scan.nextcloud.com, in seconds |
Rescan
Too many checks with --rescan may lead to no further scans being possible for a certain period of time.
As a rule, it is sufficient to perform one scan per day.
Example output
$ check-nextcloud-security -H nextcloud.example.com
CRITICAL: This server version is end-of-life and has no security fixes.
Nextcloud 24.0.11.1 on nextcloud.example.com, rating: F, last scanned: 2023-05-30 07:48:58.000000 | rating=0;;;0;5 vulnerabilities=0;;;0; time=0.842s;;;0;
$ check-nextcloud-security -H nextcloud.example.com
OK: Server is up to date. No known vulnerabilities.
Nextcloud 26.0.2.1 on nextcloud.example.com, rating: A+, last scanned: 2023-05-29 08:50:58.000000 | rating=5;;;0;5 vulnerabilities=0;;;0; time=0.731s;;;0;
Icinga Director
Icinga Director manages
CheckCommand, Service Template, and Service objects through its web UI
instead of hand-written config files. The steps below work for either the
native install or the Docker image.
-
Create the Command
- Navigate to Icinga Director → Commands → Add.
- Command name:
check_nextcloud_security - Command:
- Native install:
/usr/lib/nagios/plugins/check-nextcloud-security(wherever you installed/symlinked it, see Installation). - Docker:
/usr/bin/docker(see the Docker CheckCommand example for the required fixed argumentsrun,--rm, and the image name).
- Native install:
- Command type: Plugin Check Command.
-
Add the arguments on the same Command object (Fields tab → Add argument):
Argument Value Description --host$address$(or a custom Director Data Field, e.g.$nextcloud_host$)Nextcloud hostname or URL, required --proxyData Field $nextcloud_proxy$, optionalHTTP/HTTPS proxy --rescanSet-if Data Field $nextcloud_rescan$(boolean), optionalTrigger a fresh scan on every check --debugSet-if Data Field $nextcloud_debug$(boolean), optionalVerbose debug output For each optional argument, tick Skip this argument on empty value so Director omits the flag entirely when the field isn't set.
-
Expose the fields to services by defining matching Data Fields under the Command (Fields tab → Add data field), e.g.
nextcloud_host,nextcloud_proxy,nextcloud_rescan,nextcloud_debug- then set their Data Type (StringorBoolean) and Var Filter as needed. -
Create a Service Template
- Icinga Director → Service Templates → Add.
- Check command:
check_nextcloud_security. - Check interval:
24h(avoid scanning more often - see Rescan). - Leave the Data Fields empty here so they can be filled in per service/host.
-
Apply it to a host or host group
- Icinga Director → Services → Add (or a Service Apply Rule for a whole host group).
- Import the Service Template created above.
- Fill in
nextcloud_host(or rely on$address$if you didn't override it) and any optional fields. - Deploy the configuration from Icinga Director → Deployments.
Once deployed, Icinga2 will invoke the command exactly as described in the
Icinga2 / Nagios section, whether that resolves to the
native binary or docker run under the hood.
Automated deployment with Ansible
Prefer not to click through Icinga Director or configure hosts by hand?
ansible/ contains ready-to-use playbooks that install
and configure check-nextcloud-security (native or Docker) on one or more
Icinga2 hosts, including the CheckCommand/Service objects described
above. See ansible/README.md for prerequisites and
usage.
Scheduling without Icinga2 / Nagios (systemd timer / cron)
If you don't run Icinga2/Nagios, you can still schedule regular scans with
systemd timers or cron. Ready-to-adapt example files live in
contrib/:
contrib/systemd/check-nextcloud-security.serviceand.timercontrib/systemd/check-nextcloud-security.env.examplecontrib/cron/check-nextcloud-security.cron
systemd timer
sudo mkdir -p /etc/check-nextcloud-security
sudo cp contrib/systemd/check-nextcloud-security.env.example /etc/check-nextcloud-security/env
sudo $EDITOR /etc/check-nextcloud-security/env # set CNS_HOST (and any other options)
sudo cp contrib/systemd/check-nextcloud-security.service /etc/systemd/system/
sudo cp contrib/systemd/check-nextcloud-security.timer /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now check-nextcloud-security.timer
# Run it once immediately to verify the setup:
sudo systemctl start check-nextcloud-security.service
journalctl -u check-nextcloud-security.service
cron
sudo cp contrib/cron/check-nextcloud-security.cron /etc/cron.d/check-nextcloud-security
sudo chmod 644 /etc/cron.d/check-nextcloud-security
sudo $EDITOR /etc/cron.d/check-nextcloud-security # set CNS_HOST (and any other options)
Both examples configure the check entirely through environment variables, so the same binary or Docker image can be reused unmodified across hosts - only the environment file/cron entry changes.
Troubleshooting
IP addresses are not supported by the Scan API.
Pass a hostname, not an IP address - scan.nextcloud.com resolves the host
itself and cannot scan a bare IP. Use --host nextcloud.example.com, not
--host 203.0.113.10.
UNKNOWN: ... Scan failed! Either no Nextcloud/ownCloud found or too many scans queued
Either the target host isn't a reachable Nextcloud/ownCloud instance, or
scan.nextcloud.com is rate-limiting new scan requests from your IP. Wait a
while before retrying, and avoid scheduling checks more often than once a day
(see Rescan).
UNKNOWN: Scan result unclear. Please verify manually.
The API returned a rating this plugin doesn't recognize. Run with --debug
(or CNS_DEBUG=1) to log the raw API response, and check the result manually
at https://scan.nextcloud.com.
Requests keep failing / retries exhausted
- Confirm outbound HTTPS access to
scan.nextcloud.comfrom the host (or container) running the check, including through any required proxy (--proxy/CNS_PROXY). - Increase
--retries/CNS_RETRIESand--backoff-factor/CNS_BACKOFF_FACTORif your network is flaky or high-latency. - Run with
--debugto see each retry attempt logged.
Docker: permission denied while trying to connect to the Docker socket
The user running Icinga2/cron/systemd needs permission to talk to the Docker
daemon - either add it to the docker group, or run the check via sudo,
depending on your security policy.
Nothing happens / no output from cron or systemd
- Cron and systemd units don't have a login shell's
PATHor environment by default - use the full path tocheck-nextcloud-securityand setCNS_HOSTexplicitly (see Scheduling). - Check logs with
journalctl -u check-nextcloud-security.service(systemd) or your configured log file (cron, see the example cron file).
Exit code reference
| Exit code | Meaning |
|---|---|
0 |
OK |
1 |
WARNING |
2 |
CRITICAL |
3 |
UNKNOWN |
License
Licensed under the terms of GNU General Public License v3.0. See LICENSE file.
More
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file check_nextcloud_security-1.2.0.tar.gz.
File metadata
- Download URL: check_nextcloud_security-1.2.0.tar.gz
- Upload date:
- Size: 64.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0366f9cda86af636714339f6edde014236384ce07bcc5e7f11982e272712ae37
|
|
| MD5 |
983b99678c07ac170775b3c6999b4aa2
|
|
| BLAKE2b-256 |
527ba8fd752e6040fa8669e74a0d2456951d5b4ee80ee00b32f1dc5c6cfba409
|
File details
Details for the file check_nextcloud_security-1.2.0-py3-none-any.whl.
File metadata
- Download URL: check_nextcloud_security-1.2.0-py3-none-any.whl
- Upload date:
- Size: 38.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
59dbc52115088efd6cfe2e4fcf616c3a750e9a18bff2ff98218a78159e926890
|
|
| MD5 |
80a29a3d4596339939d753a741abf88b
|
|
| BLAKE2b-256 |
35b7a5ef2643cb9fbe405393ad8da1ca69bd85264258ec403e35b69da1af0d52
|