Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
NcStatusCheck — Monitorización centralizada para múltiples instancias de Nextcloud | Kitploit
Herramientas/GitLabGitLab/jp.louvel/ncstatuscheck
Análisis de VulnerabilidadesAuditoría de ConfiguraciónSeguridad en la Nube
GitLabjp.louvel/ncstatuscheck

NcStatusCheck

Monitorización centralizada para múltiples instancias de Nextcloud

Ver Repositorio
214hace 18h 16mAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

NcStatusCheck

Monitoreo centralizado para múltiples instancias de Nextcloud

NcStatusCheck es una herramienta de monitoreo que te permite rastrear el estado de múltiples servidores Nextcloud desde una única interfaz web. Analiza las versiones de Nextcloud y PHP y proporciona recomendaciones de actualización.

Interfaz de NcStatusCheck Interfaz de NcStatusCheck - 2

🎯 Características

Monitoreo

  • Vigilancia automatizada de múltiples instancias de Nextcloud
  • Tres modos de recopilación de datos por servidor: Básico (solo versión de NC), Extendido (datos completos mediante la API serverinfo) y Push (datos enviados por la instancia remota)
  • Análisis de versiones para Nextcloud y PHP
  • Detección del servidor web (nginx, Apache) y protocolos HTTP
  • Seguimiento de disponibilidad (mini uptime): accesibilidad actual + último cambio de estado, mostrado como una insignia roja de "sin conexión" solo cuando está caído. Un diario de transiciones acotado también alimenta un % de disponibilidad de 30 días y una lista de incidentes recientes en la página de detalle
  • Alerta de caducidad del certificado SSL: se lee de la sonda HTTPS existente (sin solicitud adicional), insignia cuando el certificado caduca pronto ( / )
< 15d
< 7d
  • Auditoría de aplicaciones instaladas: verifica occ app:list contra la tienda de aplicaciones de Nextcloud para señalar aplicaciones a revisar — bloqueantes (que bloquean la actualización, incompatibles, aplicaciones de prueba en producción) más señales informativas de madurez/turbulencia (publicadas recientemente, pre-1.0, compilación alpha/beta/rc, ráfaga de lanzamientos, versión recién publicada)
  • Bloques de vigilancia a nivel de flota: un bloque "Aplicaciones a vigilar" (📦) y su gemelo "Contenedores a vigilar" (🐳) agregan cada aplicación / imagen Docker señalada de todas las instancias en una sola entrada cada uno, con filtros por tipo por grupo y una ventana emergente que lista las instancias afectadas y sus versiones
  • Alertas proactivas (webhook y/o correo electrónico): se activan ante un cambio de estado confirmado (sin conexión, mantenimiento, recuperado) para que recibas notificación sin tener el panel abierto — Slack / Mattermost / Google Chat / Discord / JSON sin procesar (ALERT_WEBHOOK_URL), y/o un correo de resumen por lote (ALERT_EMAIL_TO) enviado mediante envío SMTP directo a tu servidor de correo (PHPMailer incluido; recurre al MTA local cuando no hay un relay SMTP configurado). También cubre señales de evolución lenta (ALERT_CHECKS): caducidad del certificado SSL (por niveles), versión de Nextcloud vulnerable/obsoleta, sonda Push obsoleta, informe de auditoría crítico, hallazgo de aplicación bloqueante — una alerta por cada nueva condición, sin spam de recordatorios
  • Período de gracia para actualizaciones: una instancia solo se marca como desactualizada unos días después de que se publique un parche (nc_update_grace_days), para evitar perseguir un lanzamiento con errores del mismo día
  • Columna de estado usando el principio de "silencio = todo bien": solo muestra insignias (⚠️ advertencias, 📦 aplicaciones, 🔄 Docker, 🔒 SSL, 🔴 sin conexión, 🚧 mantenimiento) cuando hay algo que informar
  • Sistema de caché para datos de servidores y versiones oficiales
  • Página de detalle

    • Vista completa de la configuración de cada servidor Nextcloud (PHP, OPcache, Redis, base de datos…) para servidores Extendidos/Push
    • Página de detalle básica para servidores sin sonda: muestra versión, servidor web, protocolo HTTP y una sugerencia de actualización
    • % de disponibilidad de 30 días y lista de incidentes recientes (inicio, fin, duración, motivo), calculados a partir del diario de transiciones de disponibilidad acotado — etiqueta honesta de "medido durante N días" mientras el diario sea más reciente que la ventana
    • Reglas de advertencia de configuración con indicadores ⚠️, cada una reconocible (motivo + caducidad opcional)
    • Sección de informe de auditoría del servidor cuando la instancia envía su informe mensual de nc-audit.sh
    • Accesible haciendo clic en cualquier nombre de servidor o indicador de estado

    Interfaz

    • Panel centralizado con resumen de estado (las tarjetas de resumen muestran recuentos de sin conexión / certificado por caducar / aplicaciones a revisar solo cuando no son cero)
    • Filtros avanzados por estado de Nextcloud, estado de PHP, estado general, imagen Docker en ejecución y búsqueda de texto
    • Versiones oficiales obtenidas automáticamente de las fuentes de Nextcloud
    • Calendario de lanzamientos con fechas de próximas versiones
    • Interfaz FR / EN / DE (selector de idioma en la esquina superior derecha)

    Administración

    • Interfaz de administración para configurar reglas de versiones
    • Tabla de resumen de modos de sonda en la parte superior: explica los tres métodos de recopilación (Básico, Extendido, Push) de un vistazo
    • Gestión de servidores mediante interfaz web con diseño de tarjetas: dos zonas de sonda distintas (serverinfo / push), tokens enmascarados con opción de revelar, eliminación en línea
    • Botón "Configurar sondas" por servidor para alternar zonas de tokens, estado guardado en localStorage
    • Búsqueda de servidores en tiempo real con coincidencia insensible a acentos
    • Generador de scripts Push: genera un script bash cron listo para usar (chmod 700) para la instancia remota de Nextcloud, actualizado automáticamente a medida que cambian las opciones
    • Botón "Activar Push" en el panel: envía una solicitud push a todos los servidores push configurados (visible solo cuando existe al menos un servidor push, período de espera de 5 minutos)
    • Configuración flexible de umbrales de seguridad por rama de Nextcloud

    🏗️ Arquitectura```

    ncstatuscheck/ ├── Frontend │ ├── index.php # Main entry point │ ├── template.html # HTML template (dashboard) │ ├── admin.html # Administration interface │ ├── detail.php # Server detail page │ ├── audit.php # Server-audit script distribution page (nc-audit.sh) │ ├── troubleshooting.php # Probe troubleshooting guide │ ├── app.js / admin.js / detail.js / audit.js / troubleshooting.js │ └── style*.css # One stylesheet per page family ├── APIs (HTTP) │ ├── api.php # Main monitoring API │ ├── detail-api.php # Detail page API (serverinfo + warnings + acks + availability) │ ├── push-api.php # Push reception + trigger + audit-report reception │ ├── ack-api.php # Warning acknowledge / unmute │ ├── admin-api.php # Version configuration routing │ ├── servers-admin-api.php # Server list management │ ├── nextcloud-versions-api.php # Official version scraping │ ├── nextcloud-apps-api.php # App store catalog (slim cache) for the apps audit │ ├── desktop-releases-api.php # Desktop client releases (GitHub, slim cache) │ ├── php-versions-api.php # PHP branch support data │ └── apps-warnings-api.php # Manual app warnings (known-bug list) CRUD ├── Shared modules (lib/) │ ├── auth.php # Auth + CSRF + URL redaction (defense in depth) │ ├── csrf-client.js # Auto-inject X-CSRF-Token in fetch() │ ├── nextcloud-client.php # Centralized HTTP client → remote Nextclouds │ ├── servers-store.php # Single source of truth for servers.json │ ├── uptime-state.php # Up/down state machine + transition journal + availability │ ├── alerts.php # Proactive alert dispatch: webhook + email digest │ ├── alerts-checks.php # Slow-signal alerts (SSL/version/push/audit/apps) + dedup state │ ├── smtp-mailer.php # SMTP transport adapter over vendored PHPMailer │ ├── phpmailer/ # Vendored PHPMailer (3 files + LICENSE, pinned in VERSION) │ ├── apps-warnings-manager.php # Manual app warnings storage │ ├── ui-common.js # NcUI: notify / confirm / prompt + shared app-audit messages │ ├── url-guard.php # Anti-SSRF (loopback, RFC1918, link-local…) │ ├── json-cache.php # Locked JSON read/write helpers │ └── version-config-manager.php # Version rules CRUD ├── Business logic │ ├── version-rules.php # NC / PHP status analysis engine │ ├── warnings-rules.php # Configuration warning engine │ ├── apps-rules.php # Installed-apps audit engine (store catalog cross-check) │ ├── cron-update.php # Full collection script, CLI only (twice a day) │ └── cron-ping.php # Lightweight up/down probe, CLI only (every 5 min) ├── Tools (never web-served — blocked by nginx/.htaccess) │ ├── tools/nc-audit.sh # Standalone server audit script (root, read-only) │ └── tools/ncstatuscheck-push-core.sh # Generic Push probe core (fleet-shared) ├── Tests │ └── tests/run.php # Plain-PHP test suite (no framework): php tests/run.php ├── Configuration │ ├── config.php # Central configuration (git-ignored) │ └── servers.json # Server list with tokens (git-ignored) └── Cache ├── servers_data.json # All server data ├── serverinfo_.json # Raw per-server cache (Extended) ├── push_.json # Last push payload per server ├── ack_.json # Acknowledged warnings per server ├── audit_.json # Last nc-audit.sh report per server ├── version-config.json # Version configuration ├── uptime_state.json # Up/down state per server (mini uptime) ├── uptime_history.json # Bounded up/down transition journal (availability % + incidents) ├── alerts_state.json # "Already alerted" memory of the check alerts ├── nextcloud_versions.json # Official NC versions ├── nextcloud_apps.json # App store slim catalog (apps audit) ├── apps-warnings.json # Manual app warnings (admin-curated) ├── .csrf_secret # CSRF HMAC secret (binary, 0600) └── *.log # Activity logs

    deploy/ansible/ # Fleet deployment of the Push core (Ansible / scp) deploy/docker/ # Container packaging of the monitor itself

    root@kitploit:~
    ## 🔌 Modos de recopilación
    
    Los modos no son mutuamente excluyentes: un servidor puede ser Extended y Push simultáneamente.
    
    | Modo | Insignia | Fuente | Datos recopilados |
    |------|----------|--------|-------------------|
    | **Basic** | *(ninguna)* | `/status.php` + cabeceras HTTP | Versión de Nextcloud (PHP/servidor web si está expuesto) |
    | **Extended** | `⚡ Extended` (púrpura → naranja en error/desactualizado) | `/ocs/v2.php/apps/serverinfo/api/v1/info` con `NC-Token` | Versión de NC, PHP, servidor web, OPcache, Redis, BD, usuarios activos… |
    | **Push** | `📡 Push` (azul → naranja en error/desactualizado) | POST a `push-api.php` | Datos enviados por la instancia NC remota mediante script cron |
    
    El **NC-Token de serverinfo** está disponible en **Nextcloud Configuración → Administración → Sistema**.
    
    El **token push** se genera desde la interfaz de administración; el administrador proporciona un script cron bash listo para usar (`chmod 700`) para desplegar en la instancia monitorizada.
    
    Los datos del modo Extended los proporciona la aplicación [nextcloud/serverinfo](https://github.com/nextcloud/serverinfo), que debe estar instalada y habilitada en la instancia monitorizada.
    
    **Comportamiento de respaldo**: si la API Extended no es accesible (error de conexión, token no válido, aplicación no instalada), NcStatusCheck recurre automáticamente a `/status.php` para obtener al menos la versión de Nextcloud.
    
    **Umbral de desactualización Push**: un servidor push se considera desactualizado si no se han recibido datos dentro de `auto_push_interval + 30 minutos`. El intervalo push predeterminado es de 12 horas.
    
    ### Columnas de la tabla del panel
    
    El panel principal muestra 5 columnas: **Servidor** | **Versión de NC** | **PHP** | **Sondas** | **Estado**
    
    La columna **Sondas** muestra los modos de recopilación activos para cada servidor:
    - Insignia `⚡ Extended` (púrpura, se vuelve naranja en error de conexión o datos desactualizados)
    - Insignia `📡 Push` (azul, se vuelve naranja cuando no se reciben datos dentro del umbral)
    - Ambas insignias pueden aparecer simultáneamente si ambos modos están activos
    - Sin insignia = solo modo Basic
    
    ### Columna de estado
    
    La columna de estado solo muestra algo cuando hay algo sobre lo que actuar:
    
    | Indicador | Insignia | Significado |
    |-----------|----------|-------------|
    | Sin conexión | `🔴 Offline` | Instancia inaccesible (sonda HTTP fallida), con "sin conexión durante X" |
    | Advertencias activas | `⚠️ N` | N problemas de configuración |
    | Auditoría de aplicaciones | `📦 N` | N aplicaciones instaladas para revisar (bloquean actualización/incompatibles) |
    | Caducidad SSL | `🔒 N d` | El certificado caduca pronto — naranja `< 15d`, rojo `< 7d` o caducado |
    | Actualizaciones Docker | `🔄 M` | M actualizaciones de contenedores disponibles |
    | Todo correcto | *(vacío)* | Nada que informar |
    | Sin datos | `?` | Modo Basic sin datos push |
    
    #### Activo/inactivo y caducidad SSL
    
    NcStatusCheck mantiene un estado activo/inactivo **mínimo** por servidor (solo estado actual + fecha del último cambio — sin series temporales, sin página de historial). "Activo" significa que la sonda HTTPS saliente alcanzó la instancia; una insignia roja **Offline** aparece solo cuando está inactiva. Durante esa misma sonda HTTPS, la **caducidad del certificado SSL** se lee de forma gratuita (`CURLOPT_CERTINFO`) y se muestra cuando se acerca. Ambos son visibles en su totalidad en la página de detalle. *Nota: estas comprobaciones salientes no se aplican a instancias solo Push con las que el monitor nunca contacta.*
    
    #### Auditoría de aplicaciones (`📦`)
    
    Cuando un servidor Push informa de sus aplicaciones instaladas (`occ app:list`, script push v3+), NcStatusCheck las contrasta con el catálogo de la tienda de aplicaciones de Nextcloud y marca las aplicaciones que merecen revisión. **Solo señalización** — la herramienta nunca desactiva nada; muestra candidatos (no puede saber si una aplicación se usa realmente). Solo se utilizan señales **fácticas y binarias**. La insignia `📦 N` cuenta los hallazgos bloqueantes (sin versión compatible para la versión actual de NC, sin versión para NC N+1 → bloquea la actualización, o una aplicación de prueba/desarrollo dejada habilitada en producción). Los hallazgos informativos (aplicación desactualizada en la instancia, abandonada upstream, PHP incompatible) se muestran solo en la página de detalle. Los hallazgos pueden silenciarse mediante el mismo mecanismo de reconocimiento que las advertencias.
    
    ### Formato de `servers.json````json
    [
      {"url": "https://cloud.example.com"},
      {"url": "https://cloud2.example.com", "serverinfo_token": "abc123def456"},
      {"url": "https://cloud3.example.com", "serverinfo_token": "...", "push_token": "xyz789"}
    ]
    

    🚀 Instalación

    Requisitos previos

    • PHP 8.1+ con extensiones cURL y JSON — ese es el mínimo de sintaxis contra el que CI ejecuta las pruebas, no una recomendación de despliegue: tanto 8.1 como 8.2 ya han superado su fecha de fin de soporte de seguridad, usa una versión con soporte actual (8.3+ en el momento de escribir esto) para cualquier cosa expuesta a internet
    • Servidor web nginx o Apache con HTTPS
    • Acceso de red a los servidores Nextcloud que se van a monitorizar

    Configuración del servidor web (nginx)```nginx

    server { server_name monitoring.your-domain.com; root /var/www/ncstatuscheck; index index.php;

    root@kitploit:~
    # HTTP Basic Authentication
    auth_basic "Monitoring Access";
    auth_basic_user_file /etc/nginx/.htpasswd;
    
    # Protect sensitive files/dirs (tests/run.php has no CLI-only guard — it must
    # never be reachable over HTTP; same blocklist as deploy/docker/nginx.conf)
    location ~ ^/(cache/|\.git|deploy/|tools/|tests/) {
        deny all;
        return 404;
    }
    
    # .txt covers servers.txt (legacy server list — real monitored URLs)
    location ~* \.(log|json|txt)$ {
        deny all;
        return 404;
    }
    
    # Security headers for static HTML pages (admin.html, template.html).
    # PHP pages (index.php, detail.php) send the same headers themselves
    # via send_security_headers() in lib/auth.php.
    location ~* \.html$ {
        add_header X-Content-Type-Options nosniff always;
        add_header X-Frame-Options DENY always;
        add_header Referrer-Policy no-referrer always;
        add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'" always;
        try_files $uri =404;
    }
    
    # Standard PHP configuration (adjust the socket to your PHP version —
    # use a security-supported one: 8.2 has been EOL since December 2025)
    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.4-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    
    location / {
        try_files $uri $uri/ =404;
    }
    

    }

    root@kitploit:~
    > **Apache**: el repositorio incluye archivos `.htaccess` que reflejan las reglas `deny`
    > anteriores (raíz: bloquea `*.log`/`*.json`/`*.txt` y `.git`; `cache/`, `tools/`,
    > `deploy/`, `tests/`: `Require all denied`). Solo funcionan si el vhost establece
    > `AllowOverride FileInfo AuthConfig` (o `All`) — el valor predeterminado de Debian para
    > `/var/www` es `AllowOverride None`, en cuyo caso replica las reglas directamente en el
    > vhost. La autenticación básica HTTP aún debe configurarse en el vhost de cualquier manera.
    
    ### Implementación
    
    1. **Clonar el repositorio**```bash
    git clone https://gitlab.com/jp.louvel/ncstatuscheck.git
    cd ncstatuscheck
    
    1. Configuración Crea tu archivo de configuración a partir de la plantilla:```bash cp config-example.php config.php
    root@kitploit:~
    Edita `config.php` y ajusta las rutas y la URL a tu entorno:```php
    define('MONITOR_PATH', '/var/www/ncstatuscheck');
    define('MONITOR_URL', 'https://monitoring.your-domain.com'); // your public URL
    define('CACHE_DIR', MONITOR_PATH . '/cache');
    
    1. Añadir servidores

    Los servidores se gestionan directamente desde la interfaz de administración (botón ⚙️ Admin). También puedes crear servers.json manualmente:```json [ {"url": "https://cloud.example.com"}, {"url": "https://nextcloud.mycompany.org", "serverinfo_token": "your_token_here"} ]

    root@kitploit:~
    > **Migración desde `servers.txt`**: si existe un archivo `servers.txt`, se convierte automáticamente a `servers.json` en el primer acceso. Luego puedes eliminar `servers.txt`.
    
    4. **Establecer permisos**
    
    nginx/PHP-FPM se ejecutan con su propio usuario (`www-data` en Debian/Ubuntu, `nginx`/`apache`
    en la familia RHEL — ajusta según corresponda) — si clonaste como tu propio usuario de inicio de sesión, ese usuario
    casi con seguridad no será `www-data` ni estará en su grupo, por lo que `chmod` por sí solo deja al
    servidor web **sin acceso alguno**, ni siquiera de lectura (cada solicitud devuelve 403/404):```bash
    chown -R www-data:www-data /var/www/ncstatuscheck   # adjust the user:group to your distro
    
    chmod 750 /var/www/ncstatuscheck
    chmod 750 cache img
    
    chmod 640 *.php *.html *.js *.css *.md
    chmod 600 config.php servers.json servers.txt   # secrets / serverinfo & push tokens
    chmod 660 cache/*.json cache/*.log
    

    Si servers.json aún no existe (estás dejando que la interfaz de administración lo cree en lugar del paso manual anterior), el chmod 600 anterior simplemente no tiene nada sobre lo que actuar — eso está bien: ServersStore::save() aplica chmod al archivo a 0600 por sí mismo en cada escritura, por lo que un servers.json (re)creado a través de la interfaz de administración nunca permanece legible por grupo/mundo con tokens de serverinfo/push dentro.

    1. Autenticación HTTP```bash htpasswd -c /etc/nginx/.htpasswd admin
    root@kitploit:~
    6. **Tareas programadas (opcional)**
    
    Dos crons complementarios: instala ambos **en la misma llamada `crontab -`**:
    `crontab -` instala un crontab completo nuevo desde stdin, no añade, por lo
    que ejecutarlo dos veces (una por línea) deja solo el *segundo* trabajo — el
    primero desaparece silenciosamente, sin error. Esto también conserva cualquier
    cosa que ya esté en tu crontab (`crontab -l` canalizado primero) en lugar de
    borrarlo:```bash
    (crontab -l 2>/dev/null; cat <<'EOF'
    # Full collection (NC/PHP versions, serverinfo, app-store catalog) — twice a day
    0 6,18 * * * cd /var/www/ncstatuscheck && php cron-update.php
    # Lightweight reachability probe (status.php only -> up/down state) — every 5 min
    */5 * * * * cd /var/www/ncstatuscheck && php cron-ping.php
    EOF
    ) | crontab -
    

    Re-ejecutar esto añade duplicados si estas líneas ya están presentes — comprueba con crontab -l primero si no estás seguro.

    cron-ping.php es intencionadamente mínimo: solo comprueba el status.php de cada instancia y actualiza el estado arriba/abajo (cache/uptime_state.json), por lo que puede ejecutarse con frecuencia sin carga. Una instancia solo se marca como caída después de UPTIME_FAIL_THRESHOLD sondeos fallidos consecutivos (por defecto 2 → ~10 min con una cadencia de 5 min); la recuperación a activa es inmediata. El cron-update.php completo permanece sin cambios para todo lo demás.

    Docker (alternativa a instalación en bare-metal)

    En lugar de los pasos 1–6 anteriores, NcStatusCheck también puede ejecutarse como un pequeño stack de docker compose (PHP-FPM + nginx + un contenedor cron) — el repositorio se monta por bind tal cual, sin paso de compilación ni Composer, por lo que refleja exactamente la estructura de bare-metal, solo que contenerizado. Sirve únicamente HTTP plano (puerto 8080 por defecto) — coloca tu propio proxy inverso con terminación TLS delante.

    La configuración completa — configuración, los problemas de permisos (uid 82, pre-creación de servers.json), autenticación HTTP Basic, cron, actualizaciones y copias de seguridad — vive íntegramente en deploy/docker/README.md. Empieza ahí; esta sección es intencionadamente solo una referencia, para evitar mantener dos copias de los mismos pasos sincronizadas.

    📋 Uso

    Interfaz principal

    • Ve a https://monitoring.your-domain.com
    • Consulta el panel con el estado de todos tus servidores
    • Usa los filtros para acotar por estado o búsqueda
    • Comprueba las versiones oficiales y el calendario de lanzamientos

    Administración

    • Abre la interfaz de administración mediante el botón "⚙️ Admin"
    • Una tabla resumen de modos de sondeo en la parte superior de la página explica las diferencias entre los métodos de recopilación Basic, Extended y Push
    • Gestión de servidores: cada servidor se muestra como una tarjeta con dos zonas de sondeo plegables:
      • Zona Serverinfo: configura el token de lectura (NC → extracción de NcStatusCheck)
      • Zona Push: genera un token push y descarga el script cron listo para usar para la instancia remota
    • Configuración de Nextcloud: establece versiones mínimas seguras por rama (efectos hover en las filas)
    • Configuración de PHP: establece estados recomendados/soportados por versión

    Página de detalle

    Accesible haciendo clic en cualquier nombre de servidor o en su indicador de Health.

    Para servidores Basic (sin sonda Extended ni Push), una página simplificada muestra los datos disponibles (versión de NC, servidor web, protocolo HTTP) con un aviso y una sugerencia para habilitar una sonda.

    Para servidores Extended / Push, la página de detalle completa muestra secciones separadas:

    SecciónCampos
    Sistema NextcloudVersión, modo debug, memcache local/distribuida, bloqueo de archivos, espacio en disco
    PHPVersión, memory_limit, upload_max_filesize, max_execution_time, FPM, OPcache
    Servidor webNombre + versión, protocolo HTTP
    Base de datosTipo, versión, tamaño
    CachéRedis, tasa de aciertos de APCu
    Usuarios activosÚltimos 5 min, 1 h, 24 h, 7 días

    API

    NcStatusCheck expone varios endpoints REST:

    API principal (api.php)

    • GET ?action=get_data — Obtener datos (caché o actualización)
    • POST ?action=refresh_data — Forzar la actualización de todos los servidores

    API Push (push-api.php)

    • POST con cabecera push_token — Recibir datos push de una instancia NC remota
    • POST ?action=request_push_all — Solicitar un push inmediato de todos los servidores push configurados (establece un indicador de activación consumido por el script cron remoto)

    El script cron generado por la interfaz de administración se divide en dos: un núcleo genérico /usr/local/bin/ncstatuscheck-push.sh — idéntico en cada servidor (toda la lógica) — controlado por una pequeña configuración por instancia /etc/ncstatuscheck/<slug>.conf (SERVER_URL, SLUG, OCC_CMD, DOCKER_ENABLED, SKOPEO_ENABLED). Se invoca como ncstatuscheck-push.sh /etc/ncstatuscheck/<slug>.conf [--test]. El núcleo se niega a cargar una configuración escribible por grupo/todos (anti inyección de código).

    Es multi-destino (fan-out): los datos se recopilan una vez y se envían a cada monitor listado en /etc/ncstatuscheck/targets-<slug>.conf (una línea url|push_token[|http_user|http_pass] por monitor). El administrador de cada monitor emite un comando idempotente para registrarse.

    Múltiples instancias de Nextcloud en un mismo host: las rutas por instancia se sufijan con un <slug> derivado de la URL monitorizada (p. ej. latest.ezeo.coop → latest_ezeo_coop): <slug>.conf, /etc/cron.d/ncstatuscheck-<slug>, targets-<slug>.conf, ncstatuscheck-push-<slug>.log, estado …-<slug>.<md5>.last. Solo el núcleo se comparte, por lo que las instancias co-ubicadas nunca colisionan.

    Nextcloud ejecutándose en Docker (imagen oficial, compose, AIO): totalmente compatible — el script se instala en el host (cron root + acceso al daemon de Docker), nunca dentro del contenedor, y occ pasa por docker exec: OCC_CMD=docker exec -u www-data <container> php occ (contenedor AIO: nextcloud-aio-nextcloud). El generador de scripts de administración tiene un preajuste de tipo de instalación que rellena esto. Nunca añadas -t (sin TTY bajo cron); mantén -u www-data (la imagen oficial rechaza occ como root).

    Despliegue/actualizaciones de flota: como el núcleo es un único archivo idéntico, actualizar la lógica en muchos servidores = reemplazar ese único archivo (el marcador ↑ señala servidores que ejecutan una versión anterior). Consulta deploy/ansible/ para un playbook listo para usar (o un simple bucle scp). El monitor permanece pasivo — nunca envía código a la flota; el ancla de confianza es tu propio acceso SSH, no el monitor.

    Migración desde una instalación anterior a v4 (script monolítico por instancia): elimina el antiguo /usr/local/bin/ncstatuscheck-push-<slug>.sh y /etc/cron.d/ncstatuscheck-<slug> antes de instalar el núcleo + la configuración (el targets-<slug>.conf se reutiliza tal cual), de lo contrario harás doble push.

    API de detalle (detail-api.php)

    • GET ?server=<url> — Datos completos de serverinfo + advertencias calculadas para un servidor Extended/Push

    APIs de administración

    • admin-api.php — Configuración de versiones
    • servers-admin-api.php — Gestión de servidores (get_servers, add_server, remove_server, update_server_token, generate_push_token, remove_push_token)
    • nextcloud-versions-api.php — Versiones oficiales
    • desktop-releases-api.php — Lanzamientos del cliente de escritorio de Nextcloud (get_desktop_releases, refresh_desktop_releases)

    🩺 Auditoría de servidores (nc-audit.sh)

    Un subsistema separado de la monitorización: un script bash independiente y de solo lectura (tools/nc-audit.sh) ejecutado como root en un servidor Nextcloud para una auditoría única / mensual del ajuste de web + PHP + base de datos, contrastada con la capacidad física de la máquina (RAM, CPU, tipo de disco). Orientado a una oferta de supervisión gestionada: el cliente lo instala, el monitor solo recibe informes — sin acceso a la máquina/red requerido. El script solo lee la configuración (sin cambios), imprime un informe en color y escribe una copia en /tmp.

    Qué comprueba: capacidad del servidor (RAM/CPU/SSD-HDD, swappiness, detección de servidor compartido) · Nextcloud (versiones, cron, caché, Redis en tiempo de ejecución, tipo de BD, registros) · PHP/PHP-FPM (SAPI de servicio real, OPcache en tiempo de ejecución, memoria multi-pool) · Apache (memoria de trabajadores consciente de MPM) · Nginx · PostgreSQL · MariaDB · higiene de seguridad (fail2ban o CrowdSec + bouncer + blocklist comunitaria; actualizaciones pendientes / reinicio / servicios en librerías obsoletas) · conciliación del presupuesto de RAM (InnoDB + FPM + Apache frente a RAM real) · análisis profundo con herramientas opcionales si ya están presentes (mysqltuner, pt-variable-advisor, apache2buddy, sar/iostat).```bash

    Download (the page distributes it; the repo raw URL is public)

    curl -fsSL https://gitlab.com/jp.louvel/ncstatuscheck/-/raw/master/tools/nc-audit.sh -o /usr/local/bin/nc-audit.sh chmod 700 /usr/local/bin/nc-audit.sh

    sudo nc-audit.sh # auto-detect, dedicated server sudo nc-audit.sh /var/www/nextcloud # explicit path (or NC_PATH=…) sudo NC_RAM_BUDGET_PCT=50 nc-audit.sh # shared host: size to 50% of RAM

    root@kitploit:~
    **Hosts multi-instancia** (varios Nextclouds + una base de datos compartida). `NC_RAM_BUDGET_PCT`
    es entonces el presupuesto **total** de la pila; `NC_PHP_SHARE_PCT`% de este (por defecto 60, el resto
    cubre DB + web + SO — redúcelo en servidores con mucha carga de DB) es la parte de PHP, dividida entre
    los pools de FPM por **peso** (una importancia relativa — no un porcentaje, ni MB) para dar un
    objetivo `pm.max_children` por pool:```
    target = PHP_share × (weight / Σ weights) / ~50 MB per process
    

    El objetivo es un techo que el presupuesto permite, no un valor que debas fijar (solo aumenta un pool que realmente se satura). Los pesos son decisión tuya: la herramienta nunca los adivina.```bash

    Weights you provide (a human judgment — the tool never guesses them):

    sudo NC_RAM_BUDGET_PCT=70 NC_INSTANCES="poolA:4,poolB:2,poolC:1" nc-audit.sh

    Interactive helper (terminal only): lists the pools, asks a weight for each,

    prints the targets + a reusable NC_INSTANCES line:

    sudo NC_RAM_BUDGET_PCT=70 nc-audit.sh --tune-fpm

    root@kitploit:~
    **Informe push-back** (opcional, reutiliza la infraestructura Push): `nc-audit.sh --push
    /etc/ncstatuscheck/<slug>.conf` ejecuta la auditoría y envía el informe mediante POST al
    monitor(es), que lo almacenan y lo muestran en la página de detalles del servidor (sección "🩺
    Auditoría del servidor"). Normalmente un cron mensual. La página web (admin, beta) en
    `audit.php` distribuye el script (descarga + inline + one-liner de GitLab) y muestra
    su versión.
    
    > **Las herramientas de análisis profundo nunca se instalan** mediante el script — solo se ejecutan si
    > ya están presentes (sin `curl | bash`, sin autoinstalación), cada una limitada por `timeout`.
    
    ## 🔧 Configuración avanzada
    
    ### Personalización de las reglas de versión
    
    Las reglas de evaluación son configurables a través de la interfaz de administración:
    
    **Estados de Nextcloud:**
    - `dev` — Versión de desarrollo
    - `stable` — Versión estable actual
    - `oldstable` — Versión estable anterior compatible
    - `deprecated` — Versión obsoleta
    
    **Estados de PHP:**
    - `recommended` — Versión recomendada
    - `supported` — Versión compatible
    - `deprecated` — Versión obsoleta
    
    ### Variables de configuración
    
    Edita `config.php` para adaptar la configuración:```php
    // Environment: 'dev' or 'prod'
    define('ENV', 'prod');
    
    // Paths and URLs
    define('MONITOR_PATH', '/var/www/ncstatuscheck');
    define('MONITOR_URL', 'https://monitoring.your-domain.com');
    
    // Main server cache duration
    define('CACHE_MAX_AGE', 86400); // 24 hours
    
    // Official Nextcloud versions cache duration
    define('VERSIONS_CACHE_AGE', 86400);
    
    // Consecutive failed probes before a server is marked "down" (min 1)
    define('UPTIME_FAIL_THRESHOLD', 2);
    
    // Proactive alerts — webhook on a confirmed up/down state change.
    // Empty URL = disabled. Format: 'slack' (default, also Mattermost/Google Chat),
    // 'discord', or 'raw' (structured JSON). The URL usually carries a secret, so it
    // is never logged in full — see config-example.php for details.
    define('ALERT_WEBHOOK_URL', '');
    define('ALERT_WEBHOOK_FORMAT', 'slack');
    
    // Check alerts on top of up/down (cron-update cadence, 2×/day): SSL expiry
    // tiers, vulnerable (below min_secure) or deprecated Nextcloud version, stale
    // Push data, critical audit report, blocking apps-audit finding. Edge-triggered with a persisted state
    // (cache/alerts_state.json): one alert per NEW condition, no reminders, re-arms
    // when resolved (renewed cert, fixed/acked app…). First run arms silently.
    define('ALERT_CHECKS', 'ssl,version,push_stale,audit,apps'); // '' = up/down only
    define('ALERT_SSL_DAYS', '30,14,7');                          // days-left tiers
    
    // Email channel, independent of the webhook (either one arms the alerting).
    // One digest mail per batch. Recommended transport: direct SMTP submission to
    // your mail server (vendored PHPMailer, lib/phpmailer/ — nothing to set up on
    // the host). Without ALERT_SMTP_HOST it falls back to PHP mail() (local MTA).
    define('ALERT_EMAIL_TO', '');    // comma list of recipients, '' = off
    define('ALERT_EMAIL_FROM', '');  // default: ncstatuscheck@<hostname>
    define('ALERT_SMTP_HOST', '');   // e.g. 'mail.example.org', '' = mail() fallback
    define('ALERT_SMTP_PORT', 587);
    define('ALERT_SMTP_SECURITY', 'starttls'); // 'starttls' | 'tls' | 'none'
    define('ALERT_SMTP_USER', '');
    define('ALERT_SMTP_PASS', '');
    

    Consulta config-example.php para ver la lista completa y comentada de opciones (incluyendo DEMO_MODE y PUSH_SCRIPT_VERSION).

    🛡️ Seguridad

    Medidas implementadas

    • Autenticación HTTP Basic obligatoria, reforzada por una verificación de autenticación a nivel de aplicación en cada endpoint de administración (defensa en profundidad)
    • Protección CSRF: token HMAC inyectado automáticamente en cada petición mutante (lib/csrf-client.js + csrf_require())
    • Protección anti-SSRF en cada URL proporcionada por el operador (se rechazan loopback, RFC1918 y link-local; redirecciones solo HTTPS; verificación de IP tras la conexión)
    • HTTPS obligatorio con certificados Let's Encrypt
    • Protección de archivos de datos y registros: reglas de nginx (ver arriba) replicadas por los archivos .htaccess incluidos para Apache; servers.json con chmod 0600 automático (contiene tokens)
    • Cabeceras de seguridad (CSP, X-Frame-Options, nosniff, Referrer-Policy) en cada página servida por PHP
    • Validación estricta de URL en todas las entradas
    • Scripts de cliente ejecutados como root: la configuración de la instancia se carga como root y el archivo de objetivos decide a dónde se envían los datos recopilados — ambos se rechazan a menos que no sean escribibles por grupo/otros ni pertenezcan a un tercero
    • Aislamiento entre instancias monitorizadas: un push solo se acepta cuando la URL del cuerpo coincide con una entrada Y hash_equals() pasa con el token de esa entrada, por lo que un servidor monitorizado comprometido no puede leer ni sobrescribir los datos de otro. request_push / request_push_all están detrás de autenticación de administrador + CSRF. Verificado de extremo a extremo contra un escenario de cliente comprometido
    • Informe de destinos de push: cada instancia declara a qué monitores envía sus pushes (solo URLs, nunca tokens); la página de detalle los muestra y se dispara una alerta cuando el conjunto cambia — una línea extra en targets.conf copiaría silenciosamente cada push a un tercero
    • Saneamiento de la carga útil del push: los IDs de aplicación están en una lista blanca de caracteres; los campos Docker de formato libre (nombre, imagen, versión, estado) se limpian de <>"'& en la ingesta, además del escape en el momento del renderizado
    • Verificación SSL/TLS para conexiones salientes — nunca deshabilitada, incluido el transporte de alertas SMTP
    • Respuestas remotas limitadas (2 MB): un servidor monitorizado controla completamente lo que responde y nada autentica esa dirección. Sin límite, un servidor que solo transmita datos agotaría la memoria de PHP — un error fatal que ningún try/catch puede capturar, lo que mataría la ejecución de recopilación a mitad del bucle y, con ella, todas las alertas de toda la flota
    • Anonimización en modo demo cubre más que la URL: nombres de contenedores, hosts de registries privados en referencias de imágenes y el hostname citado dentro de los mensajes de error de cURL se eliminan, tanto en el panel como en la página de detalle

    Recomendaciones

    • Usa contraseñas seguras para la autenticación HTTP
    • Restringe el acceso a direcciones conocidas — la pestaña de filtrado de IP de administración genera las reglas por ti (ver abajo)
    • Supervisa los registros en busca de intentos de intrusión
    • Mantén PHP y las dependencias del sistema actualizados

    Banner de salud de config.php (administración)

    config.php está en gitignore y se edita a mano por servidor, por lo que se desvía — silenciosamente, ya que casi todas las constantes tienen un valor de respaldo en el código. Un banner en la parte superior de la página de administración informa de lo que realmente está mal, y solo cuando algo lo está: un PUSH_SCRIPT_VERSION dejado atrás por una actualización, ningún transporte de alertas configurado en absoluto, una etiqueta de cierre final que emite un byte antes de cualquier header(), un directorio de caché no escribible, constantes ausentes que caen silenciosamente en valores predeterminados.

    Solo lectura por diseño y sin acción de guardado, por la misma razón que la pestaña de Notificaciones: config.php pertenece a root y contiene secretos. El contenido del archivo nunca viaja — solo hechos sobre él — y ningún secreto se lee.

    Filtrado de IP (pestaña de administración)

    Todo lo anterior es a nivel de aplicación: cualquiera en internet aún puede alcanzar el monitor y sondearlo, y solo la contraseña lo detiene. La pestaña de filtrado de IP genera las reglas que colocan una lista blanca delante de la aplicación, de modo que los hosts desconocidos no puedan hablar con ella en absoluto. Es defensa en profundidad, no un reemplazo de la autenticación Basic ni de los tokens de push — y solo produce texto para revisar y pegar, nunca escribe una configuración de servidor web o firewall.

    Dos clases de origen, deliberadamente desiguales, para que un servidor monitorizado comprometido no pueda alcanzar la administración:

    ClaseQuiénPuede alcanzar
    pushinstancias monitorizadas solo en modo Push/push-api.php, nada más
    adminbastión / VPN / IP de oficina fijatodo

    Las instancias sondeadas en modo Basic/Extended no abren ninguna conexión entrante y no reciben ninguna entrada de lista blanca.

    Las direcciones provienen de dos fuentes, y la diferencia importa: el registro DNS de un dominio monitorizado es su dirección de ingreso, mientras que su push sale desde su egreso. Donde difieren, solo funciona la segunda. Por lo tanto, push-api.php registra la dirección de origen real de cada push (source_ip en la caché de push), y la pestaña la incluye en la lista blanca, informando de la discrepancia. Hasta que un servidor haya hecho push una vez, recurre a DNS A+AAAA y lo indica.

    Tres salidas:

    • nginx (recomendado) — un archivo conf.d autocontenido (geo + map) más una única línea if ($ncsc_forbidden) { return 403; } en el vhost. No es necesario duplicar el bloque fastcgi, los archivos estáticos también están cubiertos (admin.html es uno), y /.well-known/acme-challenge/ permanece abierto para que la renovación de certificados no se rompa silenciosamente.
    • Apache 2.4 — <LocationMatch> con una búsqueda negativa hacia adelante más un <Location> para el endpoint de push, de modo que las dos secciones no puedan solaparse y nada dependa del orden de fusión de Apache. Todas las direcciones de una regla van en una línea Require ip: varias líneas dentro de <RequireAll> se combinan con AND, lo que nadie puede satisfacer.
    • ufw — tosco por naturaleza (un filtro de paquetes ve puertos, no URLs), por lo que no puede expresar la división push/admin. Úsalo solo como capa exterior.

    El generador se niega a emitir cualquier cosa cuando no se proporciona ninguna dirección de administración, advierte cuando la propia dirección del operador no está cubierta, y advierte cuando la petición llegó a través de un proxy (tanto geo como Require ip leen el peer de transporte, por lo que detrás de un proxy todos los clientes parecen iguales). El fragmento ufw generado coloca la regla SSH primero, mantiene el puerto 80 abierto para el desafío HTTP-01, y explica la trampa de IPv6: a diferencia de nginx, que rechaza una dirección v6 no listada, ufw no filtra v6 en absoluto a menos que IPV6=yes esté configurado — un host de doble pila estaría de otro modo completamente abierto a través de IPv6.

    Límite conocido, señalado en la propia página: una vez aplicadas las reglas, esta pestaña no descubre nada nuevo. Un push rechazado es rechazado por el servidor web antes de llegar a PHP, por lo que la dirección registrada sigue siendo la última que logró pasar — y aún parece verificada. Dos consecuencias: añadir un servidor Push significa regenerar y reaplicar las reglas, o su primer push será rechazado; y si la dirección de una instancia cambia, la nueva solo se puede leer en el registro de acceso del servidor web (grep 'push-api.php' access.log | grep ' 403 '). Por lo tanto, la pestaña muestra la fecha de última aparición de cada dirección observada y la marca una vez que es más antigua que un ciclo completo de push perdido — el mismo umbral que la alerta push_stale, que cubre el mismo punto ciego desde el otro lado.

    Distinguir un problema de filtrado de cualquier otro: un GET simple en el endpoint de push separa las capas limpiamente, sin efectos secundarios y sin necesidad de token — ejecútalo desde la máquina en cuestión, ya que lo que se juzga es la dirección saliente de esa máquina:```bash curl -sS -o /dev/null -w '%{http_code}\n' https://your-monitor/push-api.php

    root@kitploit:~
    | Respuesta | Significado |
    |---|---|
    | `403` | bloqueado por el filtrado de IP |
    | `401` | el filtrado pasó, Basic auth está respondiendo — el problema está en otro lugar |
    | `405` | la solicitud llegó a la aplicación (GET no es un método aceptado allí) |
    | nada / timeout | no es el filtrado: un filtro responde, no se queda en silencio |
    
    Vuelve a ejecutar con `-u user:password` para resolver una duda sobre un `403`: si el código no
    cambia, realmente es el filtrado. Verificado tanto en nginx como en Apache (incluyendo
    con `Require valid-user` habilitado), el filtro responde *antes* de la autenticación —
    y un `403` proveniente de la propia aplicación siempre lleva JSON en el cuerpo.
    
    La lógica de los snippets vive en `lib/hardening-rules.php`, que es pura y está cubierta
    por `tests/run.php`: los snippets son el producto aquí, y uno incorrecto o bien
    bloquea al operador o deja un agujero. Tanto la salida de nginx como la de Apache
    han sido verificadas conductualmente (servidores reales, direcciones de origen reales, incluyendo
    intentos de path-traversal de la clase `push`).
    
    ### Análisis automatizado (etapa `security` del CI)
    
    El escaneo de dependencias (`npm/pnpm audit`, Snyk Open Source, Dependabot) es un no-op
    aquí: no hay `package.json` ni `composer.json` — nada que escanear. El
    riesgo vive en el código personalizado (~15k líneas de PHP, ~6k de JS) y en los scripts
    de shell que se ejecutan **como root** en las instancias monitoreadas (`tools/*.sh`). El pipeline
    está dirigido allí:
    
    | Trabajo | Herramienta | Bloqueante | Alcance |
    |---|---|---|---|
    | `secrets_scan` | gitleaks | sí | secretos commiteados (árbol de trabajo) |
    | `sast_semgrep` | semgrep (`p/php`, `p/javascript`, `p/owasp-top-ten`) | sí | SSRF, falta de authz/CSRF, XSS |
    | `shellcheck` | shellcheck (`--severity=warning`) | sí | `tools/*.sh` — root en hosts de clientes |
    | `dockerfile_misconfig` | trivy misconfig | sí | `deploy/docker/` |
    | `container_cve` | trivy image | no (`allow_failure`) | la imagen que `deploy/docker` construye, más `nginx:alpine` |
    | `ui_tests` | node (sin dependencias) | sí | invariantes de escape de `lib/ui-common.js` (ambas regresiones XSS pasadas) |
    | `phpmailer_freshness` | GitHub API | no (`allow_failure`) | pin vendored vs release upstream |
    | `deploy_selfcheck` | nc-selfcheck.sh | sí | el ruleset nginx enviado (reglas de denegación + cabeceras de seguridad) levantado en un contenedor desechable |
    
    Todos los trabajos bloqueantes tienen una **línea base de cero hallazgos**, por lo que cualquier nueva alerta es una señal
    real. Dos decisiones deliberadas, documentadas en línea en `.gitlab-ci.yml`:
    
    - **`php.lang.security.injection.echoed-request` está excluida** de semgrep: marca
      cada `echo json_encode()` como XSS, que es lo que cada endpoint de API aquí
      hace legítimamente (respuestas JSON, no HTML). Representó 10 de 10
      hallazgos en la primera ejecución, todos falsos. Mantenerla entrenaría a todos a
      ignorar el trabajo.
    - **Los dos trabajos `allow_failure` reportan hechos upstream** (un CVE en `nginx:alpine`
      o uno cuyo fix aún no ha llegado a la rama Alpine, una nueva release de PHPMailer)
      que un merge request no puede arreglar. Rojo-pero-tolerado es la señal
      precisa — "momento de reconstruir / refrescar el vendoring" — no una razón para bloquear
      trabajo no relacionado. `phpmailer_freshness` reporta una GitHub API inalcanzable o con
      límite de tasa como un *skip*, nunca como "desactualizado".
    - **`container_cve` escanea la imagen que construye, no la etiqueta `FROM`.** El
      Dockerfile endurece la base con `apk --no-cache upgrade` (la imagen oficial de PHP
      va por detrás de los repos de Alpine — envió c-ares 1.34.6-r0 mientras
      1.34.8-r0, que corrige CVE-2026-33630, ya estaba publicada). Escanear la etiqueta
      base reportaría por tanto CVEs que la imagen enviada ya no tiene: un
      trabajo permanentemente naranja que nadie lee.
    
    Las listas de permitidos son intencionalmente estrechas: `.gitleaks.toml` excusa cadenas
    placeholder **literales**, nunca archivos de documentación completos (permitir `README.md`
    cegaría el escaneo el día que un secreto real se pegue en él) — así que un nuevo token
    de ejemplo en la documentación debe añadirse allí. `.trivyignore` contiene una sola entrada,
    `DS-0002`, argumentada en el archivo: el maestro de php-fpm debe iniciar como root para bajar
    sus workers a `www-data` (uid 82).
    
    ### Verificación post-despliegue (`nc-selfcheck.sh`)
    
    El CI puede bloquear la configuración *enviada* (el trabajo `deploy_selfcheck` de arriba levanta
    el ruleset de nginx en un contenedor y lo sondea), pero no puede verificar el servidor
    al que realmente desplegaste — host diferente, credenciales de Basic-auth, permisos
    del sistema de archivos. `tools/nc-selfcheck.sh` cierra esa brecha. Es un script
    bash independiente y de solo lectura (mismo modelo que `nc-audit.sh`) que ejecutas después de cada despliegue:```bash
    # Black-box, no credentials: confirms Basic auth is enforced (401) and that
    # sensitive files are blocked (cache/, servers.*, .git, config.php source).
    bash tools/nc-selfcheck.sh https://monitoring.example.com
    
    # + security headers behind Basic auth:
    bash tools/nc-selfcheck.sh -u user:pass https://monitoring.example.com
    
    # + filesystem checks (run ON the host): servers.json / config.php / CSRF-secret
    # permissions, and a stray closing "?>" in config.php.
    bash tools/nc-selfcheck.sh --webroot /var/www/ncstatuscheck https://monitoring.example.com
    

    Sale con código de salida distinto de cero ante cualquier hallazgo crítico (fuga de código fuente, archivo secreto sin bloquear, almacén de tokens legible por cualquier usuario, autenticación Basic ausente), por lo que puede condicionar un despliegue: conéctalo a tu script de sincronización/despliegue como paso posterior. WARN/INFO nunca hacen fallar la ejecución.

    🧪 Pruebas y desarrollo

    Modo de desarrollo```php

    // In config.php define('ENV', 'dev');

    root@kitploit:~
    En modo de desarrollo, se muestra información adicional (versión de PHP, servidor web).
    
    ### Pruebas del servidor
    Use la interfaz de administración para añadir un servidor por URL. El servidor será consultado en la siguiente actualización de datos.
    
    ### Registros de depuración
    Revise los archivos de registro en `cache/`:
    - `monitor.log` — Registros generales de la aplicación
    - `cron.log` — Registros completos del script de recopilación (`cron-update.php`)
    - `ping.log` — Registros ligeros de sondeo de estado activo/inactivo (`cron-ping.php`)
    - `alerts.log` — Envío proactivo de alertas (webhook/correo electrónico), nunca registra secretos de webhook ni credenciales SMTP
    
    ### Suite de pruebas```bash
    php tests/run.php   # plain-PHP assertions, no framework — exit 0 = all green
    

    Cubre la lógica de negocio pura (reglas de versión/aplicaciones, advertencias, máquina de estados de tiempo de actividad y disponibilidad, máquina de estados de deduplicación/rearme de alertas, constructores de correos electrónicos).

    🤝 Contribuciones

    Reportar un error

    Abre una nueva incidencia con:

    • Una descripción detallada del problema
    • Pasos para reproducirlo
    • Registros de errores si están disponibles
    • Tu configuración del entorno

    Proponer una mejora

    1. Abre una incidencia para discutir tu idea
    2. Haz un fork del proyecto
    3. Crea una rama para tu funcionalidad
    4. Implementa con documentación
    5. Envía una solicitud de fusión

    📝 Licencia

    Este proyecto está licenciado bajo GNU AGPL v3.

    👥 Créditos

    NcStatusCheck es desarrollado por ézéo, una cooperativa digital especializada en soluciones de código abierto.

    Colaboradores

    • Equipo de ézéo — Desarrollo inicial y mantenimiento

    ¿Necesitas ayuda? Consulta las incidencias o contacta con el equipo de ézéo.

    Descargar herramienta