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.
Installationen af panelet er beskrevet på separate trinvise sider. Vælg en metode:
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.
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.
Scoren starter på maksimum og falder for hvert fundet problem:
PermitRootLogin yes) — −20Resultat: 80+ = Beskyttet, 60–79 = Vær opmærksom, <60 = I fare.
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.
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:
@BotFather i Telegram → /newbot → få en token af typen 123456:ABC....@userinfobot, eller åbn https://api.telegram.org/bot<TOKEN>/getUpdates og find "chat":{"id":...}.Email. To metoder at vælge imellem under “Indstillinger” → Email:
re_...) og et bekræftet afsenderdomæne.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.
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):
my.arciveo.com → afsnittet “Licenser” / “Licensaktivering” — kopiér koden ARCIVEO-….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”.Panelet verificerer nøglen kryptografisk: signaturen, bindingen til domænet og gyldighedsperioden.
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.
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. 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”);TIMEZONE — PHP-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.
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.
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.
ufw enable skal du tillade SSH (ufw allow OpenSSH), ellers mister du adgangen til serveren.
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.
Blokerer automatisk en IP efter for mange mislykkede loginforsøg. Analyserer logfiler fra SSH, nginx, Apache og andre tjenester.
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:
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”):
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:
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”.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.
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:
@reboot. Samtidig sætter kommandoen create … -exist grænsen maxelem 300000 (standard er 65536 — level 1 passer ikke, du får “Hash is full”):
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.
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.
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).
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:
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.
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.
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:
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.
/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:
chmod 755 /var/lib/aide og cron-kontrol kl. 02:00 — der kræves intet manuelt.
sudo aideinit && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db.
Antivirusscanner til Linux. Særligt nyttig til at kontrollere /var/www for PHP-shells og skadelig kode.
enable --now? Tre typiske årsager:
1. Linjen Example står stadig i konfigurationen — clamd nægter at starte, så længe den er der:
2. Signaturdatabasen er ikke hentet — clamd starter ikke uden den:
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).
sudo journalctl -u clamav-daemon -n 30 --no-pager.
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.
Linux Malware Detect (LMD) — malware-scanner målrettet webtrusler: PHP-shells, webbackdoors, downloadere. Bruger ClamAV-motoren og supplerer den med egne signaturer.
maldet --report.
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.
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”.
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).
/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:
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.
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.
/etc/passwd, skrivning til systemkataloger). Nul kritiske på et døgn på en rolig server er en sund tilstand.
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.
ModSecurity — en web-firewall (WAF) til Apache eller Nginx. Blokerer angreb på applikationsniveau: SQL-injektioner, XSS, path traversal, scannere.
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:
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.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.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.---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.
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.
ausearch (/usr/sbin/ausearch) og om nødvendigt fra /var/log/audit/audit.log med kommandoen tail. Begge skal være i sudoers.
Overvåger tjenester (nginx, php-fpm, mysql osv.) og genstarter dem, hvis de går ned. Kan sende advarsler til e-mail.
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.
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:
conf.d med httpd på 2812 og et sæt tjek — på en ny installation behøver du ikke konfigurere manuelt.
PSAD analyserer iptables-loggen og opdager portscanninger og netværksangreb, idet hver kilde tildeles et trusselsniveau (1–5). Supplerer fail2ban og Suricata.
psad --Status (skal være i sudoers). Uden iptables-logning vil siden være tom — det er normalt, indtil der har været scanninger.
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).
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.
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.
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/.
Wrapperen debsums-scan.sh finder selv dashboardets data/ — stien skal ikke angives.
/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.
Lynis kører manuelt eller via cron. Rapporten skal gemmes i projektets mappe data/lynis/ — monitoren læser filen lynis-report.dat.
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:
Logwatch skal gemme daglige rapporter i projektets mappe data/logwatch/ i formatet .txt. Monitor viser den seneste rapport og arkivet.
Netværksovervågning kræver ingen installation — det er en indbygget dashboardside. Den viser serverens netværksstatus fra lokale kilder:
/proc/net/dev;ip;ss;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:
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.
Den indbyggede side viser tre ting:
df); skalaen bliver rød ved ≥90%;lsblk), kun de reelle (loop/snap er skjult);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/.
Wrapperen smart-scan.sh finder selv dashboardets data/ — stien skal ikke angives. Internt udelukker lsblk -e7,11 loop/cdrom.
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.
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.
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”.
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.
Siden “Angrebskort” bestemmer landet ud fra IP med kommandoen geoiplookup. Uden GeoIP-pakken kan landene ikke bestemmes, og der vises ingen punkter på kortet:
/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.
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.
127.0.0.1 (bind-address i MySQL/PostgreSQL-konfigurationen, bind 127.0.0.1 i Redis) eller luk porten i UFW.
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.
/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”.
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.
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:
Opdatering til en ny version. Tag først en backup. Læg derefter kodefilerne op igen, og bevar dine data:
public/, includes/, assets/, cron/, database/ samt roddens .htaccess (frontcontroller — routingen må ikke beholdes fra den gamle version), manifest.json, sw.js;config.php (databasedata), data/ (rapporter), logs/, tmp/ (sessioner og cache).SSH_FX_PERMISSION_DENIED — Permission 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.
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.
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.
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:
config.php, data/.mysqldump på den gamle → import på den nye; ret databasedata i config.php.adm, cron-job.Hvis du ikke kan logge ind, kan alt rettes direkte i databasen fra serveren. Åbn databasen (navnet står i config.php):
Mistet WebAuthn-nøgle (andet trin fejler) — slå 2FA fra, log ind med adgangskode og registrér en ny nøgle:
Glemt adgangskode — angiv en ny hash (generér den på serveren og indsæt den):
Låst dig selv ude med IP-filteret — slå begrænsningen fra:
sudo mysql på serveren eller phpMyAdmin / databaseafsnittet i hostingpanelet. Slå WebAuthn og IP-filteret til igen efter gendannelsen.
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.
sudo crontab -l og at cron-tjenesten er aktiv.
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:
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.
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./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:
/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.
/usr/local/bin/, log — /var/log/arciveo-cron.log) — du skal ikke gøre noget manuelt.
/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.
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:
stat -c %U /path/to/monitor.
sudo crontab -e), ellers vil det køre to gange.
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:
www-data — tjek, hvem sitets PHP-FPM-pulje kører som (ps -o user= -C php-fpm), og indsæt den i sudoers-linjen.
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:
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.
Fejl 500 — tjek logfilerne for PHP, nginx og selve monitoren:
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 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).
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).
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).
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.
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.
/etc/nginx/sites-enabled/, /etc/nginx/conf.d/) og Apache (/etc/apache2/sites-enabled/) plus den aktuelle host fra HTTP_HOST.
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: listen over databaser hentes via dets egen PDO-forbindelse.
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:
monitor-pgstat fra sudoers (trin 13 i den manuelle installation), og opret ikke selve scriptet: PostgreSQL-kortet forbliver blot inaktivt.
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.
ignoreip./etc, uden for /usr/share) — potentiel manipulation. Tjek pakken: debsums PACKAGE_NAME, og geninstallér den ved tvivl (apt install --reinstall).127.0.0.1, eller luk porten i UFW. Det er et reelt hul.certbot renew eller indstillingerne i panelet).sudo apt update && sudo apt upgrade; genstart serveren efter en kerneopdatering.