FAQ

Dit is de handleiding voor installatie, configuratie en onderhoud van Arcivéo Monitor. De secties zijn gegroepeerd: algemeen overzicht, uitrol van het dashboard, koppeling van beveiligingstools, ingebouwde modules en diagnostiek. Commando's kunt u kopiëren met de knop rechts.

Waar te beginnen

01. Paneel installeren — kies een methode

De installatie van het paneel staat op aparte stapsgewijze pagina's. Kies een methode:

Weet u het niet zeker — kies dan de automatische. Deze handleiding blijft de centrale bron voor SSL, tools, cron en diagnostiek — de installatiepagina's verwijzen naar de onderdelen ervan, zonder iets te dupliceren.

Overzicht

02. Wat is Arcivéo Monitor

Arcivéo Monitor — een beveiligingsdashboard voor uw server. Het verzamelt gegevens van geïnstalleerde tools (Fail2ban, UFW, Lynis, ModSecurity, AIDE, ClamAV, Auditd, CrowdSec, Suricata, Falco e.a.) en toont ze in één interface met een dashboard, aanvalskaart en gedetailleerde pagina's per tool.

De monitor is geen actief beveiligingsmiddel — hij blokkeert zelf geen aanvallen. Zijn taak is om informatie van reeds werkende tools te verzamelen en overzichtelijk te presenteren.

03. Hoe de monitor op de server werkt

De monitor werkt alleen lokaal — hij moet worden geïnstalleerd op dezelfde server die hij monitort. Er is geen SSH of externe API.

Alle commando's (fail2ban-client, ufw status, ipset list, enz.) voert het paneel uit namens de gebruiker van de webserver (meestal www-data, op hostingpanelen — het account van de site) met een beperkte set rechten sudo — alleen voor specifieke tools, zonder algemene root-toegang. De resultaten worden geparseerd en in de browser weergegeven.

Installeer de monitor voor meerdere servers op elke server afzonderlijk, met een uniek domein.

04. Hoe de beveiligingsscore wordt berekend

De score begint op het maximum en daalt voor elk gevonden probleem:

  • UFW niet actief — −30
  • Fail2ban niet actief (geen actieve jails) — −25
  • Geen WebAuthn-sleutels — −15
  • Lynis hardening index < 60 — −20; 60–79 — −10
  • IPset ipsum niet geladen — −10
  • Bedreigingen gevonden door ClamAV — −20
  • Bestandswijzigingen door AIDE — −15
  • SSL verlopen — −30, verloopt <14 dagen — −15, <30 dagen — −5
  • CrowdSec geïnstalleerd maar niet actief — −5
  • Suricata geïnstalleerd maar niet actief — −5
  • Database/cache (MySQL, PostgreSQL, Redis…) van buitenaf bereikbaar — −10
  • Root-login via SSH toegestaan (PermitRootLogin yes) — −20
  • Beveiligingsupdates wachten op installatie — −5

Resultaat: 80+ = Beveiligd, 60–79 = Let op, <60 = Onder dreiging.

Aftrekpunten voor ClamAV, AIDE, CrowdSec en Suricata gelden alleen als de tool is geïnstalleerd. Lynis en AIDE zonder geïnitialiseerde database worden weergegeven als “geen gegevens” en verlagen de score niet. Het aantal aanvallen van vandaag wordt op het dashboard getoond, maar heeft geen invloed op de beveiligingsscore.

Instellingen en licentie

05. WebAuthn — tweefactorauthenticatie

WebAuthn is een standaard voor authenticatie zonder wachtwoord via een hardwaresleutel. Ondersteunt YubiKey, Touch ID, Face ID, Windows Hello, Passkey.

Na het inloggen met een wachtwoord vraagt het systeem om bevestiging via een geregistreerde sleutel. Zelfs als het wachtwoord uitlekt, is inloggen zonder de fysieke sleutel of biometrie onmogelijk.

Open om dit in te stellen WebAuthn-sleutels in het zijmenu en klik op “Sleutel registreren”. Registreer meteen twee sleutels: als uw enige sleutel verloren gaat of kapot raakt, is inloggen op het dashboard daarmee onmogelijk.

WebAuthn werkt alleen via HTTPS. Op een HTTP-verbinding zijn registratie en inloggen met een sleutel niet beschikbaar.

06. Meldingen: Telegram en Email

Het dashboard kan een beveiligingsrapport naar Telegram en e-mail sturen (via een knop en volgens schema). In te stellen in het onderdeel “Instellingen”.

Telegram. U hebt een bot-token en chat id nodig:

  1. Schrijf in Telegram naar @BotFather/newbot → ontvang een token in de vorm 123456:ABC....
  2. Stuur uw nieuwe bot een willekeurig bericht (zodat hij u kan antwoorden).
  3. Zoek uw chat id op: schrijf naar de bot @userinfobot, of open https://api.telegram.org/bot<TOKEN>/getUpdates en zoek naar "chat":{"id":...}.
  4. Plak het token en de chat id in “Instellingen” → Telegram en klik op “Opslaan en test versturen”.

Email. Twee methoden naar keuze in “Instellingen” → Email:

  • SMTP — host, poort (465/SSL of 587/TLS), gebruikersnaam en wachtwoord van uw mailbox;
  • Resend — moderne API: geef een API-sleutel op (re_...) en een geverifieerd afzenderdomein.
De knop “Test versturen” controleert het kanaal meteen. Het schema van het automatische rapport loopt via cron (onderdeel “Alle cron-taken”): cron start de verzending en de kanalen worden uit de instellingen gehaald.

Rapportstatus: “LET OP” of “OK”. De titel wordt alleen “LET OP” bij een echt probleem of een openstaande actie: een ClamAV-dreiging gevonden, bestandswijzigingen in AIDE, kritieke Falco-gebeurtenissen (Emergency/Alert/Critical in de laatste 24 u), een gecrashte service in Monit, herstart vereist, verlopend SSL (≤14 dagen) of wachtende beveiligingsupdates. Achtergrondruis — SSH-bruteforce door bots, door fail2ban geblokkeerde IP-adressen, Suricata-alerts, Lynis-waarschuwingen en reeds afgeslagen ModSecurity-verzoeken — verhoogt de status niet, dus zulke cijfers in het rapport betekenen op zichzelf geen “LET OP”.

07. Licentie — invoeren en activeren

Gedetailleerde monitoringmodules (Lynis, UFW, ModSecurity, aanvalskaart, AIDE, ClamAV enz.) worden ontgrendeld met een geldige licentie. Zonder licentie werken het dashboard, de instellingen en het account, maar tonen de modules de kaart “Licentie vereist”.

Na aankoop in uw account beschikt u over een activatiecode in de vorm ARCIVEO-XXXX-XXXX-XXXX-XXXX. Deze moet u “activeren” voor het domein van uw paneel — dat zet de code om in een ondertekend licentiebestand (blok [license]) dat u in het paneel plakt.

Zo activeert u (3 stappen):

  1. Pak de activatiecode. Account my.arciveo.com → onderdeel “Licenties” / “Licentieactivatie” — kopieer de code ARCIVEO-….
  2. Activeer de code voor uw domein. Open in datzelfde account “Licentieactivatie” en voer in: activatiecode, uw e-mailadres en domein van het paneel (het adres waarop de monitor opent, bijv. monitor.example.com). Klik op activeren — het systeem genereert een licentiebestand dat aan dit domein gekoppeld is en toont het in een veld met de knop “Kopiëren”.
  3. Plak de sleutel in het paneel. Kopieer de volledige licentietekst → open in het paneel “Instellingen” → blok “Licentie”, plak en klik op “Opslaan”. De modules worden meteen ontgrendeld.

Het paneel controleert de sleutel cryptografisch: handtekening, domeinkoppeling en geldigheidsduur.

Het domein bij activatie moet exact overeenkomen met het adres van het paneel. Neem het uit de constante APP_URL in config.php en voer alleen de hostnaam in — zonder https:// en zonder www-prefix. Activatie is eenmalig: de code wordt een licentie voor het ingevoerde domein en kan niet opnieuw worden geactiveerd — bij een fout in het domein past de sleutel niet bij uw paneel en is de code verbruikt. Voer het domein daarom zorgvuldig in.
Is de geldigheid verlopen of is het domein gewijzigd — dan verschijnt er een waarschuwing in de kop van het paneel. De licentie is permanent aan het domein gekoppeld en wordt niet overgedragen naar een ander domein: voor een nieuwe termijn of een nieuw domein hebt u een nieuwe sleutel nodig (te koop in uw account en eenmalig te activeren).

08. Bestand config.php — alle instellingen van het dashboard

Alle belangrijke parameters van het dashboard staan in één bestand config.php in de root (naast de map public/) als gewone define()-constanten. Het bestand wordt bij de installatie aangemaakt; het handmatig bewerken is zelden nodig — meestal bij het wijzigen van het domein, een verhuizing of het koppelen aan een andere database. Na elke wijziging PHP-FPM opnieuw starten (anders worden de wijzigingen door OPcache niet toegepast).

Vul uw eigen waarden in op de gemarkeerde plekken; laat de rest zoals die is:

// --- Database --- define('DB_HOST', 'localhost'); // laten staan define('DB_NAME', 'db_name'); // wat u bij het aanmaken van de DB hebt opgegeven define('DB_USER', 'user'); // wat u bij het aanmaken van de DB hebt opgegeven define('DB_PASS', 'db_password'); // wat u bij het aanmaken van de DB hebt opgegeven define('DB_CHARSET', 'utf8mb4'); // laten staan // --- Applicatie --- define('APP_URL', 'https://monitor.example.com'); // adres van het dashboard, zonder slash aan het eind define('TIMEZONE', 'Europe/Amsterdam'); // uw tijdzone // --- Sessieduur --- define('SESSION_LIFETIME', 28800); // inactiviteit tot opnieuw inloggen, sec (28800 = 8 u)

Database. Verbindingsgegevens voor MySQL/MariaDB:

  • DB_HOST — host van de DBMS, bijna altijd localhost;
  • DB_NAME — naam van de database van het dashboard;
  • DB_USER — DB-gebruiker (toegang alleen tot de eigen database);
  • DB_PASS — wachtwoord van deze gebruiker;
  • DB_CHARSET — tekenset van de verbinding, laat utf8mb4 staan.

Applicatie.

  • APP_URL — volledig adres van het dashboard (bijv. https://monitor.example.com). Moet overeenkomen met het domein waarvoor de licentie is geactiveerd — anders wordt de sleutel geweigerd (zie het onderdeel “Licentie”);
  • TIMEZONE — tijdzone van PHP: beïnvloedt alleen hoe het dashboard datums en tijden toont. Op de uitvoertijd van cron-taken heeft dit geen invloed — daar geldt de systeemtijdzone (zie “Alle cron-taken”).

Sessieduur. SESSION_LIFETIME — time-out voor inactiviteit van de sessie in seconden (voortschrijdend: wordt bij activiteit vernieuwd). Standaard 28800 = 8 uur; na deze inactiviteitsduur vraagt het dashboard om opnieuw in te loggen. Bijvoorbeeld 3600 = 1 uur, 86400 = een etmaal.

Foutregistratie. Fouten worden nooit aan bezoekers getoond, maar weggeschreven naar logs/php_errors.log — ze zijn zichtbaar op de pagina “Applicatielogs”. Deze regels (display_errors=0, log_errors=1, pad error_log) hoeft u meestal niet te wijzigen — de instellingen staan direct in het bestand en zijn niet afhankelijk van php.ini.

config.php is een geheim bestand. Het bevat het DB-wachtwoord. Het staat in de root van het dashboard (naast public/), en de webroot (DocumentRoot) van dit dashboard is juist de root van het dashboard, niet public/. Het bestand “lekt” op zichzelf niet: in de .htaccess in de root staat er een expliciet verbod voor (Require all denied) — de server geeft 403 terug. Zelfs zonder deze regel zou de broncode niet lekken: dit is PHP — de server voert het uit en geeft het niet als tekst terug. Voor de zekerheid: plaats het niet in openbare repositories en stuur het niet met een echt wachtwoord naar de ondersteuning. Bestandsrechten — 640.
Bij een verhuizing of het herstellen van toegang is dit bestand de belangrijkste bron van gegevens: de DB-naam, gebruiker en wachtwoord komen juist hiervandaan (zie de onderdelen “Dashboard bijwerken en verhuizen” en “Toegang herstellen”).

Beveiligingstools

09. UFW-firewall

UFW (Uncomplicated Firewall) is een eenvoudige interface voor nftables/iptables. Sluit alle inkomende poorten af behalve die expliciet zijn toegestaan. De pagina “UFW-firewall” toont de status en regels.

sudo apt install ufw # SSH toestaan (verplicht VÓÓR het inschakelen!) en web sudo ufw allow OpenSSH sudo ufw allow 80,443/tcp # DB van buitenaf afsluiten (alleen lokale toegang) sudo ufw deny 3306 # Inschakelen en controleren sudo ufw enable sudo ufw status verbose
Sta vóór ufw enable verplicht SSH toe (ufw allow OpenSSH), anders verliest u de toegang tot de server.
“Externe blootstelling” op het dashboard houdt rekening met UFW: een poort die door een deny-regel is afgesloten, geldt niet als extern bereikbaar.
Skipping adding existing rule is geen fout. Zo meldt UFW dat exact dezelfde regel al bestaat en niet opnieuw wordt toegevoegd. Bij een herhaalde uitvoering van de automatische configuratie (die idempotent is) is dit een normale melding — er is geen actie nodig.

10. Fail2ban installeren

Blokkeert automatisch een IP-adres na te veel mislukte aanmeldpogingen. Analyseert de logs van SSH, nginx, Apache en andere diensten.

sudo apt install fail2ban sudo systemctl enable --now fail2ban # Status controleren: sudo fail2ban-client status
Een werkende configuratie (jail.local met tientallen jails en autoban uit ipsum) vindt u in het volgende gedeelte.

11. Werkende configuratie Fail2ban + ipsum

De basisinstallatie staat hierboven. Hier vindt u een werkende configuratie die tientallen actieve jails en duizenden bans oplevert: algemene instellingen, belangrijke jails en het automatisch bannen van kwaadaardige IP's uit de lijst ipsum.

Het bestand /etc/fail2ban/jail.local — algemene instellingen en de belangrijkste jails:

[DEFAULT] bantime = 1w findtime = 900 maxretry = 3 backend = systemd banaction = nftables-multiport ignoreip = 127.0.0.1/8 ::1 <YOUR_IP> <TRUSTED_NETS> # Progressieve ban: elke herhaling duurt langer bantime.increment = true bantime.factor = 2 bantime.maxtime = 5w bantime.rndtime = 300 [sshd] enabled = true maxretry = 5 bantime = -1 # permanente ban voor SSH-bruteforce findtime = 3600 # Recidivisten: wie meerdere bans kreeg, wordt voorgoed gebannd [recidive] enabled = true logpath = /var/log/fail2ban.log banaction = %(banaction_allports)s bantime = -1 findtime = 86400 maxretry = 2 [http-get-dos] enabled = true maxretry = 100 findtime = 300 bantime = 1w # Webservices (apache-*, nginx-*, php-url-fopen, phpmyadmin-syslog): [nginx-http-auth] enabled = true port = http,https [apache-badbots] enabled = true port = http,https # … en de overige jails per service (dovecot, exim, postfix-sasl, # mysqld-auth, vsftpd, portscan, pam-generic) — enabled = true
Vul in ignoreip beslist uw eigen IP en vertrouwde netwerken in, anders kunt u uzelf bannen. Na wijzigingen: sudo fail2ban-client reload.

Het automatisch laden van de blokkeerlijst ipsum gaat via de root-cron (sudo crontab -e): level 1 (100.000+ IP's) wordt geladen in de set ipsum, die op de firewall wordt geblokkeerd (meer hierover in het gedeelte “IPset-blokkeerlijst”):

# 04:00 — bijwerken ipset ipsum (level 1, maximale dekking): 0 4 * * * /usr/local/bin/load-ipsum.sh >> /path/to/monitor/logs/cron.log 2>&1
De set moet ipsum heten — precies die wordt door het dashboard gelezen (kaart “IPset ipsum”). Levels: levels/1.txt — maximale dekking, levels/3.txt — nauwkeuriger (3+ bronnen).

Waarom de “Beveiligingsmonitor” in twee zones is verdeeld. De bescherming werkt op twee niveaus, en het dashboard vermengt ze niet:

  • Echte aanvallen (reactief) — alles wat fail2ban heeft opgevangen: actuele inbraakpogingen (jails sshd, apache-*, nginx-* enz.) en hardnekkige recidivisten (jail recidive — degenen die al meerdere keren gebannd zijn). Dit zijn IP's die echt bij u probeerden in te breken — ze staan op de aanvalskaart en de “Tijdlijn”.
  • Preventieve blokkering (proactief) — de publieke blokkeerlijst van bekende kwaadaardige IP's ipset ipsum, die op de firewall met een DROP-regel wordt geblokkeerd. Deze adressen hebben uw server in de meeste gevallen niet eens geraakt — ze worden vooraf afgesneden; de teller “IPset ipsum” toont hoeveel er preventief zijn afgesneden.

Het verschil is simpel: reactief — “deze vielen aan en werden gebannd”, preventief — “deze werden geblokkeerd nog vóór de poging”. Vroeger werd list-3 ipsum kunstmatig in recidive gedreven (vandaar de oude indeling “lijst-recidivisten”); nu bevat recidive alleen echte recidivisten, en de preventie draait volledig op de firewall.

12. Blokkeerlijst IPset (ipsum)

ipsum — een publieke lijst met kwaadaardige IP's, die dagelijks wordt bijgewerkt. De monitor toont het aantal geladen adressen op het dashboard en de aanvalskaart en verrekent dit in de beveiligingsscore (−10 als de set niet is geladen).

Een minimale variant zonder fail2ban — een aparte set ipsum met blokkering via iptables:

# Set aanmaken (eenmalig): sudo ipset create ipsum hash:ip # Updatescript /usr/local/bin/update-ipsum.sh: #!/bin/bash ipset flush ipsum for ip in $(curl -s https://raw.githubusercontent.com/stamparm/ipsum/master/levels/3.txt); do ipset add ipsum "$ip" 2>/dev/null done iptables -C INPUT -m set --match-set ipsum src -j DROP 2>/dev/null \ || iptables -I INPUT -m set --match-set ipsum src -j DROP # Cron (sudo crontab -e, dagelijks om 4:00): 0 4 * * * /usr/local/bin/update-ipsum.sh
De uitgebreide variant met fail2ban-recidive — in de sectie “Werkende configuratie Fail2ban + ipsum”.
ipset leeft in het geheugen en gaat verloren bij een herstart. Alleen een dagelijkse cron laat de set leeg vanaf de reboot tot de volgende run (het dashboard toont 0). Laad de set ook bij het opstarten — verplaats het laden naar een script en koppel het aan @reboot. Meteen stelt het commando create … -exist de limiet maxelem 300000 in (standaard 65536 — level 1 past er niet in, dan krijgt u “Hash is full”):
# /usr/local/bin/load-ipsum.sh #!/bin/bash curl -s https://raw.githubusercontent.com/stamparm/ipsum/master/levels/1.txt \ | grep -v '^#' | sed 's/^/add ipsum /' \ | (echo "create ipsum hash:ip hashsize 131072 maxelem 300000 -exist"; echo "flush ipsum"; cat) \ | ipset restore -exist # sudo crontab -e — dagelijks om 04:00 EN bij elke start: 0 4 * * * /usr/local/bin/load-ipsum.sh @reboot sleep 60 && /usr/local/bin/load-ipsum.sh
Hoe het werkt bij automatische installatie. Het script laadt de volledige lijst level 1 (100+ duizend IP's) in de set ipsum en, als de firewall wordt beheerd door de installer (verse VPS — profielen “Volledig”/“Lichtgewicht”), koppelt het de set aan UFW met een DROP-regel — verkeer van deze IP's wordt daadwerkelijk geblokkeerd. De regel staat na ESTABLISHED,RELATED, zodat bestaande verbindingen (waaronder uw SSH) niet worden verbroken — alleen nieuwe verbindingen uit de lijst worden afgekapt. De set wordt hersteld bij het laden van de service ipsum-load.service vóór de firewall (anders zou UFW niet opstarten), en wordt bijgewerkt door de cron om 04:00. Op een reeds geconfigureerde server (paneel, eigen firewall) raakt de installer de firewall niet aan — daar blijft ipsum een lijst voor het dashboard en de aanvalskaart, en de DROP-regel wordt desgewenst handmatig toegevoegd (de minimale variant met iptables … --match-set ipsum … -j DROP — hierboven). Bij automatische installatie hoeft u handmatig niets te doen.

13. CrowdSec installeren

Moderne vervanging voor Fail2ban met collectieve threat intelligence: blokkeringen van de community plus eigen regels. Vereist een aparte bouncer om blokkeringen op de firewall toe te passen.

curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash sudo apt install crowdsec sudo systemctl enable --now crowdsec # Bouncer voor iptables/nftables: sudo apt install crowdsec-firewall-bouncer-iptables # Status controleren: sudo systemctl status crowdsec sudo cscli decisions list sudo cscli bouncers list
Status “Niet actief” in het dashboard = de service is geïnstalleerd, maar de dienst is niet actief (de monitor controleert dit via systemctl is-active crowdsec). Starten: sudo systemctl enable --now crowdsec; bij een crash kijkt u naar sudo journalctl -u crowdsec -n 30. Dezelfde regel geldt voor elke service met de status “Niet actief” (Suricata, Falco, Monit, MySQL).
“0 scenario's” of “0 bouncers” op het dashboard. CrowdSec is standaard vrijwel leeg — zonder collecties detecteert het niets, en zonder een geregistreerde bouncer worden blokkeringen niet op de firewall toegepast. Installeer de basiscollecties en controleer of de bouncer in de lijst staat:
# Basiscollecties (Linux + SSH + webserver): sudo cscli collections install crowdsecurity/linux crowdsecurity/sshd crowdsecurity/base-http-scenarios sudo systemctl reload crowdsec # Bouncer moet in de lijst staan met de status actieve verbinding: sudo cscli bouncers list
In het bouncer-log stream halted / blokkeringen worden niet toegepast. Dit is een verweesde api-sleutel: de bouncer is verwijderd uit cscli bouncers list, maar zijn oude sleutel bleef in /etc/crowdsec/bouncers/*.yaml. Registreer de bouncer opnieuw en zet de nieuwe sleutel erin:
sudo cscli bouncers add fw-bouncer # geeft een nieuwe api_key # zet deze sleutel in api_key: in /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml sudo systemctl restart crowdsec-firewall-bouncer
De automatische installatie (profiel “Volledige bescherming”) installeert zelf de collecties en registreert de firewall-bouncer — handmatig is dit alleen nodig bij een handmatige installatie of na handmatig ingrijpen in CrowdSec.

14. AIDE installeren

AIDE (Advanced Intrusion Detection Environment) maakt een momentopname van het bestandssysteem en meldt bij elke controle wijzigingen in /etc, /bin, /usr. Na de installatie is initialisatie van de database (aideinit) verplicht.

sudo apt install aide # Database initialiseren (5–15 minuten): sudo aideinit sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db # Ubuntu 24.04: de map /var/lib/aide wordt aangemaakt met modus 700 (eigenaar _aide), # en het paneel (www-data) ziet de database niet → toont “Niet geïnitialiseerd”. # Geef de map doorloop-toegang (databasebestanden blijven 600): sudo chmod 755 /var/lib/aide # Eerste controle MET SCHRIJVEN naar de log die de monitor leest. # Op Ubuntu/Debian vereist aide een expliciete --config (anders “missing configuration”; # de binary aide.wrapper wordt in nieuwe versies niet meer meegeleverd): sudo bash -c 'aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1'
Tijdens aideinit blijft de terminal 5–15 minuten op de regel Running aide --init... staan — dat is normaal (hashing van het hele bestandssysteem, schijfbelasting). Onderbreek niet met Ctrl+C. Als het proces “blijft hangen” maar niets schrijft, wacht het mogelijk op een verborgen prompt Overwrite existing aide.db.new [Yn]? (druk op Y). Controleer de activiteit vanuit een andere sessie: pgrep -af aide.
Fout aideinit: “21_aide_spamassassin … printf: invalid number” (return code 20) — een bekende bug in het AIDE-configuratiesnippet in Ubuntu 22.04. De database wordt niet aangemaakt. Verplaats het defecte snippet en probeer opnieuw:
sudo mv /etc/aide/aide.conf.d/21_aide_spamassassin /etc/aide/21_aide_spamassassin.disabled sudo aideinit sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
Statussen op het dashboard. “Niet geïnitialiseerd” = het paneel ziet het databasebestand niet: ofwel is aideinit niet uitgevoerd, ofwel (Ubuntu 24.04) is de map /var/lib/aide aangemaakt met modus 700 en niet toegankelijk voor www-data — op te lossen met sudo chmod 755 /var/lib/aide (zie het blok hierboven). “Geen controles” = de database bestaat, maar er is nog geen controle uitgevoerd — dit is geen fout. De monitor leest de resultaten uit /var/log/aide/aide.log.
Regelmatige controle → log voor het paneel. De standaard /etc/cron.daily/aide schrijft op nieuwe Ubuntu/Debian mogelijk niet /var/log/aide/aide.log in de vereiste vorm (en aide.wrapper zit er niet meer in). Betrouwbaarder is een eigen cron met expliciete --config — die schrijft de log als root in modus 644, en de monitor leest hem zonder extra groepen:
# sudo crontab -e — dagelijkse controle om 02:00: 0 2 * * * /usr/bin/aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1 # Nu uitvoeren zonder op het schema te wachten: sudo bash -c 'aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1'
Automatische installatie doet dit alles al: chmod 755 /var/lib/aide en een controle-cron om 02:00 — handmatig is niets nodig.
Voer de eerste initialisatie uit op een schone server — vóór de installatie van webapplicaties. Maak de database na legitieme wijzigingen opnieuw aan: sudo aideinit && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db.

15. ClamAV installeren

Antivirusscanner voor Linux. Vooral handig om /var/www te controleren op PHP-shells en kwaadaardige code.

sudo apt install clamav clamav-daemon sudo systemctl enable --now clamav-daemon # Signaturedatabase bijwerken: sudo freshclam # Map handmatig scannen: sudo clamscan -r /var/www --infected
Toont de clamd-daemon “Inactief” na enable --now? Drie typische oorzaken:

1. In de config staat nog de regel Example — clamd weigert te starten zolang die er staat:

sudo sed -i '/^Example/d' /etc/clamav/clamd.conf sudo systemctl restart clamav-daemon

2. De signaturedatabase is niet gedownload — clamd start niet zonder deze:

sudo systemctl stop clamav-freshclam sudo freshclam sudo systemctl start clamav-freshclam sudo systemctl restart clamav-daemon

3. Hij is gewoon aan het laden — clamd laadt ~8 mln signatures in 30–60 sec. in het geheugen. Wacht even en controleer: systemctl is-active clamav-daemon (status activating → nog aan het laden).

Diagnostiek: sudo journalctl -u clamav-daemon -n 30 --no-pager.
Op het dashboard “Bestanden gecontroleerd: 0” / “Laatste scan: —”? De clamd-daemon houdt alleen signatures in het geheugen, zelf scant hij niets volgens een schema. Het paneel toont de resultaten van een geplande scan, dus u hebt een cron nodig die scant en een log schrijft. De automatische installatie plaatst de wrapper /usr/local/bin/clamav-scan.sh en een cron om 01:30 — na de eerste run worden “Bestanden gecontroleerd” en “Laatste scan” gevuld. Meteen starten zonder op het schema te wachten: sudo /usr/local/bin/clamav-scan.sh.

16. Linux Malware Detect (maldet) installeren

Linux Malware Detect (LMD) — malwarescanner voor webdreigingen: PHP-shells, web-backdoors, loaders. Gebruikt de ClamAV-engine en vult die aan met eigen signatures.

wget https://www.rfxn.com/downloads/maldetect-current.tar.gz tar -xzf maldetect-current.tar.gz dir=$(ls -d maldetect-*/ | head -1) && cd "$dir" && sudo bash install.sh && cd ~ rm -rf maldetect-* maldetect-current.tar.gz # Signatures bijwerken: sudo maldet -u # /var/www scannen: sudo maldet -a /var/www
LMD en ClamAV werken goed samen. Laatste rapport: maldet --report.
Bij de installatie kan de regel update-rc.d: error: unable to read /etc/init.d/maldet verschijnen — die is onschadelijk. maldet gebruikt geen init.d; het bijwerken van signatures en de scans worden gestart via /etc/cron.daily/maldet. Als u onderaan installation completed ziet, is alles geïnstalleerd.
Toont LMD op de pagina “Niet geïnstalleerd” terwijl het wel geïnstalleerd is? maldet wordt niet via apt geïnstalleerd, maar in /usr/local/maldetect, en bij ingeschakelde open_basedir wordt de aanwezigheid via de shell gecontroleerd — zie het hoofdstuk “De pagina is leeg terwijl er wel gegevens op de server zijn”.

17. Suricata installeren

Netwerkgebaseerd inbraakdetectiesysteem: analyseert verkeer op pakketniveau en kent duizenden aanvalssignaturen. Vult ModSecurity aan (die werkt op HTTP-niveau, Suricata op TCP/IP-niveau).

sudo add-apt-repository ppa:oisf/suricata-stable sudo apt update && sudo apt install suricata # Actuele regels downloaden: sudo suricata-update sudo systemctl enable --now suricata
Suricata is “Actief”, maar het dashboard toont geen meldingen / aantal gebeurtenissen is 0? Suricata schrijft /var/log/suricata/eve.json als root met modus 750 op de map, en de webserver (www-data) kan hem niet lezen. Geef de map doorloop-rechten — de bestanden erin blijven beschermd:
sudo chmod o+rx /var/log/suricata
De automatische installatie doet dit zelf — handmatig is niet nodig.

18. Falco installeren

Onderschept system calls via eBPF/kernel module en detecteert anomalieën in realtime: een shell vanuit nginx, het lezen van /etc/passwd door een webproces, schrijven naar /bin enz.

curl -fsSL https://falco.org/repo/falcosecurity-packages.asc > /tmp/falco.asc gpg --dearmor < /tmp/falco.asc | sudo tee /usr/share/keyrings/falco-archive-keyring.gpg > /dev/null sudo chmod 644 /usr/share/keyrings/falco-archive-keyring.gpg && rm /tmp/falco.asc echo "deb [signed-by=/usr/share/keyrings/falco-archive-keyring.gpg] https://download.falco.org/packages/deb stable main" \ | sudo tee /etc/apt/sources.list.d/falcosecurity.list sudo apt update && sudo apt install falco sudo systemctl enable --now falco
De monitor leest Falco-gebeurtenissen via journalctl -u falco (zonder sudo — via de groep systemd-journal). Zorg dat www-data in deze groep zit — zie “sudo instellen” (punt 2) op de pagina voor handmatige installatie.
“0 gebeurtenissen in 24 uur” is normaal, geen fout. Falco is event-driven: het blijft stil zolang alles in orde is en registreert pas een gebeurtenis bij een anomalie (een shell vanuit een webproces, het lezen van /etc/passwd, schrijven naar systeemmappen). Nul kritieke gebeurtenissen op een dag op een rustige server is een gezonde toestand.
Voor het dashboard is bestandsuitvoer betrouwbaarder. Lezen via journalctl vereist rechten op het logboek; om ervoor te zorgen dat het dashboard gebeurtenissen stabiel ziet, schakelt de automatische installatie bij Falco file_output/var/log/falco/falco.log in en stelt de service UMask=0022 in (het log wordt door de webserver gelezen). Bij een nieuwe installatie hoeft u dit niet handmatig te configureren.

19. ModSecurity (WAF) installeren

ModSecurity — een webfirewall (WAF) voor Apache of Nginx. Blokkeert aanvallen op applicatieniveau: SQL-injecties, XSS, path traversal, scanners.

# Apache: sudo apt install libapache2-mod-security2 sudo a2enmod security2 # OWASP Core Rule Set-regelset: sudo apt install modsecurity-crs # VERPLICHT: zonder dit bestand is de regel-engine uitgeschakeld sudo cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf sudo sed -i 's/^SecRuleEngine DetectionOnly/SecRuleEngine On/' /etc/modsecurity/modsecurity.conf sudo apache2ctl configtest && sudo systemctl reload apache2 # Controle: moet 403 teruggeven curl -s -o /dev/null -w '%{http_code}\n' "https://monitor.example.com/?id=1%20UNION%20SELECT%201,2--"
Het pakket installeren beschermt op zichzelf niets. Apache laadt de configs via de regel IncludeOptional /etc/modsecurity/*.conf, maar het pakket plaatst alleen modsecurity.conf-recommended — dat valt niet onder het masker *.conf. Als u het niet naar modsecurity.conf kopieert, blijft SecRuleEngine op Off: de module is geladen, de CRS-regels zijn geladen, maar het verkeer wordt niet gecontroleerd en er wordt geen audit-log aangemaakt. De tussenstand DetectionOnly schrijft alleen gebeurtenissen naar het log zonder verzoeken te blokkeren — het paneel toont dit geel.

Toegang van het paneel tot het audit-log. Het log /var/log/apache2/modsec_audit.log is eigendom van root (rechten 640); de webgebruiker kan het niet lezen. Het paneel haalt de gegevens op via een wrapper — maak die aan:

sudo tee /usr/local/bin/monitor-modsec >/dev/null <<'EOF' #!/bin/sh echo "ENGINE=$(grep -hE '^SecRuleEngine[[:space:]]+' /etc/modsecurity/*.conf 2>/dev/null | tail -1 | awk '{print $2}')" echo "---LOG---" tail -n 3000 /var/log/apache2/modsec_audit.log 2>/dev/null echo "---RULES---" for f in /etc/modsecurity/crs/rules/*.conf /usr/share/modsecurity-crs/rules/*.conf /etc/modsecurity/custom-rules.conf; do [ -f "$f" ] && { echo "===FILE:$(basename "$f")==="; cat "$f"; } done EOF sudo chown root:root /usr/local/bin/monitor-modsec sudo chmod 755 /usr/local/bin/monitor-modsec # in /etc/sudoers.d/monitor (gebruiker = degene waaronder PHP-FPM draait): # www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-modsec
De wrapper neemt de laatste SecRuleEngine-directive zonder inspringing: ingesprongen regels staan binnen <LocationMatch>/<Directory>-blokken (bijvoorbeeld het uitschakelen van de WAF voor phpMyAdmin) en bepalen de globale modus niet.
De gebruiker in sudoers moet overeenkomen met de gebruiker van de FPM-pool: op een gewone Apache/Debian is dat www-data, in HestiaCP draait de sitepool onder de site-eigenaar (bijvoorbeeld admin) — controleer met grep -E '^user' /etc/php/*/fpm/pool.d/monitor.example.com.conf.
Als de site achter een Nginx-proxy staat (HestiaCP), ziet Apache de proxy zelf als client — het paneel haalt het echte IP-adres van de aanvaller uit de header X-Forwarded-For. Alleen transacties met een geactiveerde regel komen in de statistieken: de directive SecAuditLogRelevantStatus schrijft alle 4xx/5xx-antwoorden naar het audit-log, dus komen ook gewone 403/500 daarin terecht — het paneel telt die niet als WAF-gebeurtenissen.
Het blok ---RULES--- is nodig voor het onderdeel “Alle actieve regels” — het paneel toont niet alleen de geactiveerde, maar alle geladen CRS-regels + aangepaste regels. De drie paden in de lus for f in … zijn de typische plekken voor CRS-regels en lokale aanvullingen; hebt u een andere indeling (het pakket plaatst bestanden in zijn eigen map, of de aangepaste regels staan niet in /etc/modsecurity/custom-rules.conf), zoek dan de werkelijke paden met het commando sudo grep -rl 'IncludeOptional\|^Include ' /etc/apache2/mods-enabled/security2.conf /etc/apache2/conf-enabled/*.conf 2>/dev/null en zet ze in de lijst. Is de wrapper oud (zonder dit onderdeel), dan toont het onderdeel simpelweg de waarschuwing “niet beschikbaar”; de rest van de pagina werkt zoals voorheen.

20. Auditd installeren

Auditd (Linux Audit Daemon) registreert systeemaanroepen op kernelniveau: aan- en afmeldingen, sudo-opdrachten, mislukte authenticatiepogingen, bestandswijzigingen. De monitor toont aanmeldingen, mislukte pogingen en sudo-opdrachten van vandaag.

sudo apt install auditd audispd-plugins sudo systemctl enable --now auditd # Status en gebeurtenissen controleren: sudo systemctl status auditd sudo ausearch -m USER_LOGIN -ts today
De monitor leest gebeurtenissen via ausearch (/usr/sbin/ausearch) en indien nodig uit /var/log/audit/audit.log met het commando tail. Beide moeten in sudoers staan.

21. Monit installeren

Bewaakt services (nginx, php-fpm, mysql enz.) en herstart ze bij een crash. Kan meldingen sturen naar e-mail.

sudo apt install monit sudo systemctl enable --now monit # Configuratiebestanden: sudo nano /etc/monit/monitrc ls /etc/monit/conf.d/
De monitor haalt de servicelijst op via monit status. In /etc/monit/monitrc moet de HTTP-interface ingeschakeld zijn (blok set httpd met allow localhost), anders geeft monit status een fout.
“0 services onder toezicht” op het dashboard? Twee oorzaken. (1) De HTTP-interface staat uit — in monitrc is de regel set httpd uitgecommentarieerd (standaard staat die als # set httpd port 2812 …). Verwijder het commentaarteken bij het blok en sta localhost toe. (2) Een ingeschakelde httpd bewaakt op zichzelf niets — Monit telt alleen wat met check-stanza's is beschreven; zonder die is de lijst leeg, zelfs met een werkende interface. Minimale werkende configuratie:
# /etc/monit/conf.d/00-httpd — HTTP-interface voor localhost: set httpd port 2812 use address localhost allow localhost # voorbeelden van check-stanza's (wat te bewaken): check process sshd with pidfile /run/sshd.pid start program = "/usr/bin/systemctl start ssh" stop program = "/usr/bin/systemctl stop ssh" check filesystem rootfs with path / if space usage > 90% then alert
sudo monit -t # syntaxis controleren (Control file syntax OK) sudo systemctl reload monit sudo monit status
De automatische installatie plaatst een kant-en-klare conf.d met httpd op 2812 en een set controles — op een nieuwe installatie hoeft u niets handmatig in te stellen.
Service met status “Met fouten”? De monitor toont alleen de status en herstart services bewust niet vanuit het webpaneel (dat zou externe uitvoering van root-commando's in een beveiligingspaneel zijn). Diagnostiek en herstart gaan via SSH met Monit:
sudo monit status <service> # oorzaak van de fout sudo monit restart <service> # herstart via Monit # als Monit de service niet opstart — bekijk zijn eigen unit: sudo systemctl status <unit> --no-pager sudo journalctl -u <unit> -n 50 --no-pager

22. PSAD installeren (detectie van poortscans)

PSAD analyseert het iptables-logboek en detecteert poortscans en netwerkaanvallen, waarbij elke bron een dreigingsniveau (1–5) krijgt. Vult fail2ban en Suricata aan.

sudo apt install psad # PSAD leest het iptables-log — logging moet aanstaan (UFW doet dit zelf). # Voeg voor kaal iptables LOG-regels toe aan de INPUT/FORWARD-ketens. sudo psad --sig-update sudo systemctl enable --now psad
De monitor leest gegevens via psad --Status (vereist in sudoers). Zonder iptables-logging blijft de pagina leeg — dat is normaal zolang er geen scans zijn geweest.

23. AppArmor / SELinux (toegangscontrole)

Mandatory Access Control beperkt tot welke bestanden en bronnen een programma toegang heeft, zelfs als het gehackt is. In Ubuntu/Debian wordt standaard AppArmor gebruikt (meestal al geïnstalleerd en actief).

# AppArmor (Ubuntu/Debian): sudo apt install apparmor apparmor-utils sudo systemctl enable --now apparmor sudo aa-status # profielen controleren
De monitor leest de status via aa-status (moet in sudoers staan). Toont het aantal profielen in de modus enforce/complain en processen zonder profiel.

“Profielen geladen” is meer dan enforce + complain — dat is normaal. In AppArmor 4.x (Ubuntu 24.04 en nieuwer) is de modus unconfined geïntroduceerd: het profiel is in de kernel geladen, maar beperkt niets. Ubuntu markeert zo tientallen profielen voor programma's die user namespaces gebruiken (browsers, torrent-clients en dergelijke). Wanneer zulke profielen aanwezig zijn, wordt de kaart “Profielen geladen” amberkleurig en toont hun aantal — bijvoorbeeld unconfined: 90 bij 120 geladen en 26 in enforce. Alleen profielen in enforce beschermen daadwerkelijk; op Ubuntu 22.04 (AppArmor 3.x) bestaat deze modus niet en kloppen de cijfers altijd.

sudo aa-status | grep -E "profiles are" # uitsplitsing per modus sudo aa-enforce /etc/apparmor.d/profile-name # profiel naar enforce zetten
Profielen die Ubuntu bewust in unconfined heeft gelaten, moet u alleen weloverwogen naar enforce zetten: ze zijn niet per abuis uitgeschakeld, maar omdat de programma's zelf anders stukgaan. Profielen in complain zijn een ander geval: daar zijn de regels al geschreven en worden ze alleen niet toegepast.

24. debsums installeren (integriteit van pakketten)

debsums controleert of de bestanden van geïnstalleerde pakketten overeenkomen met de controlesommen uit de repository — het spoort vervangen systeembinaries op (een aanvulling op AIDE). Een volledige controle duurt 1–2 minuten en wordt daarom via cron uitgevoerd; de dashboard leest het resultaat uit data/debsums/debsums.log en verdeelt het zelf over categorieën (alleen binaries en bibliotheken zijn belangrijk).

De taak staat in de root-cron (sudo crontab -e). De kant-en-klare wrapper debsums-scan.sh wordt in /usr/local/bin/ geplaatst (chmod +x; zie het overzicht van cron-taken) en schrijft zelf een rapport naar data/debsums/ van de dashboard.

sudo apt install debsums # Cron-regel (dagelijks 4:30): 30 4 * * * /usr/local/bin/debsums-scan.sh >> /path/to/monitor/logs/cron.log 2>&1

De wrapper debsums-scan.sh vindt zelf de data/ van de dashboard — u hoeft geen pad in te vullen.

Wijzigingen in /etc/ (configuraties) en /usr/share/ (bronbestanden) op de server zijn meestal normaal — de dashboard markeert deze met een aparte kleur. Zorgwekkend zijn wijzigingen aan binaries en bibliotheken (/bin, /sbin, /usr/lib enz.) — de kaart “Binaries / bibliotheken” toont precies die.

25. Lynis-rapporten instellen

Lynis start handmatig of via cron. Het rapport moet worden opgeslagen in de map data/lynis/ van het project — de monitor leest het bestand lynis-report.dat.

# Eenmalige uitvoering (vul uw eigen pad naar de dashboardroot in): sudo lynis audit system --report-file /path/to/monitor/data/lynis/lynis-report.dat # Dagelijkse audit — cron-regel (kant-en-klare wrapper lynis-scan.sh in /usr/local/bin/, zie overzicht): 0 3 * * * /usr/local/bin/lynis-scan.sh >> /path/to/monitor/logs/cron.log 2>&1
Na de eerste uitvoering toont de pagina “Lynis-audit” meteen de hardening index, waarschuwingen en aanbevelingen.
Knop “Audit starten” op de Lynis-pagina. Deze start lynis-scan.sh op de achtergrond rechtstreeks vanuit het dashboard (zonder op cron te wachten): toont “Scannen…” en werkt na afloop zelf het rapport bij. Hiervoor heeft de webgebruiker een sudoers-regel nodig om het script uit te voeren — het installatieprogramma voegt die automatisch toe aan /etc/sudoers.d/monitor. Als het dashboard handmatig/eerder is geïnstalleerd, voeg die dan toe met dezelfde gebruiker die al in het bestand staat:
u=$(sudo awk '/NOPASSWD/ && !/lynis-scan/ {print $1; exit}' /etc/sudoers.d/monitor) [ -n "$u" ] && echo "$u ALL=(ALL) NOPASSWD: /usr/local/bin/lynis-scan.sh" | sudo tee -a /etc/sudoers.d/monitor sudo visudo -c && sudo chmod 440 /etc/sudoers.d/monitor

26. Logwatch-rapporten instellen

Logwatch moet dagelijkse rapporten opslaan in de projectmap data/logwatch/ in het formaat .txt. De monitor toont het laatste rapport en het archief.

# Dagelijks (6:00) — cron-regel (kant-en-klare wrapper logwatch_daily.sh in /usr/local/bin/, zie overzicht): 0 6 * * * /usr/local/bin/logwatch_daily.sh >> /path/to/monitor/logs/cron.log 2>&1

Dashboardmodules

27. Netwerkmonitor (ingebouwd)

De netwerkmonitor hoeft niet te worden geïnstalleerd — het is een ingebouwde pagina van het dashboard. Deze toont de netwerkstatus van de server uit lokale bronnen:

  • interfaces en verkeer — uit /proc/net/dev;
  • linkstatus (UP/DOWN) en IP — via ip;
  • verbindingen en luisterende poorten — via ss;
  • netwerkgebeurtenissen van de kernel over 24 u — via journalctl -k.

De eerste drie bronnen werken zonder sudo, dus interfaces, verkeer, verbindingen en poorten zijn direct zichtbaar. Het blok “Kernelgebeurtenissen” gebruikt journalctl -k — dit wordt gelezen via de groep systemd-journal (“sudo instellen”, punt 2), sudo is niet nodig. Controleer of alles toegankelijk is voor de webgebruiker:

# Controle als www-data (hieronder draait PHP): sudo -u www-data bash -c 'cat /proc/net/dev' sudo -u www-data bash -c 'ip -o link show' sudo -u www-data bash -c 'ss -s' sudo -u www-data journalctl -k --no-pager -n 5
Het blok “Netwerkgebeurtenissen van de kernel” toont gebeurtenissen van de netwerkstack van de kernel (linkwijziging up/down, carrier-fouten, “network unreachable”). Firewall-vermeldingen UFW BLOCK komen hier niet in — die staan op de pagina's “UFW-firewall” en “Aanvalskaart”. Een leeg blok met een groen vinkje = geen netwerkstoringen in de afgelopen 24 uur.

28. Schijf en SMART

De ingebouwde pagina toont drie dingen:

  • Bestandssystemen — vulling van partities (df); de balk wordt rood bij ≥90%;
  • Opslagapparaten — lijst met schijven (lsblk), alleen echte (loop/snap verborgen);
  • Gezondheid (SMART) — schijfstatus en attributen (smartctl).

Ruimte en apparatenlijst werken meteen, zonder configuratie. Voor SMART is het pakket smartmontools nodig. Het webproces heeft geen directe toegang tot schijfapparaten, daarom wordt SMART via cron uitgelezen naar het bestand data/disk/smart.txt, dat het paneel vervolgens leest.

De taak staat in de root-cron (sudo crontab -e). De kant-en-klare wrapper smart-scan.sh plaatst u in /usr/local/bin/ (chmod +x; zie het overzicht van cron-taken) en schrijft zelf naar data/disk/ van het paneel.

sudo apt install smartmontools # Cron-regel (elke 30 minuten): */30 * * * * /usr/local/bin/smart-scan.sh >> /path/to/monitor/logs/cron.log 2>&1

De wrapper smart-scan.sh vindt zelf de data/ van het paneel — u hoeft geen pad op te geven. Intern sluit lsblk -e7,11 loop/cdrom uit.

Op virtuele schijven (QEMU/KVM en dergelijke) is doorgaans alleen de algemene status “gezondheid: OK” beschikbaar, terwijl temperatuur, bedrijfsuren en gerealloceerde sectoren leeg kunnen zijn — dat is normaal. Op een fysieke server worden alle attributen weergegeven.

29. Prestaties (CPU/RAM/Netwerk/Schijf)

De pagina toont de belastingsgeschiedenis van de server over de laatste 24 uur — Load Average, CPU-bezetting en I/O-wachttijd, RAM/Swap, netwerkverkeer (ontvangen/verzonden), schijf-I/O (lezen/schrijven), schijf- en inode-vulling, geopende bestandsdescriptoren en MySQL-verbindingen, plus het huidige aantal TCP-verbindingen en processen.

De gegevens verzamelt cron/collect_metrics.php — eens per 5 minuten wordt één “ruwe” momentopname van de tellers weggeschreven (/proc/loadavg, /proc/meminfo, /proc/stat, /proc/net/dev, /proc/diskstats, df/df -i, /proc/sys/fs/file-nr, SHOW GLOBAL STATUS LIKE 'Threads_connected') naar de databasetabel system_metrics; percentages en snelheden berekent de pagina zelf uit het verschil tussen naburige momentopnamen (schijf-/inode-/descriptorvulling/MySQL-verbindingen zijn momentwaarden, zonder herberekening). Sudo is niet vereist — de bronnen worden zonder rootrechten gelezen. Punten ouder dan 24 uur worden bij elke schrijfbewerking automatisch verwijderd.

# Cron-regel (elke 5 minuten): */5 * * * * /usr/local/bin/collect-metrics-all.sh >> /path/to/monitor/logs/cron.log 2>&1

De wrapper collect-metrics-all.sh (zie het overzicht van cron-taken) vindt zelf alle geïnstalleerde panelinstanties op de server en start voor elk de cron/collect_metrics.php onder de sitehouder.

Zolang de collector niet minstens tweemaal heeft gedraaid (de eerste ~10 minuten na installatie), toont de pagina “gegevens worden verzameld” — de grafieken hebben minstens één paar naburige punten nodig om snelheden en percentages te berekenen.

Belastingsmeldingen (onderdeel “Instellingen” → “Belastingsmeldingen”) — bij overschrijding van de drempel voor CPU/RAM/schijf/inodes stuurt het paneel een melding naar Telegram/Email (dezelfde kanalen als het dagelijkse rapport — die apart inschakelen voor meldingen is niet nodig), en nog een — wanneer de metriek weer normaal is. Tijdens het aanhouden van de drempel spamt het niet opnieuw: de volgende melding komt pas na een cyclus “hersteld → opnieuw overschreden”.

De drempels worden door dezelfde collect_metrics.php bij elke uitvoering gecontroleerd (eens per 5 minuten) — een aparte cron is niet nodig. De status “al gemeld / nog niet” wordt bewaard in data/alerts_state.json, de drempels in de panelinstellingen.

30. Aanvalskaart (GeoIP)

De pagina “Aanvalskaart” bepaalt het land op basis van het IP met het commando geoiplookup. Zonder het GeoIP-pakket worden landen niet bepaald en verschijnen er geen punten op de kaart:

sudo apt install geoip-bin geoip-database # Controle: geoiplookup 8.8.8.8
Sudo is niet vereist — de database /usr/share/GeoIP/GeoIP.dat is voor iedereen leesbaar en de resultaten worden gecachet in tmp/geoip_cache.json. De kaart zelf (Leaflet + OpenStreetMap-tegels) laadt in de browser — er is internet nodig op de computer waarop het dashboard is geopend.

31. Externe blootstelling, updates en automatische updates

Twee ingebouwde dashboardkaarten die niet “aan/uit” van een tool tonen, maar de werkelijke beveiliging van de server. Vereisen geen installatie en worden lokaal gelezen zonder sudo.

Externe blootstelling — hoeveel diensten op alle interfaces luisteren (0.0.0.0/[::]) en van buitenaf bereikbaar zijn. Markeert rood als een database of cache naar buiten toe openstaat (MySQL, PostgreSQL, Redis, MongoDB, Memcached, Elasticsearch) — dat is een direct lek (−10 op de beveiligingsscore). Bron: ss -tuln.

Is de kaart rood — sluit de database af voor de buitenwereld: bind hem aan 127.0.0.1 (bind-address in de MySQL/PostgreSQL-config, bind 127.0.0.1 in Redis) of sluit de poort in UFW.
“Open poort” ≠ “bereikbaar van buitenaf”. Een dienst die op 127.0.0.1 (loopback) luistert, is alleen voor de server zelf zichtbaar — van buitenaf kunt u er niet bij, ook al is de poort “open”. Daarom is Postfix op poort 25, gebonden aan loopback, veilig: de automatische configuratie zet inet_interfaces = loopback-only (plus een neutrale smtpd_banner — dit verhelpt de Lynis-opmerking MAIL-8818 over het tonen van de versie). De kaart “Externe blootstelling” telt naar buiten toe alleen wat op 0.0.0.0/[::] luistert; loopback-diensten tellen daar niet mee.
Lynis MAIL-8818 handmatig (als u de mail zelf hebt opgezet): stel in /etc/postfix/main.cf smtpd_banner = $myhostname ESMTP in (zonder versie en OS) en inet_interfaces = loopback-only, en daarna sudo systemctl restart postfix.

Beveiligingsupdates — hoeveel securitypatches op installatie wachten en of een herstart nodig is na een kernel-update (−5 op de beveiligingsscore als er patches zijn). Bron: /usr/lib/update-notifier/apt-check, bestand /var/run/reboot-required. De gedetailleerde lijst staat op de pagina “Beveiligingsupdates”.

# Updates installeren: sudo apt update && sudo apt upgrade # Controleren wat naar buiten toe luistert: ss -tuln | grep -E '0\.0\.0\.0|\[::\]'
De updatekaart werkt op Ubuntu/Debian (update-notifier-common). Ontbreekt apt-check — dan telt de monitor de patches via apt-get -s upgrade.

Automatische beveiligingsupdates (unattended-upgrades) — op de pagina “Beveiligingsupdates” toont een aparte kaart of de automatische installatie van securitypatches is ingeschakeld en wanneer die voor het laatst is uitgevoerd. Sudo is niet nodig — de status wordt gelezen via apt-config dump.

sudo apt install unattended-upgrades sudo dpkg-reconfigure -plow unattended-upgrades # inschakelen # Controleren wat is ingeschakeld: apt-config dump | grep Unattended-Upgrade

Onderhoud

32. Back-ups

Een back-up is uw belangrijkste vangnet: gegevensverlies is erger dan welke inbraak dan ook. U heeft twee dingen nodig — een back-up van de server/sites en apart een back-up van de paneeldatabase (daarin staan gebruikers, WebAuthn-sleutels, instellingen, licentie).

Optie A — HestiaCP: tabblad Backup bij de gebruiker → knop om een back-up te maken (of volgens schema in de serverinstellingen). De back-up omvat de sites en hun databases.

Optie B — handmatig (cron): databasedump + archief van de map data/ van het paneel:

# root-cron (sudo crontab -e) — dagelijkse back-up om 2:30 (vul uw eigen namen/paden in): 30 2 * * * mysqldump -u root MY_DB | gzip > /var/backups/monitor-db-$(date +\%F).sql.gz 40 2 * * * tar czf /var/backups/monitor-data-$(date +\%F).tar.gz -C /path/to/monitor data # Archieven ouder dan 14 dagen verwijderen: 0 3 * * * find /var/backups -name 'monitor-*' -mtime +14 -delete
Een back-up op dezelfde server beschermt tegen fouten, maar niet tegen verlies van de server. Kopieer de archieven naar externe opslag (een andere server, S3, rclone naar de cloud). Controleer of het herstel echt werkt.

33. Paneel bijwerken en migreren

Bijwerken naar een nieuwe versie. Maak eerst een back-up. Upload daarna de codebestanden opnieuw, met behoud van uw gegevens:

  • overschrijven (code): public/, includes/, assets/, cron/, database/, en ook de .htaccess in de root (front controller — de routing mag niet van de oude versie blijven staan), manifest.json, sw.js;
  • niet aanraken: config.php (DB-gegevens), data/ (rapporten), logs/, tmp/ (sessies en cache).
# Na het uploaden — de PHP-cache leegmaken (als opcache aan staat): sudo systemctl reload php*-fpm
FileZilla meldt SSH_FX_PERMISSION_DENIEDPermission denied. De bestanden van het paneel zijn eigendom van www-data (zo zijn ze bij de installatie ingesteld), terwijl de SFTP-client verbindt met uw eigen gebruiker, die geen schrijfrechten heeft. Het hele paneel aan www-data geven “om het maar werkend te krijgen” is precies wat tot deze fout leidt; hieronder drie manieren, elk lost het probleem op.
# Variant A (aanbevolen) — eigenaren scheiden: de code van u, de werkmappen van de webserver. # De webserver krijgt helemaal geen schrijfrechten op de CODE van het paneel: sudo chown -R deploy:www-data /path/to/monitor sudo chown -R www-data:www-data /path/to/monitor/data /path/to/monitor/tmp /path/to/monitor/logs sudo find /path/to/monitor -type d -exec chmod 755 {} \; sudo find /path/to/monitor -type f -exec chmod 644 {} \; sudo chmod 750 /path/to/monitor/data /path/to/monitor/tmp /path/to/monitor/logs sudo chmod 640 /path/to/monitor/config.php # Variant B — ACL bovenop de huidige eigenaren (niets verplaatsen): sudo apt install -y acl sudo setfacl -R -m u:deploy:rwX /path/to/monitor sudo setfacl -R -d -m u:deploy:rwX /path/to/monitor # Variant C — via de groep www-data. Eenvoudiger, maar schrijfrechten op de # bestanden krijgt ook de webserver (bij een PHP-lek is de code vervangbaar): sudo usermod -aG www-data deploy sudo find /path/to/monitor -type d -exec chmod 2775 {} \; sudo find /path/to/monitor -type f -exec chmod 664 {} \; sudo chmod 640 /path/to/monitor/config.php sudo chmod 2750 /path/to/monitor/data /path/to/monitor/tmp /path/to/monitor/logs
Waarom variant A veilig is. Het paneel schrijft slechts naar drie mappen — data/ (rapporten), tmp/ (sessies en cache), logs/; die blijven eigendom van www-data. De rest is code, en de webserver heeft die alleen nodig om te lezen, wat de groep www-data met rechten 644 biedt. Bijkomend voordeel: bij een PHP-lek zijn de bestanden van het paneel niet meer te overschrijven. Op hostingpanelen (HestiaCP en dergelijke) is variant A niet nodig: daar zijn de sitebestanden toch al eigendom van het account waarmee u via SFTP inlogt, en de webserver leest ze via de groep.
Valkuil van variant B: elke volgende chmod op de bestanden reset het ACL-masker, en de toegang verdwijnt geruisloos. Als het uploaden na het “opschonen van de rechten” opnieuw op Permission denied stuit — herhaal beide setfacl-commando's.
Bit 2 in variant C is setgid: via SFTP geüploade bestanden blijven in de groep www-data, anders kan het paneel ze niet overschrijven. Na variant C maakt u opnieuw verbinding in FileZilla — de nieuwe groep werkt pas bij een nieuwe login. Controle: id deploy (de groep www-data moet verschijnen) en ls -ld /path/to/monitor (drwxrwsr-x — de letter s betekent dat setgid is gezet).

Migreren naar een andere server:

  1. Zet op de nieuwe server de site + HTTPS op (zie de pagina voor handmatige installatie).
  2. Kopieer alle paneelbestanden samen met config.php, data/.
  3. Migreer de DB: mysqldump op de oude → import op de nieuwe; pas de DB-gegevens in config.php aan.
  4. Herhaal op de nieuwe server: sudoers, lidmaatschap van de groep adm, cron-taken.
  5. De licentie is gekoppeld aan het domein — als het domein hetzelfde is, blijft de sleutel werken.

34. Toegang herstellen (sleutel, wachtwoord of IP-blok kwijt)

Als u niet kunt inloggen, is alles rechtstreeks in de database op de server te repareren. Open de database (naam staat in config.php):

sudo mysql MY_DB

WebAuthn-sleutel kwijt (tweede factor lukt niet) — schakel 2FA uit, log in met uw wachtwoord en registreer een nieuwe sleutel:

UPDATE users SET webauthn_enabled = 0;

Wachtwoord vergeten — stel een nieuwe hash in (genereer deze op de server en vul in):

# Hash van het nieuwe wachtwoord genereren: php -r "echo password_hash('NEW_PASSWORD', PASSWORD_BCRYPT), \"\n\";" # In de database (plak de verkregen hash): # UPDATE users SET password = '$2y$10$...' WHERE username = 'admin';

Uzelf buitengesloten met het IP-filter — schakel de beperking uit:

UPDATE settings SET value = '0' WHERE name = 'ip_restriction_enabled';
Toegang tot de database heeft u altijd: sudo mysql op de server, of phpMyAdmin / het databasegedeelte in het hostingpaneel. Schakel na het herstel WebAuthn en het IP-filter weer in.

35. Alle cron-taken op één plek

Het overzicht van taken staat in de root-cron van de server (toevoegen via sudo crontab -e). Laat alleen de regels staan van de tools die u gebruikt; pas de paden aan uw eigen server aan.

# Server-cron van de monitor (root) — voeg toe via: sudo crontab -e # 01:30 — ClamAV-scan van gevaarlijke paden (web, home, temp) → kaarten “Bestanden gecontroleerd” en “Laatste scan” 30 1 * * * /usr/local/bin/clamav-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 02:00 — bestandsintegriteitscontrole AIDE (expliciete --config nodig) 0 2 * * * /usr/bin/aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1 # bij het opstarten — rechten /var/lib/aide herstellen (het pakket-tmpfiles-bestand # aide-common.conf zet ze terug op 0700, en het dashboard ziet de database niet meer) @reboot chmod 755 /var/lib/aide # 03:00 — beveiligingsaudit Lynis 0 3 * * * /usr/local/bin/lynis-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 04:00 — bijwerken van blokkeerlijst ipsum (level 1) 0 4 * * * /usr/local/bin/load-ipsum.sh >> /path/to/monitor/logs/cron.log 2>&1 # de ipsum-set wordt bij het opstarten geladen door de service ipsum-load.service (VÓÓR de firewall, anders # ziet UFW de set niet in before.rules) — geen cron. Hier alleen de dagelijkse refresh hierboven. # 06:00 — Logwatch-rapport 0 6 * * * /usr/local/bin/logwatch_daily.sh >> /path/to/monitor/logs/cron.log 2>&1 # elke 30 min — SMART-schijfcontrole */30 * * * * /usr/local/bin/smart-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 04:30 — pakketintegriteit debsums 30 4 * * * /usr/local/bin/debsums-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 08:00 — gepland rapport naar Email en Telegram 0 8 * * * /usr/local/bin/daily-report-all.sh >> /path/to/monitor/logs/cron.log 2>&1 # elk uur — vernieuwen van pakketlijsten (voor de kaart “Beveiligingsupdates”) 0 * * * * /usr/bin/apt-get update -qq >/dev/null 2>&1 # elke 5 min — momentopname van resources (CPU/RAM/netwerk/schijf) voor de pagina “Prestaties” */5 * * * * /usr/local/bin/collect-metrics-all.sh >> /path/to/monitor/logs/cron.log 2>&1
Details per taak vindt u in de bijbehorende secties. Backup-taken (vorige sectie) worden aan dezelfde cron toegevoegd. Controleer na wijzigingen: sudo crontab -l en of de cron-service actief is.
Cron-tijd = tijdzone van de server, niet TIMEZONE uit config.php. De constante TIMEZONE beïnvloedt alleen PHP (hoe het dashboard datums toont), maar de cron-daemon voert taken uit op de systeemtijd van het OS. Als de tijdzone van de server niet met de uwe overeenkomt, komt het rapport van “08:00” op het verkeerde moment binnen. Voorbeeld: de server staat in een andere zone (Europe/London, UTC+1) en u zit in Amsterdam (UTC+2) → het rapport van “08:00” komt bij u om 09:00 binnen. Controleer en breng zo nodig de systeemtijdzone in overeenstemming met de uwe:
# Huidige tijdzone van de server controleren: timedatectl # Uw eigen tijdzone instellen (voorbeeld) en cron herstarten: sudo timedatectl set-timezone Europe/Amsterdam sudo systemctl restart cron
Daarna wordt de regel 0 8 * * * om 08:00 lokale tijd uitgevoerd. Anders zou u de cron zelf moeten verschuiven, maar bij de overgang naar winter-/zomertijd loopt die verschuiving weer uit de pas — daarom is het beter de systeemtijdzone in te stellen.
Kant-en-klare wrapper-scripts. Hun werkende kopieën en een voorbeeld-crontab (crontab.txt) staan in de map system/ naast het project, buiten public_html. Dit is geen onderdeel van de site — ze hoeven niet naar de webroot te worden geüpload; plaats ze op de server op de systeempaden (zoals in de crontab hierboven):
  • lynis-scan.sh/usr/local/bin/ (chmod +x) — voert lynis audit system uit, zet tijdens de scan de vlag /tmp/lynis-running en kopieert lynis-report.dat naar data/lynis/ van het dashboard;
  • logwatch_daily.sh/usr/local/bin/ (chmod +x) — stelt het dagelijkse Logwatch-rapport op (sshd, fail2ban, sudo, postfix) in data/logwatch/;
  • smart-scan.sh/usr/local/bin/ (chmod +x) — legt de schijfstatus vast (smartctl) in data/disk/;
  • debsums-scan.sh/usr/local/bin/ (chmod +x) — controleert de pakketintegriteit (debsums) in data/debsums/;
  • clamav-scan.sh/usr/local/bin/ (chmod +x) — ClamAV-antivirusscan van gevaarlijke paden (web, home, temp); schrijft een overzicht naar /var/log/clamav/scan.log, waar de ClamAV-pagina het uitleest (regel 01:30 in de crontab hierboven);
  • load-ipsum.sh/usr/local/bin/ (chmod +x) — werkt de ipset-set ipsum (level 1) ter plekke bij, zonder de actieve firewallregels te breken (de regel 04:00 in de crontab hierboven);
  • daily-report-all.sh/usr/local/bin/ (chmod +x) — voert het rapport cron/daily_report.php van het dashboard uit (regel 08:00 in de crontab hierboven);
  • daily_report.php — zit al in het dashboard (cron/daily_report.php), wordt uitgevoerd via daily-report-all.sh, hoeft niet apart geïnstalleerd te worden;
  • collect-metrics-all.sh/usr/local/bin/ (chmod +x) — voert cron/collect_metrics.php van het dashboard uit (pagina “Prestaties”, regel */5 in de crontab hierboven); collect_metrics.php zit al in het dashboard, hoeft niet apart geïnstalleerd te worden;
  • crontab.txt (system/cron/) — voorbeeldtaken; voeg de gewenste regels toe via sudo crontab -e.
Het pad naar het script in de crontab moet overeenkomen met waar u het hebt geplaatst.
Hoe u een script in /usr/local/bin/ plaatst. Rechtstreeks vanuit FileZilla kunt u daar niet schrijven — de map is van root, en de SFTP-client krijgt SSH_FX_PERMISSION_DENIED. De volgorde is: eerst het bestand uploaden naar /tmp (daar mag iedereen schrijven), en het dan met één opdracht op zijn plaats zetten:
# in FileZilla: in het veld “Externe site” /tmp invoeren en het script daarheen uploaden, # daarna via SSH (install zet meteen eigenaar en rechten, chown/chmod niet nodig): sudo install -o root -g root -m 755 /tmp/lynis-scan.sh /usr/local/bin/lynis-scan.sh rm -f /tmp/lynis-scan.sh # controle: bestand op zijn plek, rechten rwxr-xr-x, syntaxis intact bash -n /usr/local/bin/lynis-scan.sh && ls -l /usr/local/bin/lynis-scan.sh
Verwar de mappen niet: u hebt /tmp in de root van de server nodig — niet /var/tmp en niet tmp/ binnen het dashboard zelf (dat laatste is van www-data en afgeschermd van uw gebruiker). In de FileZilla-boom is /tmp een tak op het bovenste niveau, naast var, niet erin.
Server met de automatische configuratie opgezet? Deze wrappers en hun cron-taken zijn al geïnstalleerd door het script (in /usr/local/bin/, log — /var/log/arciveo-cron.log) — u hoeft handmatig niets te doen.
Waar de scripts het dashboard zoeken. De wrappers zijn domein-neutraal: ze vinden dashboard-installaties door /home/*/web/*/public_html en /var/www/* af te lopen, en plaatsen de rapporten in hun data/. Als het dashboard op een ander pad staat — voeg dat toe aan de regel for app in … in de scripts, anders komen de rapporten van Lynis/SMART/debsums/Logwatch niet in het dashboard terecht.
cron.log en toegangsrechten. Het bestand logs/cron.log wordt als eerste aangemaakt door de root-cron — het is dan van root, en het tabblad “Cron-log” in het dashboard kan het noch lezen noch legen. Maak het bestand vooraf aan als de webgebruiker (de eigenaar van de sitemap; op HestiaCP is dat het account, bijv. admin) — dan voegt de root-cron er alleen aan toe zonder de eigenaar te wijzigen:
# vooraf aanmaken als webgebruiker (vóór het toevoegen van cron-regels): sudo -u OWNER touch /path/to/monitor/logs/cron.log # als cron.log al door de root-cron is aangemaakt — aan de webgebruiker geven: sudo chown OWNER:OWNER /path/to/monitor/logs/cron.log sudo chmod 644 /path/to/monitor/logs/cron.log
De eigenaar van de map achterhalen: stat -c %U /path/to/monitor.
Beheer vanuit het dashboard. In de sectie “Systeem” is er een pagina “Crontab” — u kunt taken bekijken en toevoegen zonder SSH. Het dashboard bewerkt alleen taken die er zelf mee zijn toegevoegd (een apart blok in de root-crontab, gemarkeerd met dienstcommentaren); alles wat al in de crontab staat (de lijst hierboven) wordt daar getoond in een alleen-lezen lijst “Overige servertaken” met de knop “Kopiëren naar editor” — die zet alleen het schema/de opdracht in het toevoegformulier, de oorspronkelijke regel wordt niet aangeraakt. Om een bestaande taak “onder beheer van het dashboard te brengen” — kopieer hem naar de editor, sla op, en verwijder daarna de oude regel handmatig (sudo crontab -e), anders wordt hij twee keer uitgevoerd.
Eenmalige configuratie op de server. De pagina heeft een geprivilegieerd wrapper-script nodig — niet een kale sudo crontab (dat zou directe escalatie naar root betekenen voor iedereen die toegang tot de dashboardsessie krijgt), maar een beperkt script met twee opdrachten (list/set) dat alleen zijn eigen blok tussen de dienstcommentaren aanraakt. Installeer het eenmalig:
sudo install -m 0755 -o root -g root /dev/stdin /usr/local/sbin/arciveo-cron <<'ARCIVEO_CRON_EOF' #!/bin/bash set -euo pipefail BEGIN='# >>> ARCIVEO-CRON-MANAGED (edited from the panel; do not edit by hand) >>>' END='# <<< ARCIVEO-CRON-MANAGED <<<' cmd=${1:-} case "$cmd" in list) [ "$#" -eq 1 ] || { echo "usage: ${0##*/} list" >&2; exit 2; } crontab -l -u root 2>/dev/null || true ;; set) [ "$#" -eq 1 ] || { echo "usage: ${0##*/} set (body on stdin)" >&2; exit 2; } body=$(cat) if grep -qF "$BEGIN" <<<"$body" || grep -qF "$END" <<<"$body"; then echo "invalid body: markers not allowed" >&2; exit 2 fi current=$(crontab -l -u root 2>/dev/null || true) tmp=$(mktemp); trap 'rm -f "$tmp"' EXIT { if grep -qF "$BEGIN" <<<"$current"; then awk -v b="$BEGIN" '{print} $0==b{exit}' <<<"$current" else [ -n "$current" ] && printf '%s\n' "$current" echo "$BEGIN" fi printf '%s\n' "$body" echo "$END" if grep -qF "$END" <<<"$current"; then awk -v e="$END" 'f{print} $0==e{f=1}' <<<"$current" fi } > "$tmp" crontab -u root "$tmp" ;; *) echo "usage: ${0##*/} <list|set>" >&2; exit 2 ;; esac ARCIVEO_CRON_EOF echo "www-data ALL=(ALL) NOPASSWD: /usr/local/sbin/arciveo-cron" | sudo tee -a /etc/sudoers.d/monitor sudo visudo -c
De webgebruiker kan verschillen van www-data — controleer onder welke gebruiker de PHP-FPM-pool van de site draait (ps -o user= -C php-fpm) en vul die in de sudoers-regel in.
Nieuw bestand met de verkeerde eigenaar geüpload — de pagina antwoordt “Access denied.”. Als het bestand public/crontab_monitor.php via FTP/SFTP onder een andere systeemgebruiker (bijvoorbeeld root) is geüpload dan de overige sitebestanden, kan de webserver het niet lezen. Vergelijk de eigenaar en rechten met een naastgelegen bestand en breng ze in overeenstemming:
ls -la public/crontab_monitor.php public/ssl_monitor.php sudo chown OWNER:OWNER public/crontab_monitor.php sudo chmod 644 public/crontab_monitor.php

Diagnostiek

36. Tool is geïnstalleerd, maar toont “Niet geïnstalleerd”

De monitor detecteert de aanwezigheid van tools via dpkg-query — de APT-pakketdatabase. Als een tool niet via apt is geïnstalleerd (handmatig, uit snap of vanuit broncode), ziet dpkg het niet.

# Controleren via dpkg: dpkg -l fail2ban | grep '^ii' dpkg -l auditd | grep '^ii' # Pad naar de binary zoeken: which ufw fail2ban-client auditctl # Sudo-test als www-data: sudo -u www-data sudo fail2ban-client status sudo -u www-data sudo ufw status verbose

37. Problemen oplossen (500, geen gegevens)

Fout 500 — controleer de logs van PHP, nginx en de monitor zelf:

tail -50 /var/log/nginx/error.log tail -50 /var/log/php*-fpm.log # Monitorlogs: tail -50 logs/monitor_$(date +%Y-%m-%d).log # Maprechten: ls -la data/ tmp/ logs/
Dashboard op een hostingpaneel (HestiaCP, ISPmanager, cPanel)? Daar draait PHP niet onder www-data, maar onder het gebruikersaccount (bijvoorbeeld admin — de eigenaar van de sitemap). Alle sudo-regels en groepslidmaatschappen (adm, systemd-journal) moeten op deze gebruiker worden ingesteld, anders tonen de modules “Niet actief / 0” terwijl de services wel draaien. De echte PHP-gebruiker achterhalen: ps -o user= -C php-fpm | sort -u of de eigenaar van de sitemap stat -c '%U' /path/to/monitor. Vervang www-data daarna in alle onderstaande commando's door die gebruiker. De automatische installatie detecteert de webgebruiker zelf en stelt sudoers daarop in.

Gegevens worden niet weergegeven — bijna altijd ontbrekende sudo-rechten. Controleer het specifieke commando als webgebruiker (vervang www-data door de uwe). De vlag -n = zonder wachtwoord, net als PHP — als er om een wachtwoord wordt gevraagd, ontbreekt de regel in sudoers:

sudo -u www-data sudo -n fail2ban-client status sudo -u www-data sudo -n ufw status verbose sudo -u www-data sudo -n ipset list -t ipsum sudo -u www-data sudo -n /usr/sbin/ausearch -m USER_LOGIN -ts today sudo -u www-data sudo -n /usr/sbin/aa-status sudo -u www-data sudo -n /usr/sbin/psad --Status sudo -u www-data journalctl -u falco --no-pager -n 5
Module toont “Niet actief” / “0”, terwijl de tool wel werkt (bijvoorbeeld sudo aa-status in de terminal toont profielen, maar de pagina “AppArmor” toont “Inactief”). Oorzaak: de webgebruiker heeft geen sudo-recht op het commando van deze module. Controleer het uit de lijst hierboven: als er om een wachtwoord wordt gevraagd — voeg de ontbrekende regel toe aan /etc/sudoers.d/monitor (“Sudo instellen”). Veelvoorkomende “nieuwe” commando's: /usr/sbin/aa-status (MAC), /usr/sbin/psad --Status (PSAD).
Als een specifieke pagina (Falco, ModSecurity, Auditd, open UFW-poorten) leeg is — vergelijk met de lijst in het gedeelte over sudo: waarschijnlijk is apache2ctl, ausearch, aa-status of ss niet toegestaan, of zit de webgebruiker niet in de groepen adm/systemd-journal (daaruit worden de logs van fail2ban/auth/modsec en journalctl gelezen — Falco en kernelgebeurtenissen).

38. Pagina is leeg terwijl er data op de server staat

Symptoom: er staat data op de server (zichtbaar via shell), maar de pagina toont “geen data” of een onjuiste status — bijvoorbeeld AIDE meldt “Niet geïnitialiseerd” terwijl de database wel is aangemaakt.

Oorzaak is open_basedir: veel panelen en hostings beperken de PHP-FPM-pool tot de domeinmap, waardoor de PHP-functies file_exists(), file_get_contents(), filemtime() op systeempaden (/var/lib/aide, /var/log, /proc…) worden geblokkeerd. De monitor omzeilt dit door zulke paden met standaard systeemcommando's te lezen (cat, test, stat).

# Is het bestand zichtbaar via shell (zo leest de monitor): sudo -u www-data bash -lc 'test -e /var/lib/aide/aide.db && echo VISIBLE || echo NO' # Huidige waarde van open_basedir voor de domeinpool: grep -ri open_basedir /etc/php/*/fpm/pool.d/ 2>/dev/null
Als de shell het bestand “ziet” (VISIBLE) maar de pagina niet — dan is het open_basedir. De juiste oplossing is lezen met systeemcommando's (al gedaan voor AIDE en de Netwerkmonitor). Het uitbreiden van open_basedir naar /var, /proc is niet nodig en minder veilig.

39. SSL-pagina werkt niet

De monitor controleert certificaten door rechtstreeks via poort 443 verbinding te maken met domeinen. Als een domein vanaf de server zelf onbereikbaar is of de poort door de firewall wordt geblokkeerd, mislukt de controle.

# Certificaat handmatig controleren: echo | openssl s_client -connect monitor.example.com:443 2>/dev/null \ | openssl x509 -noout -dates # Bereikbaarheid controleren: curl -I https://monitor.example.com
De monitor haalt domeinen automatisch uit de configuraties van nginx (/etc/nginx/sites-enabled/, /etc/nginx/conf.d/) en Apache (/etc/apache2/sites-enabled/) plus de huidige host uit HTTP_HOST.
Automatische detectie van subdomeinen. Subdomeinen worden automatisch bepaald aan de hand van de openbare Certificate Transparency-logs en via het netwerk gecontroleerd — zelfs als ze op andere servers staan. U hoeft handmatig niets toe te voegen.

40. Slechts één van meerdere databases zichtbaar

De monitor verbindt met MySQL als de gebruiker uit config.php, die alleen toegang heeft tot zijn eigen database. MySQL toont in information_schema alleen databases waarvoor u rechten hebt — daarom zijn de andere niet zichtbaar.

Om de monitor alle databases te laten zien, geeft u deze gebruiker alleen-lezenrecht (eenmalig als root; vul de gebruikersnaam uit config.php in):

sudo mysql -u root GRANT SELECT, PROCESS, SHOW DATABASES ON *.* TO 'DB_USER'@'localhost'; FLUSH PRIVILEGES; EXIT;
SELECT ON *.* geeft alleen leesrecht — er kan niets worden gewijzigd, verwijderd of aangemaakt, dit is veilig voor monitoring.
Zonder deze GRANT ziet het dashboard alleen zijn eigen database — dit is geen fout, maar een rechtenbeperking. Het dashboard gebruikt geen enkele sudo mysql: de lijst met databases wordt opgehaald via zijn eigen PDO-verbinding.

41. PostgreSQL wordt niet weergegeven op de pagina “Database”

PostgreSQL vereist toegang op het niveau van de gebruiker postgres, die de webgebruiker van het dashboard niet heeft. Een brede sudo psql vanuit PHP openen is onveilig — in plaats daarvan roept het dashboard een strakke wrapper zonder parameters aan die alleen de versie, het aantal verbindingen en de lijst met databases met groottes toont. Maak deze aan:

sudo tee /usr/local/bin/monitor-pgstat >/dev/null <<'EOF' #!/bin/sh # Arciveo Monitor - read-only PostgreSQL version, connections and per-database size sudo -u postgres psql -tAc "SELECT version();" | grep -oE 'PostgreSQL [0-9.]+' echo "---" sudo -u postgres psql -tAc "SELECT count(*) FROM pg_stat_activity;" echo "---" sudo -u postgres psql -tAc "SELECT datname || '|' || pg_size_pretty(pg_database_size(datname)) FROM pg_database WHERE datistemplate = false;" EOF sudo chown root:root /usr/local/bin/monitor-pgstat sudo chmod 755 /usr/local/bin/monitor-pgstat # in /etc/sudoers.d/monitor (gebruiker = degene waaronder PHP-FPM draait): # www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-pgstat
Gebruikt u PostgreSQL niet — verwijder dan de regel monitor-pgstat uit sudoers (stap 13 van de handmatige installatie) en maak het script zelf niet aan: de PostgreSQL-kaart blijft dan gewoon inactief.

42. Er ging een alert af — wat nu

Het dashboard toont wat er gebeurt; hieronder ziet u wat u moet doen in typische situaties. Algemeen principe: raak niet in paniek, vergelijk met legitieme activiteit (uw acties, updates, back-ups) en reageer naar ernst.

  • Aanvalskaart / veel fail2ban-bans — dat is normaal voor elke server op internet (bots proberen voortdurend SSH/web). Het belangrijkste is dat de bans werken. Zorg dat SSH-toegang alleen met een sleutel gaat (wachtwoord uitgeschakeld) en dat uw IP in ignoreip staat.
  • ModSecurity heeft verzoeken geblokkeerd — de WAF weert aanvallen op de site af, dat is zijn taak. Wordt uw legitieme verkeer geblokkeerd (vals alarm), zoek dan de rule id in de details en voeg een uitzondering toe aan de CRS-config.
  • AIDE: bestanden gewijzigd — vergelijk de lijst met wat u zelf deed (pakketten updaten, configs aanpassen is normaal). Wijzigingen aan systeembinaries die u niet hebt aangeraakt zijn reden tot alertheid. Werk na legitieme wijzigingen de AIDE-database bij.
  • debsums: binaries/bibliotheken gewijzigd (buiten /etc, buiten /usr/share) — mogelijk vervanging. Controleer het pakket: debsums PACKAGE_NAME, en installeer het bij twijfel opnieuw (apt install --reinstall).
  • ClamAV / maldet: dreiging gevonden — controleer het bestand in quarantaine, open het niet. Gaat het om een webshell in de sitemap, isoleer dan de server en zoek de toegangspoort (kwetsbare plugin, gelekte toegangsgegevens).
  • Falco: kritieke gebeurtenissen (start van een shell in een container, toegang tot gevoelige bestanden) — analyseer de gebeurtenis: wiens proces, wat startte het. Vaak is dit legitieme beheeractiviteit.
  • Externe blootstelling: database/cache in het rood — sluit dit onmiddellijk: bind de service aan 127.0.0.1 of sluit de poort in UFW. Dit is een echt gat.
  • SSL verloopt / is verlopen — verleng het certificaat (Let's Encrypt verlengt zichzelf; zo niet, controleer dan certbot renew of de instellingen in het paneel).
  • Beveiligingsupdates wachten — installeer ze: sudo apt update && sudo apt upgrade; herstart de server na een kernel-update.
Tekenen van een echte inbraak (onbekende processen/gebruikers, gewijzigde binaries, uitgaande spam, onbekende cron-taken): koppel de server los van externe toegang, maak een back-up voor analyse en zet, als de data kritiek is, een schone server op vanaf een vertrouwde back-up — een rootkit betrouwbaar verwijderen is lastig.
Arcivéo - Security Monitor © 2026