Dette er en vejledning til installation, opsætning og vedligeholdelse af Arcivéo Security 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 Security 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.
To arbejdsrytmer. Panelets sider spørger værktøjerne i det øjeblik du åbner dem — du ser altid den aktuelle tilstand. Derudover kører baggrundsjob efter en plan (cron):
Den fulde liste over job findes i afsnittet “Alle cron-job ét sted”.
Scoren starter på maksimum og falder for hvert fundet problem:
PermitRootLogin yes) — −20PasswordAuthentication yes) — −10X11Forwarding slået til, MaxAuthTries over 3 eller sshd_config læsbar for alle konti — −5TRACE er slået til, eller headeren Strict-Transport-Security eller X-Frame-Options mangler — −5Resultat: 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.
Der er fire kanaler: Telegram, Email, webhook og push i browseren. De er uafhængige af hinanden — slå netop dem til, du ønsker, gerne alle fire. Ad de samme kanaler går den daglige sikkerhedsrapport, belastningsalarmerne og fundene fra hændelsessensoren; de indstilles én gang, her, i afsnittet “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.Webhook. En enkelt adresse, der tager imod en POST, dækker Slack, Discord, Mattermost, n8n og din egen handler. “Indstillinger” → Webhook: indsæt adressen, og slå kontakten til.
{"text": …}, til Discord {"content": …} (Discord afviser beskeder på over 2000 tegn, så teksten forkortes);text, event, severity, source, count, host, ts — beskedteksten behøver ikke at blive tolket igen.Push-notifikationer. Beskeden kommer direkte i browseren, og hvis panelet er lagt på telefonens hjemmeskærm, som en almindelig app-notifikation — uden bot og uden mailserver imellem. “Indstillinger” → Push-notifikationer: slå kontakten til, og tryk på “Tilslut denne enhed” på hver enhed, der skal modtage notifikationer. Tælleren “Tilsluttede enheder” viser, hvor mange der er.
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.
Panelet er lukket bag log ind med adgangskode og, hvis det er slået til, bag IP-filteret. Et program kan ikke bruge nogen af delene, så eksterne systemer har deres egen indgang — to adresser kun til læsning, beskyttet med et token. Tokenet ændrer intet på serveren: det kan kun hente tal.
Slå til — “Indstillinger” → “API kun til læsning”: kontakten “Slå API til”; tokenet oprettes automatisk ved første gemning. Knappen “Nyt token” udsteder et andet og afskærer i samme øjeblik alle, der brugte det forrige.
/api/status.php — JSON: sikkerhedsscore, modulernes tilstand, den seneste belastningsmåling med de tungeste processer og sikkerhedshændelserne i de seneste 24 timer;/api/metrics.php — de samme tal i Prometheus’ tekstformat (målingerne arciveo_*: arciveo_security_score, arciveo_fail2ban_banned, arciveo_cpu_busy_pct og så videre).Kan din klient ikke sætte en header, accepteres tokenet også som parameter — ?token=…. Vær opmærksom på, at det i den form havner i webserverens adgangslog, så headeren er at foretrække.
Prometheus. En færdig blok til scrape_configs:
api disabled — API’et er slået fra i indstillingerne. Afviste forespørgsler skrives til applikationsloggen sammen med afsenderens IP, så gætteri på tokenet kan ses på siden “Applikationslog”.
Panelet installeres på hver server for sig og svarer godt på spørgsmålet “hvordan har denne maskine det”. På spørgsmålet “hvordan har alle mine maskiner det” svarer det ikke — derfor kan hvert panel sende et kort sammendrag til kontoen, hvor serverne ses i én liste.
Det du henter på kontoen my.arciveo.com → afsnittet “Mine servere”: her udstedes et token (af formen fk_…), og modtagerens adresse angives: https://my.arciveo.com/api/fleet.php. Tokenet er ét pr. konto — det samme for alle dine servere.
Det du indstiller i panelet — “Indstillinger” → “Serveroversigt”: modtagerens adresse, tokenet, servernavnet (sådan som det står i listen; lades det tomt, bruges panelets domæne) og kontakten “Send sammendraget”. Knappen “Send nu” prøver forbindelsen med det samme, uden at vente på planen.
Derefter går sammendraget via cron, hvert 15. minut:
Hvad der præcis sendes: serverens navn og domæne, styresystem, oppetid, PHP-version; sikkerhedsscoren; modulernes tilstand (UFW, antal Fail2ban-jails, dagens blokeringer, om CrowdSec, Suricata og Falco kører, ClamAV-trusler, AIDE-ændringer, Lynis-indeks, ventende opdateringer, om genstart er nødvendig, dage til certifikatet udløber, antallet af farligt åbne porte); den seneste belastningsmåling (load, CPU, RAM, disk, inoder); hændelsestællerne for de seneste 24 timer og den seneste kritiske hændelse. Logge, adgangskoder og filindhold er ikke med i sammendraget.
sudo crontab -l) og hvad knappen “Send nu” svarer. Fejl ved afsendelse skrives til applikationsloggen med mærket FLEET — dér kan man se, om tokenet blev afvist (HTTP 401), eller om selve forbindelsen aldrig kom i stand.
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. Vinduet på 24 timer er standard: knapperne øverst skifter det til 7 dage eller 30 dage.
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.
To lagringsdybder. De “rå” femminutters øjebliksbilleder lever et døgn (plus en times margen, så det ældste punkt på grafen stadig har en forgænger at regne ud fra). Hver afsluttet time foldes sammen til én række; denne timeserie gemmes i 30 dage, og det er netop den, visningerne “7 dage” og “30 dage” læser. En måneds historik koster dermed omkring 720 rækker i stedet for cirka 8600.
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.
Tungeste processer. Under graferne er der to tabeller med de fem processer, der bruger mest CPU:
Begge tabeller beskriver altid de seneste 24 timer, også når graferne viser en måned: et øjebliksbillede af processerne findes kun i femminutters-rækkerne, og de gemmes ikke længere end et døgn.
ps, PHP-scriptet, der indsamler, og cron/sudo-kæden over det) udelades af listen — ellers ville de ligge øverst i hvert øjebliksbillede: ps viser næsten 100 % CPU i det øjeblik, den starter. Andre cron-job, der kørte i samme minut, kommer derimod med, og det er netop det, tabellen er til for.
Belastningsalarmer (afsnittet “Indstillinger” → “Belastningsalarmer”) — når tærsklen for CPU/RAM/disk/inoder overskrides, sender panelet en notifikation via alle tilslåede kanaler (Telegram, Email, webhook, push — de samme som til dagsrapporten; til alarmerne skal der ikke slås noget ekstra til) og endnu en, når værdien er tilbage på normalt niveau. Så længe tærsklen holdes, gentages beskeden ikke: den næste notifikation kommer først efter en cyklus “blev normal igen → blev overskredet på ny”.
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.
Dagsrapporten svarer på spørgsmålet “hvordan har serveren det”. Sensoren svarer på et andet — “hvad skete der lige nu”. Hvert 5. minut spørger den de hurtige kilder og noterer kun det, der har ændret sig siden den forrige kontrol; siden “Sikkerhedshændelser” i menuen viser listen over fund.
De langsomme kontroller — Lynis, debsums, pakkeopdateringer, SSL-udløb — rører sensoren ikke: deres tal ændrer sig alligevel kun en gang i døgnet og hører til dagsrapporten.
Hvad den lægger mærke til — ni kilder:
[Priority: 1] løfter fundet til kritisk;FOUND-linjer i scanningsloggen;root (kritisk) og et log ind fra en adresse, der ikke er set før (advarsel);Et værktøj, der ikke er installeret, eller hvis log panelet ikke kan læse, tier ganske enkelt — det er hverken en fejl eller en hændelse.
data/secwatch_state.json), og den første kørsel skriver kun dette mærke. Ellers ville en tilslået overvågning give en notifikation om alt, hvad loggene har samlet gennem måneder.
Indstilling — “Indstillinger” → “Overvågning af hændelser”:
23-7, hvor advarsler ikke sendes.Notifikationerne går ad de samme kanaler som dagsrapporten (Telegram, Email, webhook, push) — der skal ikke slås noget ekstra til. Alle fund skrives til listen, uanset om der blev sendt en notifikation, og gemmes i 90 dage.
Hændelseslisten. Filtre: periode (24 timer, 7, 30 eller 90 dage), alvorlighed og kilde; de seneste 500 poster vises. Knappen “Tjek nu” kører nøjagtig samme gennemgang som cron — praktisk lige efter opsætningen, så du ikke skal vente fem minutter; den angiver også årsagen, når der ikke blev sendt nogen notifikation (“under alvorlighedstærsklen”, “stille timer”, “ingen notifikationskanal er sat op”). Den røde tæller ved menupunktet er antallet af kritiske hændelser i de seneste 24 timer.
Adressekortet. Et klik på en række i hændelseslisten eller i blokken Relaterede adresser åbner alt, hvad der vides om én adresse: tidslinjen over dens hændelser, landet og på første linje en konklusion. En række i listen åbner kortet, når hændelsen handler om præcis én adresse; er der flere, er det adresserne inde i rækken, der er links. Der er fire konklusioner:
Under tidslinjen ligger blokken Hvad der skete på serveren samtidig: hændelser, der slet ingen adresse har. AIDE ved ikke, hvem der ændrede filen, ClamAV ved ikke, hvem der bragte den inficerede. Vist er dem, der falder inden for adressens aktivitet og de seks timer efter. Netop loginet sammen med det, der fulgte, skiller et forsøg fra reel adgang.
Plan. Jobbet lægges i roots crontab (sudo crontab -e), forskudt 2 minutter i forhold til måleindsamlingen, så de to ikke starter samtidig:
php cron/security_watch.php. Wrapperen finder alle installationer af panelet på serveren og kører kontrollen på vegne af webstedets ejer — med præcis de sudo-rettigheder, panelet bruger fra nettet. Et direkte kald fra roots crontab ville oprette tilstandsfilen data/secwatch_state.json med root som ejer, og knappen “Tjek nu” ville holde op med at virke.
Siden “Webserver” analyserer adgangsloggen og viser, hvor mange forespørgsler der var, hvor stor en del af dem der endte med fejl, og hvem der stod bag dem. ModSecurity svarer på spørgsmålet “hvad blev blokeret”, denne side på spørgsmålet “hvad nåede overhovedet frem til webstedet”.
Hvad man ser: antal forespørgsler, RPS, fejlandel, en separat 5xx-tæller og den leverede datamængde; en graf over forespørgsler pr. time; fordelingen af koderne 2xx/3xx/4xx/5xx; hyppige adresser, hyppige IP-adresser, hyppige fejl (kode plus sti) og klienter (User-Agent). Perioden: 24 timer eller 7 dage.
Kilden er adgangsloggen i formatet combined, så både Nginx og Apache passer, og der kræves ikke noget ekstra modul. Panelet leder efter loggen blandt standardfilerne:
/var/log/nginx/access.log/var/log/apache2/access.log/var/log/apache2/other_vhosts_access.log/var/log/httpd/access_logUd over dem kigger panelet på filer med navnene *access*.log og *requests*.log i /var/log/nginx/, /var/log/apache2/ og /var/log/httpd/. Sådan findes også en log, som et websted skriver til sin egen fil med direktivet CustomLog — for eksempel arciveo-monitor_requests.log, som Arcivéo-installationsprogrammet opretter.
Der læses kun én log: når Nginx står foran Apache, ville en sammenlægning af to logge tælle hver forespørgsel to gange. Panelet tager den første log på listen ovenfor, der er skrevet til inden for det seneste døgn (filerne fundet via navnemønster prøves derefter, nyeste først); er der ikke skrevet til nogen i et døgn, tages den senest ændrede ikke-tomme. En log, som logrotate har tømt, eller som er tilbage fra en stoppet webserver, skjuler derfor ikke den aktive. Den sidste del af loggen læses (3 MB), og resultatet caches i 5 minutter — på et travlt websted kan den valgte periode derfor være ufuldstændigt dækket; den faktiske dækning står over grafen.
adm, og webbrugeren er ikke med i den. Arcivéo-installationsprogrammet føjer webbrugeren til gruppen; efter en manuel installation hjælper en lille wrapper fra root, som kun må én ting — vise loggen (ModSecurity-siden fungerer på samme måde). Wrapperen vælger loggen efter de samme regler som panelet. Kommandoen vises på selve siden; her er den også. Indsæt den i sin helhed — det er én kommando:
Webbrugeren kan være en anden end www-data — kontrollér, hvilken bruger webstedets PHP-FPM-pulje kører som (ps -o user= -C php-fpm), og skriv den ind i sudoers-linjen. Indeholder loggens navn hverken access eller requests, tilføjer du dens sti i starten af linjen L=… inde i wrapperen.
Forsøg med kendte exploits. Panelet sammenligner forespørgsler i loggen med signaturer for omkring tyve udbredte exploits: PHP-CGI, mappetraversering i Apache, PHPUnit, Log4Shell og sårbarheder i routere, kameraer og VPN-gateways. For hvert forsøg angiver det, om det kan virke på denne server, ud fra fakta: de installerede versioner af Apache og PHP, om Java findes, og hvilken svarkode serveren gav på filforespørgslen. Kun det, der faktisk kan virke, markeres med rødt.
Hærdning af webserveren. Panelet forespørger hvert websted på serveren via 127.0.0.1 og kontrollerer, hvad en besøgende modtager: om webserverens og PHP’s versioner er synlige, om metoden TRACE er slået til, og om beskyttelsesheaderne Strict-Transport-Security, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy og Content-Security-Policy findes. Webstederne hentes fra den adresse, panelet åbnes på, og fra filerne for virtuelle værter, hvis panelet kan læse dem. Resultatet opdateres hvert 10. minut.
Mangler der noget, vises én kommando under tabellen. Den opretter en separat fil, zz-arciveo-hardening.conf, og genindlæser først webserveren, når konfigurationstesten er bestået; headers, som webstedet allerede sender, dubleres ikke. CSP tilbydes ikke som én linje: politikken bygges til det konkrete websted, ellers holder det op med at indlæse sine egne scripts, styles og skrifttyper. Fortryd ændringen på Apache:
ServerSignature) markeres ikke, når webserverens version allerede er skjult: uden version viser den kun servernavnet og værtsnavnet.
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.Panelet kører allerede, og på den samme server er der brug for endnu et websted — med sit eget domæne ved siden af monitoren. Efter den automatiske opsætning er serveren en helt almindelig Apache + PHP-FPM, så webstedet har brug for tre ting: sin egen mappe, sin egen vhost og sit eget certifikat. Panelet rører du ikke ved: det overvåger hele serveren, og en anden kopi til det andet domæne er ikke nødvendig.
site2.example.com er adressen på det nye websted. Det kan både være et selvstændigt domæne (mycompany.com) og et underdomæne (shop.mycompany.com) — for Apache er der ingen forskel, kun DNS-posten (trin 1) og udstedelsen af certifikatet (trin 5) er forskellige. site2 er blot et kort navn på webstedet: sådan hedder mappen /var/www/site2 og konfigurationsfilen site2.conf. Det har intet med domænet at gøre, Apache tager kun adressen fra ServerName; navnet kan være hvad som helst — til shop.mycompany.com er shop f.eks. praktisk: mappe /var/www/shop, konfiguration shop.conf.
1. DNS. Opret i DNS-panelet hos din registrator en A-post til denne servers IP:
Tjek efter et par minutter: dig +short site2.example.com skal returnere serverens IP.
2. Webstedets mappe.
3. vhost. Blokken indsættes i terminalen i sin helhed — stien til PHP-FPM-socket findes af sig selv:
4. Slå webstedet til, og tjek konfigurationen før genindlæsning:
5. SSL. certbot er allerede installeret af den automatiske opsætning; på dette tidspunkt skal DNS pege på serveren:
Et tredje domæne og de følgende tilføjes på samme måde — gentag trin 1–5 med et andet domæne og en anden mappe.
Host ingen ServerName (besøg via IP eller et fremmed domæne, der peger på din server), leverer Apache det alfabetisk første aktiverede websted fra /etc/apache2/sites-enabled/. Standardwebstedet 000-default slås fra af den automatiske opsætning, så den “vagthavende” rolle bliver hos panelets vhost (arciveo-monitor.conf) — det påvirker ikke websteder, der åbnes med deres eget navn. Skal et andet websted åbne via IP, så navngiv dets fil, så den kommer først alfabetisk (for eksempel 000-site2.conf).
site2_error.log og site2_access.log i /var/log/apache2/.
.htaccess (frontcontroller), og et indlejret websted ville levere noget andet, end du forventer. Hold webstederne ved siden af hinanden: /var/www/monitor, /var/www/site2.
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;security-watch-all.sh → /usr/local/bin/ (chmod +x) — kører panelets cron/security_watch.php på vegne af webstedets ejer (siden “Sikkerhedshændelser”, linjen 2-57/5 i crontab ovenfor); security_watch.php hører allerede til panelet og skal ikke installeres separat;fleet-push-all.sh → /usr/local/bin/ (chmod +x) — sender serverens sammendrag til kontoen via panelets cron/fleet_push.php (linjen 3,18,33,48 ovenfor);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.