FAQ

Dette er en vejledning til installation, opsætning og vedligeholdelse af Arcivéo Monitor. Afsnittene er grupperet: generelt overblik, udrulning af dashboardet, tilkobling af sikkerhedsværktøjer, indbyggede moduler og diagnostik. Kommandoer kan kopieres med knappen til højre.

Kom godt i gang

01. Installation af panelet — vælg metode

Installationen af panelet er beskrevet på separate trinvise sider. Vælg en metode:

Er du i tvivl — vælg den automatiske. Denne håndbog er fortsat den samlede kilde til SSL, værktøjer, cron og diagnostik — install-siderne henviser til dens afsnit uden at gentage noget.

Oversigt

02. Hvad er Arcivéo Monitor

Arcivéo Monitor — et sikkerhedsdashboard til serveren. Det indsamler data fra installerede værktøjer (Fail2ban, UFW, Lynis, ModSecurity, AIDE, ClamAV, Auditd, CrowdSec, Suricata, Falco m.fl.) og viser dem i én samlet grænseflade med dashboard, angrebskort og detaljerede sider for hvert værktøj.

Monitor er ikke et aktivt beskyttelsesværktøj — det blokerer ikke angreb af sig selv. Dets opgave er at samle information fra allerede kørende værktøjer og præsentere den overskueligt.

03. Sådan fungerer monitoren på serveren

Monitoren kører kun lokalt — den skal installeres på den samme server, som den overvåger. Ingen SSH eller fjern-API.

Alle kommandoer (fail2ban-client, ufw status, ipset list osv.) udfører panelet som webserverens bruger (typisk www-data, på hostingpaneler webstedets konto) med et snævert sæt rettigheder via sudo — kun til bestemte værktøjer, uden generel root-adgang. Resultaterne parses og vises i browseren.

Til flere servere installeres monitoren på hver enkelt for sig med et unikt domæne.

04. Sådan beregnes sikkerhedsscoren

Scoren starter på maksimum og falder for hvert fundet problem:

  • UFW er ikke aktiv — −30
  • Fail2ban kører ikke (ingen aktive jails) — −25
  • Ingen WebAuthn-nøgler — −15
  • Lynis hardening index < 60 — −20; 60–79 — −10
  • IPset ipsum er ikke indlæst — −10
  • Trusler fundet af ClamAV — −20
  • Filændringer i AIDE — −15
  • SSL er udløbet — −30, udløber om <14 dage — −15, <30 dage — −5
  • CrowdSec er installeret, men kører ikke — −5
  • Suricata er installeret, men kører ikke — −5
  • Database/cache (MySQL, PostgreSQL, Redis…) er tilgængelige udefra — −10
  • Root-login via SSH er tilladt (PermitRootLogin yes) — −20
  • Sikkerhedsopdateringer afventer installation — −5

Resultat: 80+ = Beskyttet, 60–79 = Vær opmærksom, <60 = I fare.

Fradrag for ClamAV, AIDE, CrowdSec og Suricata anvendes kun, hvis værktøjet er installeret. Lynis og AIDE uden en initialiseret database vises som “ingen data” og sænker ikke scoren. Antallet af angreb i dag vises på dashboardet, men påvirker ikke sikkerhedsscoren.

Indstillinger og licens

05. WebAuthn — tofaktorgodkendelse

WebAuthn — standard for godkendelse uden adgangskode via en hardwarenøgle. Understøtter YubiKey, Touch ID, Face ID, Windows Hello, Passkey.

Efter login med adgangskode beder systemet om bekræftelse via en registreret nøgle. Selv hvis adgangskoden lækker, kan man ikke logge ind uden den fysiske nøgle eller biometri.

For at konfigurere det skal du åbne WebAuthn-nøgler i sidemenuen og klikke på “Registrér nøgle”. Registrér to nøgler med det samme: hvis din eneste nøgle mistes eller går i stykker, kan du ikke logge ind i dashboardet med den.

WebAuthn fungerer kun via HTTPS. På en HTTP-forbindelse er registrering og login med nøgle ikke tilgængelig.

06. Notifikationer: Telegram og Email

Dashboardet kan sende sikkerhedsrapporten til Telegram og på e-mail (via knap og efter tidsplan). Konfigureres under “Indstillinger”.

Telegram. Du skal bruge bottoken og chat id:

  1. Skriv til @BotFather i Telegram → /newbot → få en token af typen 123456:ABC....
  2. Skriv en vilkårlig besked til din nye bot (så den kan svare dig).
  3. Find dit chat id: skriv til botten @userinfobot, eller åbn https://api.telegram.org/bot<TOKEN>/getUpdates og find "chat":{"id":...}.
  4. Indsæt token og chat id i “Indstillinger” → Telegram, og tryk “Gem og send test”.

Email. To metoder at vælge imellem under “Indstillinger” → Email:

  • SMTP — vært, port (465/SSL eller 587/TLS), login og adgangskode til din postkasse;
  • Resend — moderne API: angiv API-nøgle (re_...) og et bekræftet afsenderdomæne.
Knappen “Send test” tjekker kanalen med det samme. Tidsplanen for den automatiske rapport styres via cron (afsnittet “Alle cron-job”): den udløser afsendelsen, og kanalerne hentes fra indstillingerne.

Rapportstatus: “ADVARSEL” eller “OK”. Overskriften bliver “ADVARSEL” kun ved et reelt problem eller en ventende handling: fundet ClamAV-trussel, filændringer i AIDE, kritiske Falco-hændelser (Emergency/Alert/Critical inden for de sidste 24 t), en nedbrudt tjeneste i Monit, genstart påkrævet, SSL udløber (≤14 dage) eller sikkerhedsopdateringer venter. Baggrundsstøj — botters SSH-forsøg, IP-adresser bandlyst af fail2ban, Suricata-alarmer, Lynis-advarsler og allerede afværgede ModSecurity-forespørgsler — hæver ikke statussen, så sådanne tal i rapporten betyder ikke “ADVARSEL” i sig selv.

07. Licens — indtastning og aktivering

De detaljerede overvågningsmoduler (Lynis, UFW, ModSecurity, angrebskort, AIDE, ClamAV m.fl.) åbnes, når du har en gyldig licens. Uden den fungerer dashboardet, indstillingerne og kontoen, men modulerne viser kortet “Licens påkrævet”.

Efter købet i din konto har du en aktiveringskode af typen ARCIVEO-XXXX-XXXX-XXXX-XXXX. Den skal “aktiveres” til dit paneldomæne — det gør koden til en signeret licensfil (blokken [license]), som du indsætter i panelet.

Sådan aktiverer du (3 trin):

  1. Hent aktiveringskoden. Kontoen my.arciveo.com → afsnittet “Licenser” / “Licensaktivering” — kopiér koden ARCIVEO-….
  2. Aktivér koden til dit domæne. Samme sted i kontoen åbner du “Licensaktivering” og indtaster: aktiveringskoden, din e-mail og paneldomænet (adressen, hvor monitoren åbnes, f.eks. monitor.example.com). Klik på aktivér — systemet genererer en licensfil bundet til dette domæne og viser den i et felt med knappen “Kopiér”.
  3. Indsæt nøglen i panelet. Kopiér hele licensteksten → i panelet åbner du “Indstillinger” → blokken “Licens”, indsætter og klikker “Gem”. Modulerne låses op med det samme.

Panelet verificerer nøglen kryptografisk: signaturen, bindingen til domænet og gyldighedsperioden.

Domænet ved aktivering skal stemme nøjagtigt overens med paneladressen. Hent den fra konstanten APP_URL i config.php og indtast kun værtsnavnet — uden https:// og uden www-præfiks. Aktiveringen er engangs: koden gøres til en licens for det indtastede domæne og kan ikke aktiveres igen — ved en fejl i domænet passer nøglen ikke til dit panel, og koden er brugt op. Indtast derfor domænet omhyggeligt.
Er perioden udløbet, eller er domænet ændret — vises en advarsel i panelets sidehoved. Licensen er bundet til domænet for altid og overføres ikke til et andet domæne: til en ny periode eller et nyt domæne skal du bruge en ny nøgle (købes i kontoen og aktiveres én gang).

08. Filen config.php — alle indstillinger for panelet

Alle vigtige parametre for panelet er angivet i én fil config.php i roden (ved siden af mappen public/) som almindelige konstanter define(). Filen oprettes ved installationen; den skal sjældent redigeres manuelt — mest ved skift af domæne, flytning eller tilslutning til en anden database. Efter enhver ændring skal du genstarte PHP-FPM (ellers træder ændringerne ikke i kraft på grund af OPcache).

Indsæt dine egne værdier i de fremhævede felter; lad resten stå:

// --- Database --- define('DB_HOST', 'localhost'); // lad stå define('DB_NAME', 'db_name'); // det du angav ved oprettelse af databasen define('DB_USER', 'user'); // det du angav ved oprettelse af databasen define('DB_PASS', 'db_password'); // det du angav ved oprettelse af databasen define('DB_CHARSET', 'utf8mb4'); // lad stå // --- Applikation --- define('APP_URL', 'https://monitor.example.com'); // panelets adresse, uden skråstreg til sidst define('TIMEZONE', 'Europe/Copenhagen'); // din tidszone // --- Sessionstid --- define('SESSION_LIFETIME', 28800); // inaktivitet før nyt login, sek (28800 = 8 t)

Database. Forbindelsesoplysninger til MySQL/MariaDB:

  • DB_HOST — databaseserverens host, næsten altid localhost;
  • DB_NAME — navnet på panelets database;
  • DB_USER — databasebruger (adgang kun til egen database);
  • DB_PASS — adgangskoden for denne bruger;
  • DB_CHARSET — forbindelsens tegnsæt, lad utf8mb4 stå.

Applikation.

  • APP_URL — panelets fulde adresse (f.eks. https://monitor.example.com). Den skal svare til det domæne, som licensen er aktiveret på — ellers afvises nøglen (se afsnittet “Licens”);
  • TIMEZONEPHP-tidszonen: påvirker kun, hvordan panelet viser dato og tid. Den påvirker ikke tidspunktet for cron-job — der gælder systemets tidszone (se “Alle cron-job”).

Sessionstid. SESSION_LIFETIME — timeout for inaktiv session i sekunder (glidende: opdateres ved aktivitet). Standard er 28800 = 8 timer; efter så lang tids inaktivitet beder panelet dig logge ind igen. F.eks. 3600 = 1 time, 86400 = et døgn.

Fejllogning. Fejl vises aldrig til besøgende, men skrives til logs/php_errors.log — de kan ses på siden “Applikationslog”. Disse linjer (display_errors=0, log_errors=1, stien error_log) skal normalt ikke ændres — indstillingerne er sat direkte i filen og afhænger ikke af php.ini.

config.php er en hemmelig fil. Den indeholder databasens adgangskode. Den ligger i panelets rod (ved siden af public/), og for dette panel er webroden (DocumentRoot) netop panelets rod, ikke public/. Filen “lækker” ikke af sig selv: i den centrale .htaccess er der et eksplicit forbud mod den (Require all denied) — serveren returnerer 403. Selv uden denne regel ville kildekoden ikke lække: det er PHP — serveren udfører den og udleverer den ikke som tekst. For en sikkerheds skyld: læg den ikke i offentlige repositorier, og send den ikke til supporten med den rigtige adgangskode. Rettighederne på filen er 640.
Ved flytning eller gendannelse af adgang er denne fil den vigtigste kilde til oplysningerne: databasenavn, bruger og adgangskode hentes netop herfra (se afsnittene “Opdatering og flytning af panelet” og “Gendannelse af adgang”).

Sikkerhedsværktøjer

09. UFW-firewall

UFW (Uncomplicated Firewall) — en simpel grænseflade til nftables/iptables. Lukker alle indgående porte undtagen dem, der udtrykkeligt er tilladt. Siden “UFW-firewall” viser status og regler.

sudo apt install ufw # Tillad SSH (obligatorisk FØR aktivering!) og web sudo ufw allow OpenSSH sudo ufw allow 80,443/tcp # Luk databasen udefra (kun lokal adgang) sudo ufw deny 3306 # Aktivér og kontrollér sudo ufw enable sudo ufw status verbose
Før ufw enable skal du tillade SSH (ufw allow OpenSSH), ellers mister du adgangen til serveren.
“Ekstern eksponering” på dashboardet tager UFW med i betragtning: en port, der er lukket med en deny-regel, regnes ikke som tilgængelig udefra.
Skipping adding existing rule — er ikke en fejl. Sådan meddeler UFW, at nøjagtig den samme regel allerede findes, og at den ikke tilføjes igen. Ved en fornyet kørsel af autokonfigurationen (den er idempotent) er dette en normal meddelelse — der er ingen grund til at reagere.

10. Installation af Fail2ban

Blokerer automatisk en IP efter for mange mislykkede loginforsøg. Analyserer logfiler fra SSH, nginx, Apache og andre tjenester.

sudo apt install fail2ban sudo systemctl enable --now fail2ban # Tjek status: sudo fail2ban-client status
Den fungerende konfiguration (jail.local med snesevis af jails og autoban fra ipsum) findes i næste afsnit.

11. Fungerende konfiguration af Fail2ban + ipsum

Grundinstallationen er ovenfor. Her er en fungerende konfiguration, der giver dusinvis af aktive jails og tusindvis af blokeringer: generelle indstillinger, centrale jails og autoban af skadelige IP fra listen ipsum.

Filen /etc/fail2ban/jail.local — generelle indstillinger og de vigtigste jails:

[DEFAULT] bantime = 1w findtime = 900 maxretry = 3 backend = systemd banaction = nftables-multiport ignoreip = 127.0.0.1/8 ::1 <YOUR_IP> <TRUSTED_NETS> # Progressiv ban: hver gentagelse — længere bantime.increment = true bantime.factor = 2 bantime.maxtime = 5w bantime.rndtime = 300 [sshd] enabled = true maxretry = 5 bantime = -1 # permanent ban for SSH-brute force findtime = 3600 # Gengangere: den, der har fanget flere bans — bannes for altid [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 # Webtjenester (apache-*, nginx-*, php-url-fopen, phpmyadmin-syslog): [nginx-http-auth] enabled = true port = http,https [apache-badbots] enabled = true port = http,https # … og de øvrige jails pr. tjeneste (dovecot, exim, postfix-sasl, # mysqld-auth, vsftpd, portscan, pam-generic) — enabled = true
I ignoreip skal du ubetinget skrive din egen IP og betroede net, ellers kan du banne dig selv. Efter ændringer: sudo fail2ban-client reload.

Automatisk indlæsning af bloklisten ipsum — i root-cron (sudo crontab -e): level 1 (100.000+ IP) indlæses i sættet ipsum, som afvises på firewallen (mere herom — i afsnittet “Blokliste IPset”):

# 04:00 — opdatering af ipset ipsum (level 1, maksimal dækning): 0 4 * * * /usr/local/bin/load-ipsum.sh >> /path/to/monitor/logs/cron.log 2>&1
Sættet skal hedde ipsum — det er præcis det, dashboardet læser (kortet “IPset ipsum”). Niveauer: levels/1.txt — maksimal dækning, levels/3.txt — mere præcist (3+ kilder).

Hvorfor “Sikkerhedsmonitor” er delt i to zoner. Beskyttelsen kører på to niveauer, og dashboardet blander dem ikke:

  • Reelle angreb (reaktivt) — alt, hvad fail2ban fangede: aktive indbrudsforsøg (jails sshd, apache-*, nginx-* osv.) og ondsindede gengangere (jail recidive — dem, der allerede er bannet flere gange). Det er IP, der reelt forsøgte at bryde ind hos dig — de er på angrebskortet og “Tidslinjen”.
  • Præventiv blokering (proaktivt) — den offentlige bloklise over kendte skadelige IP ipset ipsum, afvist på firewallen med reglen DROP. Disse adresser har for det meste slet ikke rørt din server — de skæres fra på forhånd; tælleren “IPset ipsum” viser, hvor mange der er afvist præventivt.

Forskellen er enkel: reaktivt — “disse angreb og fik en ban”, præventivt — “disse blev blokeret allerede før forsøget”. Tidligere blev list-3 ipsum kunstigt tvunget ind i recidive (deraf den gamle opdeling “liste-recidive”); nu er recidive kun ægte gengangere, og præventiv beskyttelse ligger helt på firewallen.

12. Bloklisten IPset (ipsum)

ipsum — en offentlig liste over skadelige IP-adresser, opdateret dagligt. Monitor viser antallet af indlæste adresser på dashboardet og angrebskortet og medregner det i sikkerhedsscoren (−10, hvis sættet ikke er indlæst).

Den minimale variant uden fail2ban — et separat sæt ipsum med blokering via iptables:

# Opret sættet (én gang): sudo ipset create ipsum hash:ip # Opdateringsscript /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, dagligt kl. 4:00): 0 4 * * * /usr/local/bin/update-ipsum.sh
Den udvidede variant med fail2ban-recidive — i afsnittet “Fungerende konfiguration af Fail2ban + ipsum”.
ipset lever i hukommelsen og går tabt ved genstart. Et enkelt dagligt cron-job efterlader sættet tomt fra genstart og indtil næste kørsel (dashboardet viser 0). Indlæs også sættet ved opstart — læg indlæsningen i et script og knyt det til @reboot. Samtidig sætter kommandoen create … -exist grænsen maxelem 300000 (standard er 65536 — level 1 passer ikke, du får “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 — dagligt kl. 04:00 OG ved hver opstart: 0 4 * * * /usr/local/bin/load-ipsum.sh @reboot sleep 60 && /usr/local/bin/load-ipsum.sh
Sådan fungerer det ved automatisk installation. Scriptet indlæser hele listen level 1 (100.000+ IP) i sættet ipsum, og hvis firewallen styres af installationsprogrammet (frisk VPS — profilerne “Fuld”/“Letvægts”), knytter det sættet til UFW med en DROP-regel — trafik fra disse IP-adresser bliver reelt blokeret. Reglen står efter ESTABLISHED,RELATED, så eksisterende forbindelser (inkl. din SSH) ikke afbrydes — kun nye forbindelser fra listen bliver blokeret. Sættet genskabes, når tjenesten ipsum-load.service indlæses før firewallen (ellers ville UFW ikke komme op), og opdateres af cron kl. 04:00. På en allerede konfigureret server (dashboard, egen firewall) rører installationsprogrammet ikke firewallen — der forbliver ipsum en liste til dashboardet og angrebskortet, og DROP-reglen tilføjes manuelt efter ønske (den minimale variant med iptables … --match-set ipsum … -j DROP — ovenfor). Ved automatisk installation behøver du ikke gøre noget manuelt.

13. Installation af CrowdSec

En moderne erstatning for Fail2ban med kollektiv threat intelligence: blokeringer fra fællesskabet plus egne regler. Kræver en separat bouncer for at anvende blokeringer på firewallen.

curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash sudo apt install crowdsec sudo systemctl enable --now crowdsec # Bouncer til iptables/nftables: sudo apt install crowdsec-firewall-bouncer-iptables # Tjek status: sudo systemctl status crowdsec sudo cscli decisions list sudo cscli bouncers list
Status “Ikke startet” i panelet = tjenesten er installeret, men servicen er ikke aktiv (monitoren tjekker den via systemctl is-active crowdsec). Start den: sudo systemctl enable --now crowdsec; ved nedbrud se sudo journalctl -u crowdsec -n 30. Samme regel gælder enhver tjeneste med status “Ikke startet” (Suricata, Falco, Monit, MySQL).
“0 scenarier” eller “0 bouncers” på dashboardet. CrowdSec kommer næsten tom ud af boksen — uden collections registrerer den intet, og uden en registreret bouncer anvendes blokeringerne ikke på firewallen. Installér de grundlæggende collections og sørg for, at bounceren står på listen:
# Grundlæggende collections (Linux + SSH + webserver): sudo cscli collections install crowdsecurity/linux crowdsecurity/sshd crowdsecurity/base-http-scenarios sudo systemctl reload crowdsec # Bounceren skal stå på listen og have status som aktiv forbindelse: sudo cscli bouncers list
I bouncerens log står stream halted / blokeringer anvendes ikke. Det er en forældreløs api-nøgle: bounceren blev fjernet fra cscli bouncers list, men dens gamle nøgle blev tilbage i /etc/crowdsec/bouncers/*.yaml. Genregistrér bounceren og indsæt en frisk nøgle:
sudo cscli bouncers add fw-bouncer # udskriver en ny api_key # indsæt denne nøgle i api_key: i /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml sudo systemctl restart crowdsec-firewall-bouncer
Automatisk installation (profilen “Fuld beskyttelse”) installerer selv collections og registrerer firewall-bouncer — manuelt er dette kun nødvendigt ved manuel installation eller efter manuel indgriben i CrowdSec.

14. Installation af AIDE

AIDE (Advanced Intrusion Detection Environment) tager et øjebliksbillede af filsystemet og rapporterer ved hver kontrol om ændringer i /etc, /bin, /usr. Efter installationen er initialisering af databasen (aideinit) obligatorisk.

sudo apt install aide # Initialisering af databasen (5-15 minutter): sudo aideinit sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db # Ubuntu 24.04: kataloget /var/lib/aide oprettes i tilstand 700 (ejer _aide), # og panelet (www-data) ser ikke databasen → viser “Ikke initialiseret”. # Åbn kataloget for gennemgang (databasefilerne forbliver 600): sudo chmod 755 /var/lib/aide # Første kontrol MED SKRIVNING til loggen, som monitoren læser. # På Ubuntu/Debian kræver aide en eksplicit --config (ellers “missing configuration”; # binæren aide.wrapper leveres ikke i nyere versioner): sudo bash -c 'aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1'
Under aideinit står terminalen i 5-15 minutter på linjen Running aide --init... — det er normalt (hashing af hele filsystemet, belastning på disken). Afbryd ikke med Ctrl+C. Hvis processen “hænger”, men intet skriver — venter den muligvis på svar på en skjult forespørgsel Overwrite existing aide.db.new [Yn]? (tryk Y). Kontrollér aktiviteten fra en anden session: pgrep -af aide.
Fejl i aideinit: “21_aide_spamassassin … printf: invalid number” (return code 20) — en kendt fejl i AIDE-konfigurationssnippet i Ubuntu 22.04. Databasen oprettes ikke. Flyt den defekte snippet ud og gentag:
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
Statusser på dashboardet. “Ikke initialiseret” = panelet ser ikke databasefilen: enten er aideinit ikke kørt, eller (Ubuntu 24.04) er kataloget /var/lib/aide oprettet i tilstand 700 og utilgængeligt for www-data — afhjælpes med sudo chmod 755 /var/lib/aide (se blokken ovenfor). “Ingen kontroller endnu” = databasen findes, men kontrollen er endnu ikke udført — det er ikke en fejl. Resultaterne læser monitoren fra /var/log/aide/aide.log.
Regelmæssig kontrol → log til panelet. Standard-/etc/cron.daily/aide på nyere Ubuntu/Debian skriver muligvis ikke /var/log/aide/aide.log i den ønskede form (og aide.wrapper findes ikke længere i dem). Det er mere pålideligt at tilføje sin egen cron med eksplicit --config — den skriver loggen som root i tilstand 644, og monitoren læser den uden ekstra grupper:
# sudo crontab -e — daglig kontrol kl. 02:00: 0 2 * * * /usr/bin/aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1 # Kør nu uden at vente på tidsplanen: sudo bash -c 'aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1'
Automatisk installation gør allerede alt dette: chmod 755 /var/lib/aide og cron-kontrol kl. 02:00 — der kræves intet manuelt.
Foretag den første initialisering på en ren server — før installation af webapplikationer. Efter legitime ændringer genopretter du databasen: sudo aideinit && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db.

15. Installation af ClamAV

Antivirusscanner til Linux. Særligt nyttig til at kontrollere /var/www for PHP-shells og skadelig kode.

sudo apt install clamav clamav-daemon sudo systemctl enable --now clamav-daemon # Opdater signaturdatabasen: sudo freshclam # Scan en mappe manuelt: sudo clamscan -r /var/www --infected
Viser clamd-dæmonen “Inaktiv” efter enable --now? Tre typiske årsager:

1. Linjen Example står stadig i konfigurationen — clamd nægter at starte, så længe den er der:

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

2. Signaturdatabasen er ikke hentet — clamd starter ikke uden den:

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

3. Den er bare ved at starte op — clamd indlæser ~8 mio. signaturer i hukommelsen på 30-60 sek. Vent, og kontrollér: systemctl is-active clamav-daemon (status activating → indlæser stadig).

Diagnostik: sudo journalctl -u clamav-daemon -n 30 --no-pager.
Viser dashboardet “Filer kontrolleret: 0” / “Seneste scanning: —”? clamd-dæmonen holder kun signaturerne i hukommelsen; den scanner ikke noget efter en tidsplan af sig selv. Panelet viser resultater af en planlagt scanning, så der skal bruges et cron-job, der scanner og skriver en log. Automatisk installation opsætter wrapperen /usr/local/bin/clamav-scan.sh og et cron-job kl. 01:30 — efter første kørsel udfyldes “Filer kontrolleret” og “Seneste scanning”. Kør den med det samme uden at vente på tidsplanen: sudo /usr/local/bin/clamav-scan.sh.

16. Installation af Linux Malware Detect (maldet)

Linux Malware Detect (LMD) — malware-scanner målrettet webtrusler: PHP-shells, webbackdoors, downloadere. Bruger ClamAV-motoren og supplerer den med egne signaturer.

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 # Opdatér signaturer: sudo maldet -u # Scan /var/www: sudo maldet -a /var/www
LMD og ClamAV fungerer godt sammen. Seneste rapport: maldet --report.
Under installationen kan linjen update-rc.d: error: unable to read /etc/init.d/maldet vises — den er harmløs. maldet bruger ikke init.d; signaturopdatering og scanninger køres via /etc/cron.daily/maldet. Ses installation completed nedenfor, er alt installeret.
Står der “Ikke installeret” for LMD på siden, selvom den er installeret? maldet installeres ikke via apt, men i /usr/local/maldetect, og med open_basedir slået til kontrolleres dens tilstedeværelse via shell — se afsnittet “Siden er tom, selvom der er data på serveren”.

17. Installation af Suricata

Netværksbaseret system til registrering af indtrængen: analyserer trafik på pakkeniveau og kender tusindvis af angrebssignaturer. Supplerer ModSecurity (der arbejder på HTTP-niveau, mens Suricata arbejder på TCP/IP-niveau).

sudo add-apt-repository ppa:oisf/suricata-stable sudo apt update && sudo apt install suricata # Hent de aktuelle regler: sudo suricata-update sudo systemctl enable --now suricata
Suricata er “Aktiv”, men dashboardet viser ingen alarmer / antal hændelser er 0? Suricata skriver /var/log/suricata/eve.json som root med tilstand 750 på kataloget, og webserveren (www-data) kan ikke læse det. Åbn kataloget for gennemgang — filerne indeni forbliver beskyttet:
sudo chmod o+rx /var/log/suricata
Den automatiske installation gør dette selv — det er ikke nødvendigt manuelt.

18. Installation af Falco

Opfanger systemkald via eBPF/kernel module og opdager anomalier i realtid: shell fra nginx, læsning af /etc/passwd af en webproces, skrivning til /bin osv.

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
Monitoren læser Falco-hændelser via journalctl -u falco (uden sudo — via gruppen systemd-journal). Sørg for, at www-data er i denne gruppe — se “Opsætning af sudo” (pkt. 2) på siden om manuel installation.
“0 hændelser på 24 timer” er normalt, ikke en fejl. Falco er event-driven: den tier, så længe alt er i orden, og logger kun en hændelse ved en anomali (shell fra en webproces, læsning af /etc/passwd, skrivning til systemkataloger). Nul kritiske på et døgn på en rolig server er en sund tilstand.
Til dashboardet er filoutput mere pålideligt. Læsning via journalctl kræver rettigheder til journalen; for at dashboardet ser hændelserne stabilt, aktiverer autoinstallationen file_output i Falco → /var/log/falco/falco.log og sætter UMask=0022 på tjenesten (loggen kan læses af webserveren). På en ny installation behøver du ikke at opsætte dette manuelt.

19. Installation af ModSecurity (WAF)

ModSecurity — en web-firewall (WAF) til Apache eller Nginx. Blokerer angreb på applikationsniveau: SQL-injektioner, XSS, path traversal, scannere.

# Apache: sudo apt install libapache2-mod-security2 sudo a2enmod security2 # Regelsæt OWASP Core Rule Set: sudo apt install modsecurity-crs # OBLIGATORISK: uden denne fil er regelmotoren slået fra 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 # Test: skal returnere 403 curl -s -o /dev/null -w '%{http_code}\n' "https://monitor.example.com/?id=1%20UNION%20SELECT%201,2--"
Selve pakkeinstallationen beskytter ikke noget i sig selv. Apache indlæser konfigurationer med linjen IncludeOptional /etc/modsecurity/*.conf, mens pakken kun lægger modsecurity.conf-recommended — den matcher ikke masken *.conf. Hvis den ikke kopieres til modsecurity.conf, forbliver SecRuleEngine Off: modulet er indlæst, CRS-reglerne er indlæst, men trafikken kontrolleres ikke, og der oprettes ingen audit-log. Mellemtilstanden DetectionOnly skriver kun hændelser til loggen uden at blokere forespørgsler — dashboardet viser den med gult.

Dashboardets adgang til audit-loggen. Loggen /var/log/apache2/modsec_audit.log tilhører root (rettigheder 640), og web-brugeren kan ikke læse den. Dashboardet henter data via en wrapper — opret den:

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 # i /etc/sudoers.d/monitor (bruger = den, som PHP-FPM kører under): # www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-modsec
Wrapperen tager sidste SecRuleEngine-direktiv uden indrykning: indrykkede linjer ligger inde i blokke som <LocationMatch>/<Directory> (f.eks. deaktivering af WAF for phpMyAdmin) og bestemmer ikke den globale tilstand.
Brugeren i sudoers skal svare til FPM-pool-brugeren: på almindelig Apache/Debian er det www-data, i HestiaCP kører sitets pool som sitets ejer (f.eks. admin) — tjek grep -E '^user' /etc/php/*/fpm/pool.d/monitor.example.com.conf.
Hvis sitet står bag en Nginx-proxy (HestiaCP), ser Apache selve proxyen som klient — dashboardet henter angriberens rigtige IP-adresse fra headeren X-Forwarded-For. I statistikken medtages kun transaktioner med en udløst regel: direktivet SecAuditLogRelevantStatus skriver alle 4xx/5xx-svar til audit-loggen, så almindelige 403/500 havner også dér — dem regner dashboardet ikke som WAF-hændelser.
Blokken ---RULES--- bruges af afsnittet “Alle aktive regler” — dashboardet viser ikke kun de udløste, men alle indlæste CRS-regler + brugerdefinerede. De tre stier i løkken for f in … er typiske placeringer for CRS-regler og lokale tilføjelser; hvis din opsætning er anderledes (pakken lægger filer i sit eget katalog, eller brugerdefinerede regler ikke ligger i /etc/modsecurity/custom-rules.conf), så find de rigtige stier med kommandoen sudo grep -rl 'IncludeOptional\|^Include ' /etc/apache2/mods-enabled/security2.conf /etc/apache2/conf-enabled/*.conf 2>/dev/null og indsæt dem i listen. Hvis wrapperen er gammel (uden dette afsnit) — viser afsnittet blot advarslen “ikke tilgængelig”, og resten af siden fungerer som før.

20. Installation af Auditd

Auditd (Linux Audit Daemon) registrerer systemkald på kerneniveau: log ind og log ud, sudo-kommandoer, mislykkede godkendelsesforsøg, filændringer. Monitor viser log ind, mislykkede forsøg og sudo-kommandoer for i dag.

sudo apt install auditd audispd-plugins sudo systemctl enable --now auditd # Tjek status og hændelser: sudo systemctl status auditd sudo ausearch -m USER_LOGIN -ts today
Monitor læser hændelser via ausearch (/usr/sbin/ausearch) og om nødvendigt fra /var/log/audit/audit.log med kommandoen tail. Begge skal være i sudoers.

21. Installation af Monit

Overvåger tjenester (nginx, php-fpm, mysql osv.) og genstarter dem, hvis de går ned. Kan sende advarsler til e-mail.

sudo apt install monit sudo systemctl enable --now monit # Konfigurationer: sudo nano /etc/monit/monitrc ls /etc/monit/conf.d/
Monitor henter listen over tjenester via monit status. I /etc/monit/monitrc skal HTTP-grænsefladen være aktiveret (blokken set httpd med allow localhost), ellers returnerer monit status en fejl.
Viser dashboardet “0 tjenester under overvågning”? To årsager. (1) HTTP-grænsefladen er slået fra — i monitrc er linjen set httpd udkommenteret (standard er # set httpd port 2812 …). Fjern kommentaren fra blokken og tillad localhost. (2) Selve den aktiverede httpd overvåger ikke noget — Monit tæller kun det, der beskrives med check-stanzaer; uden dem er listen tom, selv med en fungerende grænseflade. Minimal fungerende konfiguration:
# /etc/monit/conf.d/00-httpd — HTTP-grænseflade for localhost: set httpd port 2812 use address localhost allow localhost # eksempler på check-stanzaer (hvad der skal overvåges): 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 # tjek syntaks (Control file syntax OK) sudo systemctl reload monit sudo monit status
Autoinstallationen lægger en færdig conf.d med httpd på 2812 og et sæt tjek — på en ny installation behøver du ikke konfigurere manuelt.
Tjeneste i status “Med fejl”? Monitor viser kun tilstanden og genstarter bevidst ikke tjenester fra webpanelet (det ville være fjernudførelse af root-kommandoer i et sikkerhedspanel). Diagnostik og genstart sker via SSH gennem Monit:
sudo monit status <service> # årsag til fejlen sudo monit restart <service> # genstart via Monit # hvis Monit ikke får tjenesten op — se dens egen unit: sudo systemctl status <unit> --no-pager sudo journalctl -u <unit> -n 50 --no-pager

22. Installation af PSAD (registrering af portscanning)

PSAD analyserer iptables-loggen og opdager portscanninger og netværksangreb, idet hver kilde tildeles et trusselsniveau (1–5). Supplerer fail2ban og Suricata.

sudo apt install psad # PSAD læser iptables-loggen — logning skal aktiveres (UFW gør det selv). # For ren iptables tilføj LOG-regler i INPUT/FORWARD-kæderne. sudo psad --sig-update sudo systemctl enable --now psad
Monitoren læser data via psad --Status (skal være i sudoers). Uden iptables-logning vil siden være tom — det er normalt, indtil der har været scanninger.

23. AppArmor / SELinux (adgangskontrol)

Mandatory Access Control begrænser, hvilke filer og ressourcer et program kan tilgå, selv hvis det bliver kompromitteret. På Ubuntu/Debian bruges AppArmor som standard (normalt allerede installeret og aktivt).

# AppArmor (Ubuntu/Debian): sudo apt install apparmor apparmor-utils sudo systemctl enable --now apparmor sudo aa-status # tjek profiler
Monitoren læser status via aa-status (skal være i sudoers). Viser antal profiler i tilstanden enforce/complain og processer uden profil.

“Profiler indlæst” er flere end enforce + complain — det er normalt. I AppArmor 4.x (Ubuntu 24.04 og nyere) kom tilstanden unconfined: profilen er indlæst i kernen, men begrænser ingenting. Ubuntu markerer på den måde snesevis af profiler for programmer, der bruger user namespaces (browsere, torrent-klienter og lignende). Når sådanne profiler findes, bliver kortet “Profiler indlæst” ravgult og viser deres antal — for eksempel unconfined: 90 ved 120 indlæste og 26 i enforce. Reelt beskytter kun profiler i enforce; på Ubuntu 22.04 (AppArmor 3.x) findes denne tilstand ikke, og tallene stemmer altid.

sudo aa-status | grep -E "profiles are" # opdeling efter tilstand sudo aa-enforce /etc/apparmor.d/profile-name # sæt profilen i enforce
Profiler, som Ubuntu bevidst har efterladt i unconfined, bør kun sættes i enforce med omtanke: de er ikke slået fra ved en fejl, men fordi programmerne selv ellers holder op med at fungere. Profiler i complain er en anden sag: reglerne er allerede skrevet, de bliver bare ikke håndhævet.

24. Installation af debsums (pakkeintegritet)

debsums kontrollerer, at filerne fra installerede pakker stemmer overens med kontrolsummerne fra arkivet — afslører udskiftede systembinære filer (supplerer AIDE). En fuld kontrol tager 1-2 minutter, så den køres via cron, og dashboardet læser resultatet fra data/debsums/debsums.log og sorterer det selv i kategorier (kun binære filer og biblioteker er vigtige).

Opgaven ligger i root-cron (sudo crontab -e). Den færdige wrapper debsums-scan.sh lægges i /usr/local/bin/ (chmod +x; se oversigten over cron-opgaver) og skriver selv rapporten til dashboardets data/debsums/.

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

Wrapperen debsums-scan.sh finder selv dashboardets data/ — stien skal ikke angives.

Ændringer i /etc/ (konfigurationer) og /usr/share/ (ressourcer) på serveren er normalt uproblematiske — dashboardet markerer dem med en særskilt farve. Ændringer af binære filer og biblioteker er alarmerende (/bin, /sbin, /usr/lib osv.) — kortet “Binære filer / biblioteker” viser netop disse.

25. Opsætning af Lynis-rapporter

Lynis kører manuelt eller via cron. Rapporten skal gemmes i projektets mappe data/lynis/ — monitoren læser filen lynis-report.dat.

# Engangskørsel (indsæt din egen sti til panelets rod): sudo lynis audit system --report-file /path/to/monitor/data/lynis/lynis-report.dat # Daglig audit — cron-linje (færdig wrapper lynis-scan.sh i /usr/local/bin/, se oversigten): 0 3 * * * /usr/local/bin/lynis-scan.sh >> /path/to/monitor/logs/cron.log 2>&1
Efter den første kørsel viser siden “Lynis-audit” straks hardening index, advarsler og anbefalinger.
Knappen “Kør audit” på Lynis-siden. Den kører lynis-scan.sh i baggrunden direkte fra panelet (uden at vente på cron): viser “Scanner…” og opdaterer selv rapporten, når den er færdig. Til det skal web-brugeren have en sudoers-linje til at køre scriptet — installationsprogrammet tilføjer den automatisk i /etc/sudoers.d/monitor. Hvis panelet blev installeret manuelt/tidligere, så tilføj den med samme bruger, der allerede står i filen:
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. Konfiguration af Logwatch-rapporter

Logwatch skal gemme daglige rapporter i projektets mappe data/logwatch/ i formatet .txt. Monitor viser den seneste rapport og arkivet.

# Dagligt (6:00) — cron-linje (klar wrapper logwatch_daily.sh i /usr/local/bin/, se oversigten): 0 6 * * * /usr/local/bin/logwatch_daily.sh >> /path/to/monitor/logs/cron.log 2>&1

Dashboardmoduler

27. Netværksovervågning (indbygget)

Netværksovervågning kræver ingen installation — det er en indbygget dashboardside. Den viser serverens netværksstatus fra lokale kilder:

  • interfaces og trafik — fra /proc/net/dev;
  • linkstatus (UP/DOWN) og IP — via ip;
  • forbindelser og lyttende porte — via ss;
  • netværkshændelser fra kernen de sidste 24 t — via journalctl -k.

De første tre kilder fungerer uden sudo, så interfaces, trafik, forbindelser og porte er synlige med det samme. Blokken “Kernehændelser” bruger journalctl -k — den læses via gruppen systemd-journal (“Konfiguration af sudo”, pkt. 2), sudo er ikke nødvendig. Tjek, at alt er tilgængeligt for webbrugeren:

# Tjek som www-data (PHP kører under denne bruger): 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
Blokken “Netværkshændelser fra kernen” viser hændelser i kernens netværksstak (linkskift up/down, bærebølgefejl, “network unreachable”). Firewallposter UFW BLOCK vises ikke her — de findes på siderne “UFW-firewall” og “Angrebskort”. En tom blok med grønt flueben = ingen netværksfejl det sidste døgn.

28. Disk og SMART

Den indbyggede side viser tre ting:

  • Filsystemer — partitionernes forbrug (df); skalaen bliver rød ved ≥90%;
  • Diske — liste over diske (lsblk), kun de reelle (loop/snap er skjult);
  • Tilstand (SMART) — diskens status og attributter (smartctl).

Plads og enhedsliste virker med det samme, uden opsætning. Til SMART kræves pakken smartmontools. Webprocessen har ikke direkte adgang til diskenhederne, så SMART hentes via cron til filen data/disk/smart.txt, som dashboardet så læser.

Opgaven ligger i root-cron (sudo crontab -e). En færdig wrapper smart-scan.sh lægges i /usr/local/bin/ (chmod +x; se oversigten over cron-opgaver) og skriver selv til dashboardets data/disk/.

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

Wrapperen smart-scan.sh finder selv dashboardets data/ — stien skal ikke angives. Internt udelukker lsblk -e7,11 loop/cdrom.

På virtuelle diske (QEMU/KVM og lignende) er typisk kun den overordnede status “tilstand: OK” tilgængelig, mens temperatur, driftstimer og omfordelte sektorer kan være tomme — det er normalt. På en fysisk server vises alle attributter.

29. Ydelse (CPU/RAM/netværk/disk)

Siden viser serverbelastningens historik for de seneste 24 timer — Load Average, CPU-forbrug og I/O-ventetid, RAM/Swap, netværkstrafik (modtaget/sendt), disk-I/O (læsning/skrivning), diskopfyldning og inodes, åbne fildeskriptorer og MySQL-forbindelser samt det aktuelle antal TCP-forbindelser og processer.

Data indsamles af cron/collect_metrics.php — hvert 5. minut skrives ét “råt” øjebliksbillede af tællerne (/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') til databasetabellen system_metrics; procenter og hastigheder beregner siden selv ud fra forskellen mellem to nabosnapshots (diskopfyldning/inodes/deskriptorer/MySQL-forbindelser er øjebliksværdier uden genberegning). Sudo kræves ikke — kilderne læses uden root-rettigheder. Punkter ældre end 24 timer slettes automatisk ved hver skrivning.

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

Wrapperen collect-metrics-all.sh (se oversigten over cron-opgaver) finder selv alle installerede panelinstanser på serveren og kører hvers cron/collect_metrics.php som webstedets ejer.

Indtil kollektoren har kørt mindst to gange (de første ~10 minutter efter installationen) viser siden “data indsamles” — graferne skal bruge mindst ét par nabopunkter for at kunne beregne hastigheder og procenter.

Belastningsalarmer (afsnittet “Indstillinger” → “Belastningsalarmer”) — når tærsklen for CPU/RAM/disk/inodes overskrides, sender panelet en notifikation til Telegram/Email (samme kanaler som den daglige rapport — de behøver ikke aktiveres særskilt til alarmer) og endnu en, når metrikken er tilbage i normalen. Der spammes ikke igen, mens tærsklen holdes: næste notifikation kommer først efter en cyklus “normaliseret → overskredet igen”.

Tærsklerne kontrolleres af samme collect_metrics.php ved hver kørsel (hvert 5. minut) — der kræves ikke en separat cron. Tilstanden “allerede varslet / endnu ikke” gemmes i data/alerts_state.json, tærsklerne i panelets indstillinger.

30. Angrebskort (GeoIP)

Siden “Angrebskort” bestemmer landet ud fra IP med kommandoen geoiplookup. Uden GeoIP-pakken kan landene ikke bestemmes, og der vises ingen punkter på kortet:

sudo apt install geoip-bin geoip-database # Kontrol: geoiplookup 8.8.8.8
Sudo er ikke nødvendigt — databasen /usr/share/GeoIP/GeoIP.dat kan læses af alle, og resultaterne caches i tmp/geoip_cache.json. Selve kortet (Leaflet + OpenStreetMap-fliser) indlæses i browseren — der kræves internet på den computer, hvor dashboardet er åbnet.

31. Ekstern eksponering, opdateringer og automatiske opdateringer

To indbyggede dashboardkort, der ikke viser et værktøjs “til/fra”, men serverens reelle beskyttelse. Kræver ingen installation, læses lokalt uden sudo.

Ekstern eksponering — hvor mange tjenester lytter på alle grænseflader (0.0.0.0/[::]) og er tilgængelige udefra. Markeres rødt, hvis en database eller cache stikker ud (MySQL, PostgreSQL, Redis, MongoDB, Memcached, Elasticsearch) — det er et direkte hul (−10 i sikkerhedsvurderingen). Kilde: ss -tuln.

Er kortet rødt — luk databasen for omverdenen: bind den til 127.0.0.1 (bind-address i MySQL/PostgreSQL-konfigurationen, bind 127.0.0.1 i Redis) eller luk porten i UFW.
“Åben port” ≠ “tilgængelig udefra”. En tjeneste, der lytter på 127.0.0.1 (loopback), er kun synlig for serveren selv — den kan ikke nås udefra, selvom porten er “åben”. Derfor er Postfix på port 25 bundet til loopback sikker: autokonfigurationen sætter inet_interfaces = loopback-only (plus et neutralt smtpd_banner — lukker Lynis-bemærkningen MAIL-8818 om afsløring af version). Kortet “Ekstern eksponering” regner kun det med udadtil, som lytter på 0.0.0.0/[::]; loopback-tjenester tælles ikke med.
Lynis MAIL-8818 manuelt (hvis du selv har sat mailen op): i /etc/postfix/main.cf angiv smtpd_banner = $myhostname ESMTP (uden version og OS) og inet_interfaces = loopback-only, derefter sudo systemctl restart postfix.

Sikkerhedsopdateringer — hvor mange sikkerhedspatches venter på installation, og om der kræves genstart efter en kerneopdatering (−5 i sikkerhedsvurderingen ved ventende patches). Kilde: /usr/lib/update-notifier/apt-check, filen /var/run/reboot-required. Detaljeret liste — på siden “Sikkerhedsopdateringer”.

# Installer opdateringer: sudo apt update && sudo apt upgrade # Tjek hvad der lytter udadtil: ss -tuln | grep -E '0\.0\.0\.0|\[::\]'
Opdateringskortet virker på Ubuntu/Debian (update-notifier-common). Hvis apt-check mangler — beregner monitoren patches via apt-get -s upgrade.

Automatiske sikkerhedsopdateringer (unattended-upgrades) — på siden “Sikkerhedsopdateringer” viser et separat kort, om automatisk installation af sikkerhedspatches er slået til, og hvornår den senest kørte. Sudo er ikke nødvendigt — status læses via apt-config dump.

sudo apt install unattended-upgrades sudo dpkg-reconfigure -plow unattended-upgrades # slå til # Tjek hvad der er slået til: apt-config dump | grep Unattended-Upgrade

Vedligeholdelse

32. Sikkerhedskopiering

Backup er den vigtigste forsikring: datatab er værre end ethvert indbrud. Du har brug for to ting — backup af server/websteder og separat en backup af panelets database (der ligger brugere, WebAuthn-nøgler, indstillinger og licens).

Mulighed A — HestiaCP: fanen Backup hos brugeren → knappen til at oprette en backup (eller planlagt i serverindstillingerne). Backuppen omfatter websteder og deres databaser.

Mulighed B — manuelt (cron): databasedump + arkiv af panelets data/-mappe:

# root-cron (sudo crontab -e) — daglig backup kl. 2:30 (indsæt dine egne navne/stier): 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 # Slet arkiver ældre end 14 dage: 0 3 * * * find /var/backups -name 'monitor-*' -mtime +14 -delete
En backup på samme server redder dig fra fejl, men ikke fra tab af serveren. Kopiér arkiverne til et eksternt lager (en anden server, S3, rclone til skyen). Kontrollér, at gendannelsen rent faktisk virker.

33. Opdatering og flytning af panelet

Opdatering til en ny version. Tag først en backup. Læg derefter kodefilerne op igen, og bevar dine data:

  • overskriv (kode): public/, includes/, assets/, cron/, database/ samt roddens .htaccess (frontcontroller — routingen må ikke beholdes fra den gamle version), manifest.json, sw.js;
  • rør ikke ved: config.php (databasedata), data/ (rapporter), logs/, tmp/ (sessioner og cache).
# Efter upload — ryd PHP-cachen (hvis opcache er slået til): sudo systemctl reload php*-fpm
FileZilla melder SSH_FX_PERMISSION_DENIEDPermission denied. Panelets filer tilhører www-data (sådan blev de sat under installationen), mens SFTP-klienten forbinder som din egen bruger, der ikke har skriverettighed. At give www-data hele panelet “for at det virker” er netop det, der fører til denne fejl; nedenfor er tre måder, som alle løser problemet.
# Mulighed A (anbefales) — del ejerskabet: koden er din, arbejdsmapperne webserverens. # Webserveren får slet ingen skriverettighed til panelets KODE: 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 # Mulighed B — ACL oven på de nuværende ejere (vi flytter ikke noget): 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 # Mulighed C — via gruppen www-data. Enklere, men skriverettighed til panelets # filer får webserveren også (ved en PHP-sårbarhed kan koden udskiftes): 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
Hvorfor mulighed A er sikker. Panelet skriver kun i tre kataloger — data/ (rapporter), tmp/ (sessioner og cache), logs/; de forbliver hos www-data. Resten er kode, og webserveren har kun brug for læseadgang til den, hvilket gruppen www-data giver med rettighederne 644. Sidegevinst: ved en PHP-sårbarhed kan panelets filer ikke længere overskrives. På hostingpaneler (HestiaCP og lignende) er mulighed A ikke nødvendig: der tilhører sitets filer i forvejen den konto, du logger ind med via SFTP, og webserveren læser dem via gruppen.
Faldgrube ved mulighed B: ethvert efterfølgende chmod på filerne nulstiller ACL-masken, og adgangen forsvinder lydløst. Hvis uploaden efter “oprydning i rettighederne” igen støder på Permission denied — kør begge setfacl-kommandoer igen.
Bit 2 i mulighed C er setgid: filer uploadet via SFTP forbliver i gruppen www-data, ellers kan panelet ikke overskrive dem. Efter mulighed C — forbind igen i FileZilla: den nye gruppe træder først i kraft ved et nyt login. Kontrol: id deploy (gruppen www-data skal dukke op) og ls -ld /path/to/monitor (drwxrwsr-x — bogstavet s betyder, at setgid er sat).

Flytning til en anden server:

  1. På den nye server sætter du sitet + HTTPS op (se siden om manuel installation).
  2. Kopiér alle panelets filer sammen med config.php, data/.
  3. Flyt databasen: mysqldump på den gamle → import på den nye; ret databasedata i config.php.
  4. Gentag på den nye server: sudoers, medlemskab af gruppen adm, cron-job.
  5. Licensen er bundet til domænet — hvis domænet er det samme, virker nøglen fortsat.

34. Gendan adgang (mistet nøgle, adgangskode, IP-blok)

Hvis du ikke kan logge ind, kan alt rettes direkte i databasen fra serveren. Åbn databasen (navnet står i config.php):

sudo mysql MY_DB

Mistet WebAuthn-nøgle (andet trin fejler) — slå 2FA fra, log ind med adgangskode og registrér en ny nøgle:

UPDATE users SET webauthn_enabled = 0;

Glemt adgangskode — angiv en ny hash (generér den på serveren og indsæt den):

# Generér hash til den nye adgangskode: php -r "echo password_hash('NEW_PASSWORD', PASSWORD_BCRYPT), \"\n\";" # I databasen (indsæt den genererede hash): # UPDATE users SET password = '$2y$10$...' WHERE username = 'admin';

Låst dig selv ude med IP-filteret — slå begrænsningen fra:

UPDATE settings SET value = '0' WHERE name = 'ip_restriction_enabled';
Der er altid adgang til databasen: sudo mysql på serveren eller phpMyAdmin / databaseafsnittet i hostingpanelet. Slå WebAuthn og IP-filteret til igen efter gendannelsen.

35. Alle cron-job ét sted

Oversigten over job ligger i serverens root-cron (tilføjes via sudo crontab -e). Behold kun linjerne for de værktøjer, du bruger; ret stierne til efter din server.

# Serverens cron for monitoren (root) — indsæt via: sudo crontab -e # 01:30 — ClamAV-scan af udsatte stier (web, home, temp) → kortene “Filer scannet” og “Seneste scanning” 30 1 * * * /usr/local/bin/clamav-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 02:00 — AIDE-filintegritetstjek (kræver eksplicit --config) 0 2 * * * /usr/bin/aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1 # ved opstart — genskab rettigheder på /var/lib/aide (pakkens tmpfiles-fil # aide-common.conf sætter dem til 0700, så dashboardet ikke længere ser databasen) @reboot chmod 755 /var/lib/aide # 03:00 — Lynis-sikkerhedsaudit 0 3 * * * /usr/local/bin/lynis-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 04:00 — opdatering af ipsum-bloklisten (level 1) 0 4 * * * /usr/local/bin/load-ipsum.sh >> /path/to/monitor/logs/cron.log 2>&1 # ipsum-sættet indlæses ved opstart af servicen ipsum-load.service (FØR firewallen, ellers # ser UFW ikke sættet i before.rules) — ikke cron. Her kun den daglige refresh ovenfor. # 06:00 — Logwatch-rapport 0 6 * * * /usr/local/bin/logwatch_daily.sh >> /path/to/monitor/logs/cron.log 2>&1 # hver 30. min — SMART-disktjek */30 * * * * /usr/local/bin/smart-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 04:30 — pakkeintegritet med debsums 30 4 * * * /usr/local/bin/debsums-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 08:00 — planlagt rapport til Email og Telegram 0 8 * * * /usr/local/bin/daily-report-all.sh >> /path/to/monitor/logs/cron.log 2>&1 # hver time — opdatering af pakkelister (til kortet “Sikkerhedsopdateringer”) 0 * * * * /usr/bin/apt-get update -qq >/dev/null 2>&1 # hver 5. min — øjebliksbillede af ressourcer (CPU/RAM/netværk/disk) til siden “Ydelse” */5 * * * * /usr/local/bin/collect-metrics-all.sh >> /path/to/monitor/logs/cron.log 2>&1
Detaljer om hvert enkelt findes i de tilhørende afsnit. Backup-jobbene (forrige afsnit) tilføjes i den samme cron. Efter rettelser: tjek sudo crontab -l og at cron-tjenesten er aktiv.
Cron-tid = serverens tidszone, ikke TIMEZONE fra config.php. Konstanten TIMEZONE påvirker kun PHP (hvordan dashboardet viser datoer), men cron-dæmonen kører job efter OS'ets systemtid. Hvis serverens zone ikke stemmer med din, kommer “08:00”-rapporten på det forkerte tidspunkt. Eksempel: serveren står i en anden zone (Europe/London, UTC+1), mens du er i København (UTC+2) → “08:00”-rapporten ankommer 09:00 hos dig. Tjek og tilpas om nødvendigt systemets zone til din egen:
# Tjek serverens nuværende zone: timedatectl # Sæt din egen zone (eksempel) og genstart cron: sudo timedatectl set-timezone Europe/Copenhagen sudo systemctl restart cron
Derefter kører linjen 0 8 * * * kl. 08:00 lokal tid. Ellers skulle man flytte selve cron, men ved overgangen til vinter-/sommertid ville forskydningen skride igen — derfor er det rigtigere at indstille systemets zone.
Færdige wrapper-scripts. Deres arbejdskopier og en crontab-skabelon (crontab.txt) ligger i mappen system/ ved siden af projektet, uden for public_html. Det er ikke en del af sitet — de skal ikke uploades til webroden; læg dem på serveren efter systemstierne (som i crontab ovenfor):
  • lynis-scan.sh/usr/local/bin/ (chmod +x) — kører lynis audit system, sætter under scanningen flaget /tmp/lynis-running og kopierer lynis-report.dat til dashboardets data/lynis/;
  • logwatch_daily.sh/usr/local/bin/ (chmod +x) — danner den daglige Logwatch-rapport (sshd, fail2ban, sudo, postfix) i data/logwatch/;
  • smart-scan.sh/usr/local/bin/ (chmod +x) — henter diskstatus (smartctl) til data/disk/;
  • debsums-scan.sh/usr/local/bin/ (chmod +x) — tjekker pakkeintegritet (debsums) i data/debsums/;
  • clamav-scan.sh/usr/local/bin/ (chmod +x) — ClamAV-antivirusscan af udsatte stier (web, home, temp); skriver en oversigt til /var/log/clamav/scan.log, hvorfra ClamAV-siden læser den (linjen 01:30 i crontab ovenfor);
  • load-ipsum.sh/usr/local/bin/ (chmod +x) — opdaterer ipset-sættet ipsum (level 1) på stedet uden at bryde de aktive firewallregler (linjen 04:00 i crontab ovenfor);
  • daily-report-all.sh/usr/local/bin/ (chmod +x) — kører dashboardets rapport cron/daily_report.php (linjen 08:00 i crontab ovenfor);
  • daily_report.php — følger allerede med dashboardet (cron/daily_report.php), køres via daily-report-all.sh og skal ikke lægges op separat;
  • collect-metrics-all.sh/usr/local/bin/ (chmod +x) — kører dashboardets cron/collect_metrics.php (siden “Ydelse”, linjen */5 i crontab ovenfor); collect_metrics.php følger allerede med dashboardet og skal ikke lægges op separat;
  • crontab.txt (system/cron/) — jobskabelon; indsæt de nødvendige linjer via sudo crontab -e.
Stien til scriptet i crontab skal stemme med det sted, hvor du lagde det.
Sådan lægger du et script i /usr/local/bin/. Direkte fra FileZilla kan man ikke skrive dertil — mappen tilhører root, og SFTP-klienten får SSH_FX_PERMISSION_DENIED. Fremgangsmåden er: upload først filen til /tmp (dertil kan alle skrive), og flyt den derefter på plads med én kommando:
# i FileZilla: skriv /tmp i feltet “Fjernsted” og upload scriptet dertil, # derefter via SSH (install sætter ejer og rettigheder med det samme, chown/chmod er ikke nødvendige): sudo install -o root -g root -m 755 /tmp/lynis-scan.sh /usr/local/bin/lynis-scan.sh rm -f /tmp/lynis-scan.sh # tjek: filen er på plads, rettigheder rwxr-xr-x, syntaks er intakt bash -n /usr/local/bin/lynis-scan.sh && ls -l /usr/local/bin/lynis-scan.sh
Forveksl ikke mapperne: du skal bruge /tmp i serverens rod — ikke /var/tmp og ikke tmp/ inde i selve dashboardet (sidstnævnte tilhører www-data og er lukket for din bruger). I FileZilla-træet er /tmp en gren på øverste niveau, ved siden af var, ikke inde i den.
Sat serveren op med autokonfiguration? Disse wrappere og deres cron-job er allerede installeret af scriptet (i /usr/local/bin/, log — /var/log/arciveo-cron.log) — du skal ikke gøre noget manuelt.
Hvor scripterne leder efter dashboardet. Wrapperne er domæneneutrale: de finder dashboard-installationer ved at gennemgå /home/*/web/*/public_html og /var/www/* og lægger rapporter i deres data/. Ligger dashboardet på en anden sti — føj den til linjen for app in … inde i scripterne, ellers når rapporterne fra Lynis/SMART/debsums/Logwatch ikke frem til dashboardet.
cron.log og adgangsrettigheder. Filen logs/cron.log oprettes først af root-cron — den vil tilhøre root, og fanen “Cron-log” i dashboardet kan hverken læse eller rydde den. Opret filen på forhånd som webbrugeren (ejeren af sitets mappe; på HestiaCP er det kontoen, f.eks. admin) — så vil root-cron blot skrive videre uden at ændre ejeren:
# opret på forhånd som webbrugeren (før cron-linjerne tilføjes): sudo -u OWNER touch /path/to/monitor/logs/cron.log # hvis cron.log allerede er oprettet af root-cron — overdrag den til webbrugeren: sudo chown OWNER:OWNER /path/to/monitor/logs/cron.log sudo chmod 644 /path/to/monitor/logs/cron.log
Find mappens ejer: stat -c %U /path/to/monitor.
Styring fra dashboardet. I afsnittet “System” findes siden “Crontab” — man kan se og tilføje job uden SSH. Dashboardet redigerer kun de job, det selv har tilføjet (en separat blok i root-crontab, markeret med interne kommentarer); alt, der allerede står i crontab (listen ovenfor), vises der som read-only-liste “Andre serverjob” med knappen “Kopiér til editor” — den flytter kun tidsplan/kommando ind i tilføjelsesformularen og rører ikke den oprindelige linje. For at “overføre” et eksisterende job til dashboardets styring — kopiér det til editoren, gem, og slet derefter den gamle linje manuelt (sudo crontab -e), ellers vil det køre to gange.
Engangsopsætning på serveren. Siden har brug for et privilegeret wrapper-script — ikke rå sudo crontab (det ville være en direkte eskalering til root for enhver, der får adgang til dashboardets session), men et snævert script med to kommandoer (list/set), der kun rører sin egen blok mellem de interne kommentarer. Installér én gang:
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
Webbrugeren kan afvige fra www-data — tjek, hvem sitets PHP-FPM-pulje kører som (ps -o user= -C php-fpm), og indsæt den i sudoers-linjen.
Den nye fil blev uploadet med forkert ejer — siden svarer “Access denied.”. Hvis filen public/crontab_monitor.php er uploadet via FTP/SFTP som en anden systembruger (f.eks. root) end sitets øvrige filer, kan webserveren ikke læse den. Sammenlign ejer og rettigheder med en nabofil og bring dem i overensstemmelse:
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

Diagnostik

36. Værktøjet er installeret, men viser “Ikke installeret”

Monitoren registrerer værktøjer via dpkg-query — APT-pakkedatabasen. Hvis værktøjet ikke er installeret via apt (manuelt, fra snap eller fra kildekode), ser dpkg det ikke.

# Tjek via dpkg: dpkg -l fail2ban | grep '^ii' dpkg -l auditd | grep '^ii' # Find stien til binærfilen: which ufw fail2ban-client auditctl # Test sudo som www-data: sudo -u www-data sudo fail2ban-client status sudo -u www-data sudo ufw status verbose

37. Fejlfinding (500, ingen data)

Fejl 500 — tjek logfilerne for PHP, nginx og selve monitoren:

tail -50 /var/log/nginx/error.log tail -50 /var/log/php*-fpm.log # Monitorens logfiler: tail -50 logs/monitor_$(date +%Y-%m-%d).log # Rettigheder på mapper: ls -la data/ tmp/ logs/
Dashboard på et hostingpanel (HestiaCP, ISPmanager, cPanel)? Der kører PHP ikke under www-data, men under brugerens konto (f.eks. admin — ejeren af websitemappen). Alle sudo-regler og gruppemedlemskaber (adm, systemd-journal) skal tilføjes til denne bruger, ellers viser modulerne “Ikke aktiv / 0”, selvom tjenesterne kører. Find den reelle PHP-bruger: ps -o user= -C php-fpm | sort -u eller ejeren af websitemappen stat -c '%U' /path/to/monitor. Brug derefter denne i stedet for www-data i alle kommandoer nedenfor. Autoinstallationen finder selv webbrugeren og tilføjer sudoers til denne.

Data vises ikke — næsten altid manglende sudo-rettigheder. Tjek den konkrete kommando som webbrugeren (erstat www-data med din egen). Flaget -n = uden adgangskode, som PHP — hvis den beder om adgangskode, findes reglen ikke i 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
Modulet skriver “Ikke aktiv” / “0”, selvom værktøjet kører (f.eks. viser sudo aa-status i terminalen profiler, mens siden “AppArmor” viser “Ikke aktiv”). Årsag: webbrugeren har ikke sudo-rettighed til dette moduls kommando. Tjek den ud fra listen ovenfor: hvis den beder om adgangskode — tilføj den manglende linje i /etc/sudoers.d/monitor (“Opsætning af sudo”). Hyppige “nye” kommandoer: /usr/sbin/aa-status (MAC), /usr/sbin/psad --Status (PSAD).
Hvis en bestemt side (Falco, ModSecurity, Auditd, åbne UFW-porte) er tom — tjek listen i afsnittet om sudo: sandsynligvis er apache2ctl, ausearch, aa-status eller ss ikke tilladt, eller webbrugeren er ikke i grupperne adm/systemd-journal (derfra læses logfilerne for fail2ban/auth/modsec og journalctl — Falco og kernehændelser).

38. Siden er tom, selvom der findes data på serveren

Symptom: der findes data på serveren (synligt via shell), men siden viser “ingen data” eller forkert status — f.eks. skriver AIDE “Ikke initialiseret”, selvom databasen er oprettet.

Årsagen er open_basedir: mange paneler og hostingudbydere begrænser PHP-FPM-puljen til domænets katalog, så PHP-funktionerne file_exists(), file_get_contents(), filemtime() blokeres på systemstier (/var/lib/aide, /var/log, /proc…). Monitor omgår dette ved at læse sådanne stier med almindelige systemkommandoer (cat, test, stat).

# Er filen synlig via shell (sådan læser monitor): sudo -u www-data bash -lc 'test -e /var/lib/aide/aide.db && echo VISIBLE || echo NO' # Aktuel open_basedir-værdi for domænets pulje: grep -ri open_basedir /etc/php/*/fpm/pool.d/ 2>/dev/null
Hvis shell “ser” filen (VISIBLE), men siden ikke gør — er det open_basedir. Den rigtige løsning er læsning med systemkommandoer (allerede gjort for AIDE og Netværksmonitor). Det er ikke nødvendigt og mindre sikkert at udvide open_basedir til /var, /proc.

39. SSL-siden virker ikke

Monitoren tjekker certifikater ved at oprette forbindelse direkte til domænerne via port 443. Hvis domænet ikke er tilgængeligt fra selve serveren, eller porten er lukket af firewallen, mislykkes tjekket.

# Tjek certifikatet manuelt: echo | openssl s_client -connect monitor.example.com:443 2>/dev/null \ | openssl x509 -noout -dates # Tjek tilgængeligheden: curl -I https://monitor.example.com
Monitoren henter domænerne automatisk fra nginx-konfigurationerne (/etc/nginx/sites-enabled/, /etc/nginx/conf.d/) og Apache (/etc/apache2/sites-enabled/) plus den aktuelle host fra HTTP_HOST.
Automatisk registrering af underdomæner. Underdomæner registreres automatisk fra de offentlige Certificate Transparency-logge og kontrolleres over netværket — selv hvis de er placeret på andre servere. Du behøver ikke at tilføje noget manuelt.

40. Kun én database vises ud af flere

Monitoren forbinder til MySQL som brugeren fra config.php, der kun har adgang til sin egen database. MySQL viser kun databaser med privilegier i information_schema — derfor er de øvrige ikke synlige.

For at monitoren kan se alle databaser, skal du give denne bruger læserettigheder (én gang som root; indsæt brugernavnet fra config.php):

sudo mysql -u root GRANT SELECT, PROCESS, SHOW DATABASES ON *.* TO 'DB_USER'@'localhost'; FLUSH PRIVILEGES; EXIT;
SELECT ON *.* giver kun læseadgang — man kan ikke ændre, slette eller oprette noget, hvilket er sikkert til overvågning.
Uden denne GRANT ser dashboardet kun sin egen database — det er ikke en fejl, men en rettighedsbegrænsning. Dashboardet bruger ikke sudo mysql: listen over databaser hentes via dets egen PDO-forbindelse.

41. PostgreSQL vises ikke på siden “Database”

PostgreSQL kræver adgang på postgres-brugerniveau, som panelets webbruger ikke har. Det er ikke sikkert at åbne en bred sudo psql fra PHP — i stedet kalder panelet en snæver wrapper uden parametre, der kun udskriver version, antal forbindelser og en liste over databaser med størrelser. Opret den:

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 # i /etc/sudoers.d/monitor (bruger = den, som PHP-FPM kører under): # www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-pgstat
Bruger du ikke PostgreSQL — fjern linjen monitor-pgstat fra sudoers (trin 13 i den manuelle installation), og opret ikke selve scriptet: PostgreSQL-kortet forbliver blot inaktivt.

42. En alert er udløst — hvad gør man

Dashboardet viser hvad der sker; nedenfor står hvad du skal gøre i typiske situationer. Generelt princip: gå ikke i panik, hold det op mod legitim aktivitet (dine handlinger, opdateringer, backups), og reagér efter alvorlighed.

  • Angrebskort / mange fail2ban-bans — det er normalt for enhver server på internettet (bots hamrer konstant på SSH/web). Det vigtigste er, at bans udløses. Sørg for, at SSH-login kun sker med nøgle (adgangskode slået fra), og at din IP står i ignoreip.
  • ModSecurity blokerede forespørgsler — WAF'en afværger angreb mod sitet, det er dens opgave. Hvis din legitime trafik blokeres (falsk positiv) — find rule id i detaljerne og tilføj en undtagelse i CRS-konfigurationen.
  • AIDE: ændrede filer — sammenhold listen med det, du har gjort (pakkeopdatering, redigering af konfigurationer — normalt). Ændringer i systembinære filer, du ikke har rørt, er grund til at være på vagt. Opdatér AIDE-databasen efter legitime ændringer.
  • debsums: ændrede binære filer/biblioteker (uden for /etc, uden for /usr/share) — potentiel manipulation. Tjek pakken: debsums PACKAGE_NAME, og geninstallér den ved tvivl (apt install --reinstall).
  • ClamAV / maldet: fundet trussel — tjek filen i karantæne, åbn den ikke. Hvis det er en webshell i sitets katalog — isolér serveren og find indgangspunktet (sårbart plugin, lækket adgang).
  • Falco: kritiske hændelser (start af shell i en container, adgang til følsomme filer) — analysér hændelsen: hvis proces, hvad der blev startet. Ofte er det legitim admin-aktivitet.
  • Ekstern eksponering: database/cache i rødt — luk det straks: bind tjenesten til 127.0.0.1, eller luk porten i UFW. Det er et reelt hul.
  • SSL udløber / er udløbet — forny certifikatet (Let's Encrypt fornyer selv; ellers tjek certbot renew eller indstillingerne i panelet).
  • Sikkerhedsopdateringer venter — installér dem: sudo apt update && sudo apt upgrade; genstart serveren efter en kerneopdatering.
Tegn på et reelt indbrud (ukendte processer/brugere, ændrede binære filer, udgående spam, ukendte cron-jobs): kobl serveren fra ekstern adgang, tag en backup til analyse, og hvis data er kritiske, så rejs en ren server fra en betroet backup — det er svært at fjerne et rootkit sikkert.
Arcivéo - Security Monitor © 2026