FAQ

Tämä on Arcivéo Monitorin asennus-, määritys- ja ylläpito-opas. Osiot on ryhmitelty: yleiskatsaus, hallintapaneelin käyttöönotto, tietoturvatyökalujen liittäminen, sisäänrakennetut moduulit ja vianmääritys. Komennot voi kopioida oikealla olevalla painikkeella.

Näin pääset alkuun

01. Paneelin asennus — valitse tapa

Paneelin asennus on omilla vaiheittaisilla sivuillaan. Valitse tapa:

Jos et ole varma — valitse automaattinen. Tämä opas pysyy yhtenäisenä lähteenä SSL:stä, työkaluista, cronista ja diagnostiikasta — asennussivut viittaavat sen osioihin ilman toistoa.

Yleiskatsaus

02. Mikä on Arcivéo Monitor

Arcivéo Monitor on palvelimen tietoturvapaneeli. Se kerää tiedot asennetuista työkaluista (Fail2ban, UFW, Lynis, ModSecurity, AIDE, ClamAV, Auditd, CrowdSec, Suricata, Falco ym.) ja näyttää ne yhtenäisessä käyttöliittymässä koontinäytön, hyökkäyskartan ja kunkin työkalun yksityiskohtaisten sivujen kera.

Monitor ei ole aktiivinen suojauskeino — se ei estä hyökkäyksiä itse. Sen tehtävä on koota tiedot jo toimivista työkaluista ja esittää ne selkeässä muodossa.

03. Miten monitori toimii palvelimella

Monitori toimii vain paikallisesti — se on asennettava samalle palvelimelle, jota se valvoo. SSH:ta tai etä-API:a ei käytetä.

Kaikki komennot (fail2ban-client, ufw status, ipset list jne.) paneeli suorittaa web-palvelimen käyttäjänä (yleensä www-data, hosting-paneeleissa sivuston tili) suppealla oikeusjoukolla sudo — vain tietyille työkaluille, ilman yleistä root-oikeutta. Tulokset jäsennetään ja näytetään selaimessa.

Useille palvelimille asenna monitori kullekin erikseen, omalla yksilöllisellä domainilla.

04. Miten turvallisuusarvosana lasketaan

Arvosana alkaa maksimista ja laskee jokaisesta havaitusta ongelmasta:

  • UFW ei ole käytössä — −30
  • Fail2ban ei ole käynnissä (ei aktiivisia jail-ryhmiä) — −25
  • Ei WebAuthn-avaimia — −15
  • Lynis hardening index < 60 — −20; 60–79 — −10
  • IPset ipsum ei ole ladattu — −10
  • ClamAV löysi uhkia — −20
  • AIDE havaitsi tiedostomuutoksia — −15
  • SSL vanhentunut — −30, vanhenee <14 päivässä — −15, <30 päivässä — −5
  • CrowdSec asennettu, mutta ei käynnissä — −5
  • Suricata asennettu, mutta ei käynnissä — −5
  • Tietokanta/välimuisti (MySQL, PostgreSQL, Redis…) tavoitettavissa ulkoa — −10
  • root-kirjautuminen SSH:lla sallittu (PermitRootLogin yes) — −20
  • Turvapäivityksiä odottaa asennusta — −5

Tulos: 80+ = Suojattu, 60–79 = Huomio, <60 = Uhattuna.

ClamAV-, AIDE-, CrowdSec- ja Suricata-vähennykset koskevat vain, jos työkalu on asennettu. Lynis ja AIDE ilman alustettua tietokantaa näkyvät tilassa ”ei tietoja” eivätkä laske pistemäärää. Tämän päivän hyökkäysten määrä näkyy koontinäytöllä, mutta ei vaikuta turvallisuusarvosanaan.

Asetukset ja lisenssi

05. WebAuthn — kaksivaiheinen tunnistautuminen

WebAuthn on salasanaton tunnistautumisstandardi laitteistoavaimella. Tukee YubiKeytä, Touch ID:tä, Face ID:tä, Windows Helloa ja Passkeytä.

Salasanalla kirjautumisen jälkeen järjestelmä pyytää vahvistusta rekisteröidyllä avaimella. Vaikka salasana vuotaisi, ilman fyysistä avainta tai biometriikkaa kirjautuminen ei onnistu.

Ota käyttöön avaamalla sivuvalikosta WebAuthn-avaimet ja napsauttamalla ”Rekisteröi avain”. Rekisteröi heti kaksi avainta: jos ainoa avain katoaa tai rikkoutuu, kirjautuminen paneeliin sillä ei ole mahdollista.

WebAuthn toimii vain HTTPS-yhteydellä. HTTP-yhteydellä avaimen rekisteröinti ja sillä kirjautuminen eivät ole käytettävissä.

06. Ilmoitukset: Telegram ja sähköposti

Paneeli voi lähettää tietoturvaraportin Telegramiin ja sähköpostiin (painikkeella ja aikataulun mukaan). Määritetään kohdassa ”Asetukset”.

Telegram. Tarvitset botin tunnisteen ja chat id:n:

  1. Kirjoita Telegramissa @BotFather/newbot → saat tunnisteen muotoa 123456:ABC....
  2. Lähetä uudelle botillesi mikä tahansa viesti (jotta se voi vastata sinulle).
  3. Selvitä oma chat id:si: kirjoita botille @userinfobot tai avaa https://api.telegram.org/bot<TOKEN>/getUpdates ja etsi "chat":{"id":...}.
  4. Liitä tunniste ja chat id kohtaan ”Asetukset” → Telegram ja paina ”Tallenna ja lähetä testi”.

Sähköposti. Kaksi tapaa valittavana kohdassa ”Asetukset” → Sähköposti:

  • SMTP — palvelin, portti (465/SSL tai 587/TLS), postilaatikkosi käyttäjätunnus ja salasana;
  • Resend — nykyaikainen API: anna API-avain (re_...) ja vahvistettu lähettäjän verkkotunnus.
Painike ”Lähetä testi” tarkistaa kanavan heti. Automaattisen raportin aikataulu — cronin kautta (osio ”Kaikki cron-tehtävät”): se käynnistää lähetyksen, ja kanavat haetaan asetuksista.

Raportin tila: ”HUOMIO” tai ”OK”. Otsikoksi tulee ”HUOMIO” vain todellisen ongelman tai odottavan toimenpiteen yhteydessä: ClamAV löysi uhan, AIDE havaitsi tiedostomuutoksia, kriittisiä Falco-tapahtumia (Emergency/Alert/Critical viimeisen 24 h aikana), Monitissa kaatunut palvelu, uudelleenkäynnistys tarvitaan, SSL vanhenee (≤14 päivää) tai tietoturvapäivitykset odottavat. Taustakohina — bottien SSH-arvausyritykset, fail2banin estämät IP-osoitteet, Suricatan hälytykset, Lynisin varoitukset ja jo torjutut ModSecurity-pyynnöt — ei nosta tilaa, joten tällaiset luvut raportissa eivät itsessään tarkoita ”HUOMIO”-tilaa.

07. Lisenssi — syöttö ja aktivointi

Yksityiskohtaiset valvontamoduulit (Lynis, UFW, ModSecurity, hyökkäyskartta, AIDE, ClamAV ym.) avautuvat, kun sinulla on voimassa oleva lisenssi. Ilman sitä koontinäyttö, asetukset ja tili toimivat, mutta moduulit näyttävät kortin ”Lisenssi vaaditaan”.

Oston jälkeen tililtä löytyy aktivointikoodi muodossa ARCIVEO-XXXX-XXXX-XXXX-XXXX. Se on ”aktivoitava” paneelisi verkkotunnukselle — tämä muuntaa koodin allekirjoitetuksi lisenssitiedostoksi (lohko [license]), jonka liität paneeliin.

Näin aktivoit (3 vaihetta):

  1. Ota aktivointikoodi. Tili my.arciveo.com → osio ”Lisenssit” / ”Lisenssin aktivointi” — kopioi koodi ARCIVEO-….
  2. Aktivoi koodi verkkotunnuksellesi. Avaa samalla tilillä ”Lisenssin aktivointi”, syötä: aktivointikoodi, sähköpostisi ja paneelin verkkotunnus (osoite, jossa monitori avautuu, esim. monitor.example.com). Napsauta aktivoi — järjestelmä luo tähän verkkotunnukseen sidotun lisenssitiedoston ja näyttää sen kentässä, jossa on painike ”Kopioi”.
  3. Liitä avain paneeliin. Kopioi koko lisenssin teksti → avaa paneelissa ”Asetukset” → lohko ”Lisenssi”, liitä ja napsauta ”Tallenna”. Moduulit avautuvat heti.

Paneeli tarkistaa avaimen kryptografisesti: allekirjoituksen, verkkotunnussidoksen ja voimassaoloajan.

Verkkotunnuksen on aktivoinnissa täsmättävä tarkalleen paneelin osoitteeseen. Ota se vakiosta APP_URL tiedostosta config.php ja syötä vain isäntänimi — ilman https:// ja ilman www-etuliitettä. Aktivointi on kertaluonteinen: koodi muuttuu syötetyn verkkotunnuksen lisenssiksi eikä aktivoidu uudelleen — jos verkkotunnuksessa on virhe, avain ei sovi paneeliisi ja koodi on käytetty. Syötä siis verkkotunnus huolellisesti.
Kun voimassaolo päättyy tai verkkotunnus vaihtuu, paneelin ylätunnisteeseen ilmestyy varoitus. Lisenssi on sidottu verkkotunnukseen pysyvästi eikä siirry toiseen verkkotunnukseen: uutta voimassaoloaikaa tai uutta verkkotunnusta varten tarvitaan uusi avain (ostetaan tililtä ja aktivoidaan kertaluonteisesti).

08. config.php-tiedosto — kaikki paneelin asetukset

Kaikki paneelin perusasetukset on määritetty yhdessä config.php-tiedostossa juuressa (public/-kansion vieressä) tavallisilla define()-vakioilla. Tiedosto luodaan asennuksen yhteydessä; sitä tarvitsee harvoin muokata käsin — lähinnä verkkotunnusta vaihdettaessa, siirrettäessä tai toiseen tietokantaan kytkettäessä. Jokaisen muokkauksen jälkeen käynnistä PHP-FPM uudelleen (muuten muutokset eivät tule voimaan OPcachen takia).

Korvaa korostetut kohdat omilla arvoillasi; jätä muut ennalleen:

// --- Tietokanta --- define('DB_HOST', 'localhost'); // jätä ennalleen define('DB_NAME', 'db_name'); // mitä asetit tietokantaa luotaessa define('DB_USER', 'user'); // mitä asetit tietokantaa luotaessa define('DB_PASS', 'db_password'); // mitä asetit tietokantaa luotaessa define('DB_CHARSET', 'utf8mb4'); // jätä ennalleen // --- Sovellus --- define('APP_URL', 'https://monitor.example.com'); // paneelin osoite, ilman kauttaviivaa lopussa define('TIMEZONE', 'Europe/Helsinki'); // aikavyöhykkeesi // --- Istunnon kesto --- define('SESSION_LIFETIME', 28800); // joutenolo ennen uudelleenkirjautumista, s (28800 = 8 h)

Tietokanta. MySQL/MariaDB-yhteyden tiedot:

  • DB_HOST — tietokantapalvelimen isäntä, lähes aina localhost;
  • DB_NAME — paneelin tietokannan nimi;
  • DB_USER — tietokannan käyttäjä (pääsy vain omaan tietokantaan);
  • DB_PASS — tämän käyttäjän salasana;
  • DB_CHARSET — yhteyden merkistö, jätä utf8mb4.

Sovellus.

  • APP_URL — paneelin täysi osoite (esim. https://monitor.example.com). Sen on vastattava verkkotunnusta, jolle lisenssi on aktivoitu — muuten avain hylätään (ks. kohta ”Lisenssi”);
  • TIMEZONEPHP:n aikavyöhyke: vaikuttaa vain siihen, miten paneeli näyttää päivämäärät ja kellonajat. Cron-tehtävien ajoitukseen se ei vaikuta — siinä käytetään järjestelmän vyöhykettä (ks. ”Kaikki cron-tehtävät”).

Istunnon kesto. SESSION_LIFETIME — istunnon joutenoloaika sekunteina (liukuva: päivittyy toiminnan yhteydessä). Oletusarvo 28800 = 8 tuntia; tämän joutenoloajan jälkeen paneeli pyytää kirjautumaan uudelleen. Esimerkiksi 3600 = 1 tunti, 86400 = vuorokausi.

Virheiden kirjaus. Virheitä ei koskaan näytetä kävijöille, vaan ne kirjoitetaan tiedostoon logs/php_errors.log — ne näkyvät sivulla ”Sovelluksen lokit”. Näitä rivejä (display_errors=0, log_errors=1, error_log-polku) ei yleensä tarvitse muuttaa — asetukset on määritetty suoraan tiedostossa eivätkä ne riipu php.ini-tiedostosta.

config.php on salainen tiedosto. Siinä on tietokannan salasana. Se sijaitsee paneelin juuressa (public/-kansion vieressä), ja tämän paneelin verkkojuuri (DocumentRoot) on nimenomaan paneelin juuri, ei public/. Itse tiedosto ei ”vuoda”: juuren .htaccess-tiedostossa on sille nimenomainen esto (Require all denied) — palvelin palauttaa 403. Ilman tätä sääntöäkään lähdekoodi ei vuotaisi: tämä on PHP — palvelin suorittaa sen eikä palauta tekstinä. Varmuuden vuoksi: älä julkaise sitä julkisissa repositorioissa äläkä lähetä sitä tukeen todellinen salasana mukana. Tiedoston oikeudet — 640.
Siirrettäessä tai pääsyä palautettaessa tämä tiedosto on tärkein tietolähde: tietokannan nimi, käyttäjä ja salasana otetaan juuri täältä (ks. kohdat ”Paneelin päivitys ja siirto” ja ”Pääsyn palautus”).

Turvatyökalut

09. UFW-palomuuri

UFW (Uncomplicated Firewall) on yksinkertainen käyttöliittymä nftables/iptables-työkaluihin. Se sulkee kaikki saapuvat portit paitsi nimenomaisesti sallitut. Sivu ”UFW-palomuuri” näyttää tilan ja säännöt.

sudo apt install ufw # Salli SSH (pakollista ENNEN käyttöönottoa!) ja web sudo ufw allow OpenSSH sudo ufw allow 80,443/tcp # Sulje tietokanta ulkoa (pääsy vain paikallisesti) sudo ufw deny 3306 # Ota käyttöön ja tarkista sudo ufw enable sudo ufw status verbose
Salli SSH (ufw allow OpenSSH) ehdottomasti ennen ufw enable -komentoa, muuten menetät pääsyn palvelimelle.
Dashboardin ”ulkoinen altistuminen” huomioi UFW:n: deny-säännöllä suljettua porttia ei lasketa ulkoa saavutettavaksi.
Skipping adding existing rule ei ole virhe. UFW ilmoittaa näin, että täsmälleen sama sääntö on jo olemassa eikä sitä lisätä uudelleen. Kun automaattiasetus ajetaan uudelleen (se on idempotentti), tämä on normaali viesti — mihinkään ei tarvitse reagoida.

10. Fail2banin asennus

Estää IP-osoitteen automaattisesti, kun epäonnistuneiden kirjautumisyritysten määrä ylittyy. Analysoi SSH:n, nginxin, Apachen ja muiden palveluiden lokit.

sudo apt install fail2ban sudo systemctl enable --now fail2ban # Tarkista tila: sudo fail2ban-client status
Toimiva konfiguraatio (jail.local kymmenillä jaileilla ja automaattisella eston ipsumista) — seuraavassa osiossa.

11. Toimiva Fail2ban + ipsum -kokoonpano

Perusasennus on yllä. Tässä on toimiva kokoonpano, joka tuottaa kymmeniä aktiivisia jaileja ja tuhansia estoja: yleisasetukset, keskeiset jailit ja haitallisten IP-osoitteiden automaattinen esto ipsum-listasta.

Tiedosto /etc/fail2ban/jail.local — yleisasetukset ja tärkeimmät jailit:

[DEFAULT] bantime = 1w findtime = 900 maxretry = 3 backend = systemd banaction = nftables-multiport ignoreip = 127.0.0.1/8 ::1 <YOUR_IP> <TRUSTED_NETS> # Progressiivinen esto: jokainen toisto on pidempi bantime.increment = true bantime.factor = 2 bantime.maxtime = 5w bantime.rndtime = 300 [sshd] enabled = true maxretry = 5 bantime = -1 # pysyvä esto SSH:n brute force -hyökkäyksestä findtime = 3600 # Rikoksenuusijat: usean eston saaneet estetään pysyvästi [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 # Verkkopalvelut (apache-*, nginx-*, php-url-fopen, phpmyadmin-syslog): [nginx-http-auth] enabled = true port = http,https [apache-badbots] enabled = true port = http,https # … ja muut palvelukohtaiset jailit (dovecot, exim, postfix-sasl, # mysqld-auth, vsftpd, portscan, pam-generic) — enabled = true
Lisää ignoreip-kohtaan ehdottomasti oma IP-osoitteesi ja luotetut verkot, muuten voit estää itsesi. Muokkausten jälkeen: sudo fail2ban-client reload.

ipsum-estolistan automaattilataus root-cronissa (sudo crontab -e): level 1 (yli 100 000 IP-osoitetta) ladataan ipsum-joukkoon, joka torjutaan palomuurissa (lisätietoja osiossa ”IPset-estolista”):

# 04:00 — ipset ipsum -päivitys (level 1, maksimikattavuus): 0 4 * * * /usr/local/bin/load-ipsum.sh >> /path/to/monitor/logs/cron.log 2>&1
Joukon nimen on oltava ipsum — juuri sitä dashboard lukee (kortti ”IPset ipsum”). Tasot: levels/1.txt — maksimikattavuus, levels/3.txt — tarkempi (3+ lähdettä).

Miksi ”Tietoturvamonitori” on jaettu kahteen vyöhykkeeseen. Suojaus toimii kahdella tasolla, eikä dashboard sekoita niitä keskenään:

  • Todelliset hyökkäykset (reaktiivinen) — kaikki, mitä fail2ban nappasi: elävät murtoyritykset (jailit sshd, apache-*, nginx-* jne.) ja pahantahtoiset rikoksenuusijat (jail recidive — ne, jotka on jo estetty useita kertoja). Nämä ovat IP-osoitteita, jotka oikeasti yrittivät murtautua sisään — ne näkyvät hyökkäyskartalla ja ”Aikajanalla”.
  • Ennakoiva esto (proaktiivinen) — tunnettujen haitallisten IP-osoitteiden julkinen estolista ipset ipsum, joka torjutaan palomuurissa DROP-säännöllä. Nämä osoitteet eivät useimmiten koskeneet palvelimeesi lainkaan — ne katkaistaan ennalta; laskuri ”IPset ipsum” näyttää, kuinka monta on torjuttu ennakoivasti.

Ero on yksinkertainen: reaktiivinen — ”nämä hyökkäsivät ja saivat eston”, ennakoiva — ”nämä estettiin jo ennen yritystä”. Aiemmin recidiveen ajettiin keinotekoisesti ipsumin list-3 (tästä vanha jako ”listamaiset recidive”); nyt recidive sisältää vain todelliset rikoksenuusijat, ja ennakoiva esto on kokonaan palomuurissa.

12. IPset-estolista (ipsum)

ipsum on julkinen luettelo haitallisista IP-osoitteista, joka päivittyy päivittäin. Monitor näyttää ladattujen osoitteiden määrän hallintapaneelissa ja hyökkäyskartalla sekä huomioi sen turvallisuusarviossa (−10, jos joukkoa ei ole ladattu).

Minimaalinen vaihtoehto ilman fail2bania — erillinen ipsum-joukko ja estot iptablesin kautta:

# Luo joukko (kerran): sudo ipset create ipsum hash:ip # Päivitysskripti /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, päivittäin klo 4:00): 0 4 * * * /usr/local/bin/update-ipsum.sh
Laajennettu vaihtoehto fail2ban-recidiven kanssa on osiossa ”Fail2ban + ipsum -toimiva kokoonpano”.
ipset sijaitsee muistissa ja katoaa uudelleenkäynnistyksessä. Pelkkä päivittäinen cron jättää joukon tyhjäksi uudelleenkäynnistyksestä seuraavaan ajoon asti (hallintapaneeli näyttää 0). Lataa joukko myös käynnistyksessä — siirrä lataus skriptiin ja liitä se @reboot-ajastukseen. Samalla komento create … -exist asettaa rajan maxelem 300000 (oletus 65536 — level 1 ei mahdu, tulee ”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 — päivittäin klo 04:00 JA jokaisella käynnistyksellä: 0 4 * * * /usr/local/bin/load-ipsum.sh @reboot sleep 60 && /usr/local/bin/load-ipsum.sh
Miten se toimii automaattiasennuksessa. Skripti lataa täyden level 1 -luettelon (yli 100 tuhatta IP-osoitetta) ipsum-joukkoon ja, jos palomuuria hallitsee asennusohjelma (tuore VPS — profiilit ”Täysi”/”Kevyt”), liittää joukon UFW:hen DROP-säännöllä — näiden IP-osoitteiden liikenne estetään todella. Sääntö on jälkeen ESTABLISHED,RELATED, joten nykyiset yhteydet (ml. oma SSH:si) eivät katkea — vain uudet yhteydet luettelosta estetään. Joukko palautetaan palvelun ipsum-load.service latauksen yhteydessä ennen palomuuria (muuten UFW ei nousisi), ja se päivitetään cronilla klo 04:00. Jo valmiiksi määritellyllä palvelimella (paneeli, oma palomuuri) asennusohjelma ei koske palomuuriin — siellä ipsum jää luetteloksi hallintapaneelia ja hyökkäyskarttaa varten, ja DROP-sääntö lisätään halutessa käsin (minimaalinen vaihtoehto iptables … --match-set ipsum … -j DROP — yllä). Automaattiasennuksessa ei tarvitse tehdä mitään käsin.

13. CrowdSecin asennus

Nykyaikainen korvaaja Fail2banille kollektiivisella threat intelligence -tiedolla: yhteisön estot sekä omat säännöt. Vaatii erillisen bouncerin estojen soveltamiseksi palomuuriin.

curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash sudo apt install crowdsec sudo systemctl enable --now crowdsec # Bouncer iptables/nftables-tuelle: sudo apt install crowdsec-firewall-bouncer-iptables # Tarkista tila: sudo systemctl status crowdsec sudo cscli decisions list sudo cscli bouncers list
Tila ”Ei käynnissä” panelissa = palvelu on asennettu, mutta prosessi ei ole aktiivinen (monitori tarkistaa sen komennolla systemctl is-active crowdsec). Käynnistys: sudo systemctl enable --now crowdsec; kaatumisen sattuessa katso sudo journalctl -u crowdsec -n 30. Sama sääntö koskee mitä tahansa palvelua tilassa ”Ei käynnissä” (Suricata, Falco, Monit, MySQL).
”0 skenaariota” tai ”0 bounceria” dashboardissa. CrowdSec tulee oletuksena lähes tyhjänä — ilman kokoelmia se ei havaitse mitään, ja ilman rekisteröityä bounceria estoja ei sovelleta palomuuriin. Asenna peruskokoelmat ja varmista, että bouncer on listalla:
# Peruskokoelmat (Linux + SSH + verkkopalvelin): sudo cscli collections install crowdsecurity/linux crowdsecurity/sshd crowdsecurity/base-http-scenarios sudo systemctl reload crowdsec # Bouncerin pitää olla listalla ja aktiivisen yhteyden tilassa: sudo cscli bouncers list
Bouncerin lokissa stream halted / estoja ei sovelleta. Kyseessä on orpo api-avain: bouncer poistettiin listalta cscli bouncers list, mutta sen vanha avain jäi tiedostoon /etc/crowdsec/bouncers/*.yaml. Rekisteröi bouncer uudelleen ja kirjaa tuore avain:
sudo cscli bouncers add fw-bouncer # tulostaa uuden api_key # kirjaa tämä avain kenttään api_key: tiedostossa /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml sudo systemctl restart crowdsec-firewall-bouncer
Automaattiasennus (profiili ”Täysi suojaus”) asentaa kokoelmat ja rekisteröi firewall-bouncerin itse — manuaalisesti tämä tarvitaan vain manuaalisessa asennuksessa tai CrowdSeciin tehdyn käsin tehdyn muutoksen jälkeen.

14. AIDE:n asennus

AIDE (Advanced Intrusion Detection Environment) ottaa tilannekuvan tiedostojärjestelmästä ja ilmoittaa jokaisessa tarkistuksessa muutoksista hakemistoissa /etc, /bin, /usr. Asennuksen jälkeen tietokanta on pakko alustaa (aideinit).

sudo apt install aide # Tietokannan alustus (5–15 minuuttia): sudo aideinit sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db # Ubuntu 24.04: hakemisto /var/lib/aide luodaan tilassa 700 (omistaja _aide), # eikä paneeli (www-data) näe tietokantaa → näyttää ”Ei alustettu”. # Avaa hakemisto läpikäyntiä varten (tietokantatiedostot pysyvät 600): sudo chmod 755 /var/lib/aide # Ensimmäinen tarkistus KIRJOITUKSELLA lokiin, jota monitor lukee. # Ubuntu/Debian: aide vaatii nimenomaisen --config (muuten ”missing configuration”; # aide.wrapper-binääriä ei toimiteta uusissa versioissa): sudo bash -c 'aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1'
Komennon aideinit aikana pääte seisoo 5–15 minuuttia rivillä Running aide --init... — se on normaalia (koko tiedostojärjestelmän tiivistys, kuormittaa levyä). Älä keskeytä Ctrl+C:llä. Jos prosessi näyttää ”jumittuneen”, mutta ei kirjoita mitään — se saattaa odottaa vastausta piilotettuun kysymykseen Overwrite existing aide.db.new [Yn]? (paina Y). Tarkista aktiivisuus toisesta istunnosta: pgrep -af aide.
Virhe aideinit: ”21_aide_spamassassin … printf: invalid number” (return code 20) — tunnettu AIDE:n konfiguraatiokatkelman vika Ubuntu 22.04:ssä. Tietokantaa ei luoda. Siirrä rikkinäinen katkelma pois ja yritä uudelleen:
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
Tilat koontinäytöllä. ”Ei alustettu” = paneeli ei näe tietokantatiedostoa: joko aideinit ei ole ajettu, tai (Ubuntu 24.04) hakemisto /var/lib/aide on luotu tilassa 700 eikä ole käyttäjän www-data saatavilla — korjautuu komennolla sudo chmod 755 /var/lib/aide (katso lohko yllä). ”Ei tarkistuksia” = tietokanta on olemassa, mutta tarkistusta ei ole vielä suoritettu — tämä ei ole virhe. Monitor lukee tulokset tiedostosta /var/log/aide/aide.log.
Säännöllinen tarkistus → loki paneelille. Vakio-/etc/cron.daily/aide ei uusissa Ubuntu/Debian-versioissa välttämättä kirjoita tiedostoa /var/log/aide/aide.log oikeassa muodossa (eikä aide.wrapper ole niissä enää). Luotettavampaa on lisätä oma cron nimenomaisella --config-valinnalla — se kirjoittaa lokin rootina tilassa 644, ja monitor lukee sen ilman lisäryhmiä:
# sudo crontab -e — päivittäinen tarkistus klo 02:00: 0 2 * * * /usr/bin/aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1 # Aja nyt heti odottamatta aikataulua: sudo bash -c 'aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1'
Automaattinen asennus tekee tämän kaiken jo puolestasi: chmod 755 /var/lib/aide ja tarkistuscron klo 02:00 — mitään ei tarvitse tehdä käsin.
Tee ensimmäinen alustus puhtaalla palvelimella — ennen verkkosovellusten asennusta. Luo tietokanta uudelleen laillisten muutosten jälkeen: sudo aideinit && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db.

15. ClamAV:n asennus

Virustorjuntaskanneri Linuxille. Erityisen hyödyllinen /var/www-hakemiston tarkistamiseen PHP-shellien ja haitallisen koodin varalta.

sudo apt install clamav clamav-daemon sudo systemctl enable --now clamav-daemon # Päivitä tunnistetietokanta: sudo freshclam # Skannaa kansio manuaalisesti: sudo clamscan -r /var/www --infected
Näyttääkö clamd-demoni tilaa ”Ei aktiivinen” komennon enable --now jälkeen? Kolme tyypillistä syytä:

1. Asetustiedostoon on jäänyt rivi Example — clamd kieltäytyy käynnistymästä niin kauan kuin se on siellä:

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

2. Tunnistetietokantaa ei ole ladattu — clamd ei käynnisty ilman sitä:

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

3. Se vain latautuu — clamd lataa ~8 milj. tunnistetta muistiin 30–60 sekunnissa. Odota ja tarkista: systemctl is-active clamav-daemon (tila activating → lataus vielä käynnissä).

Diagnostiikka: sudo journalctl -u clamav-daemon -n 30 --no-pager.
Näkyykö dashboardilla ”Tiedostoja tarkistettu: 0” / ”Viimeisin skannaus: —”? Demoni clamd pitää tunnisteet vain muistissa, se ei itse skannaa mitään aikataulun mukaan. Paneeli näyttää ajastetun skannauksen tulokset, joten tarvitaan cron, joka skannaa ja kirjoittaa lokia. Automaattiasennus asentaa kääreen /usr/local/bin/clamav-scan.sh ja cronin klo 01:30 — ensimmäisen ajon jälkeen kentät ”Tiedostoja tarkistettu” ja ”Viimeisin skannaus” täyttyvät. Käynnistä heti aikataulua odottamatta: sudo /usr/local/bin/clamav-scan.sh.

16. Linux Malware Detect (maldet) -asennus

Linux Malware Detect (LMD) — haittaohjelmien skanneri verkkouhkiin: PHP-shellit, verkkotakaovet, latausohjelmat. Käyttää ClamAV-moottoria ja täydentää sitä omilla tunnisteillaan.

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 # Päivitä tunnisteet: sudo maldet -u # Skannaa /var/www: sudo maldet -a /var/www
LMD ja ClamAV toimivat hyvin yhdessä. Viimeisin raportti: maldet --report.
Asennuksen aikana voi näkyä rivi update-rc.d: error: unable to read /etc/init.d/maldet — se on vaaraton. maldet ei käytä init.d:tä, tunnisteiden päivitys ja skannaukset käynnistyvät kautta /etc/cron.daily/maldet. Jos alempana näkyy installation completed — kaikki asentui.
Sivulla LMD näyttää tilaa ”Ei asennettu”, vaikka se on asennettu? maldet ei asennu kautta apt, vaan hakemistoon /usr/local/maldetect, ja kun open_basedir on käytössä, sen olemassaolo tarkistetaan shellin kautta — katso kohta ”Sivu on tyhjä, vaikka palvelimella on tietoja”.

17. Suricatan asennus

Verkkotason tunkeutumisen havaitsemisjärjestelmä: analysoi liikennettä pakettitasolla ja tuntee tuhansia hyökkäysten allekirjoituksia. Täydentää ModSecurityä (joka toimii HTTP-tasolla, Suricata TCP/IP-tasolla).

sudo add-apt-repository ppa:oisf/suricata-stable sudo apt update && sudo apt install suricata # Lataa ajantasaiset säännöt: sudo suricata-update sudo systemctl enable --now suricata
Suricata on "Aktiivinen", mutta paneeli ei näytä hälytyksiä / tapahtumien määrä on 0? Suricata kirjoittaa tiedostoon /var/log/suricata/eve.json rootina, ja hakemistolla on oikeudet 750, joten verkkopalvelin (www-data) ei voi lukea sitä. Avaa hakemisto läpikulkua varten — sisällä olevat tiedostot pysyvät suojattuina:
sudo chmod o+rx /var/log/suricata
Automaattiasennus tekee tämän itse — käsin ei tarvitse.

18. Falcon asennus

Sieppaa järjestelmäkutsut eBPF/kernel-moduulin kautta ja havaitsee poikkeamat reaaliajassa: shell nginxistä, /etc/passwd-tiedoston lukeminen web-prosessilla, kirjoitus /bin-hakemistoon jne.

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
Monitori lukee Falcon tapahtumat komennolla journalctl -u falco (ilman sudoa — systemd-journal-ryhmän kautta). Varmista, että www-data kuuluu tähän ryhmään — ks. ”sudo-asetukset” (kohta 2) manuaalisen asennuksen sivulla.
”0 tapahtumaa 24 tunnissa” on normaalia, ei virhe. Falco on event-driven: se pysyy hiljaa niin kauan kuin kaikki on kunnossa, ja kirjaa tapahtuman vain poikkeaman yhteydessä (shell web-prosessista, /etc/passwd-tiedoston lukeminen, kirjoitus järjestelmähakemistoihin). Nolla kriittistä vuorokaudessa rauhallisella palvelimella on terve tila.
Paneelille tiedosto-tuloste on luotettavampi. Lukeminen komennolla journalctl vaatii oikeudet lokiin; jotta paneeli näkee tapahtumat vakaasti, automaattiasennus ottaa Falcossa käyttöön file_output/var/log/falco/falco.log ja asettaa palvelulle UMask=0022 (web-palvelin lukee lokin). Uudessa asennuksessa tätä ei tarvitse määrittää käsin.

19. ModSecurityn (WAF) asennus

ModSecurity — verkkopalomuuri (WAF) Apachelle tai Nginxille. Estää sovellustason hyökkäykset: SQL-injektiot, XSS, polunohituksen, skannerit.

# Apache: sudo apt install libapache2-mod-security2 sudo a2enmod security2 # OWASP Core Rule Set -sääntökokoelma: sudo apt install modsecurity-crs # PAKOLLINEN: ilman tätä tiedostoa sääntömoottori on pois päältä 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 # Tarkistus: pitää palauttaa 403 curl -s -o /dev/null -w '%{http_code}\n' "https://monitor.example.com/?id=1%20UNION%20SELECT%201,2--"
Pelkkä paketin asennus ei suojaa mitään. Apache lataa konfiguraatiot rivillä IncludeOptional /etc/modsecurity/*.conf, mutta paketti asentaa vain tiedoston modsecurity.conf-recommended — se ei osu maskiin *.conf. Jos sitä ei kopioida tiedostoon modsecurity.conf, SecRuleEngine pysyy tilassa Off: moduuli on ladattu, CRS-säännöt on ladattu, mutta liikennettä ei tarkisteta eikä auditointilokia luoda. Välitila DetectionOnly vain kirjaa tapahtumat lokiin estämättä pyyntöjä — dashboard näyttää sen keltaisena.

Dashboardin pääsy auditointilokiin. Loki /var/log/apache2/modsec_audit.log kuuluu rootille (oikeudet 640), verkkokäyttäjä ei voi lukea sitä. Dashboard hakee tiedot kääreen kautta — luo se:

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 # tiedostossa /etc/sudoers.d/monitor (käyttäjä = se, jonka alla PHP-FPM toimii): # www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-modsec
Kääre ottaa viimeisen sisennyksettömän SecRuleEngine-direktiivin: sisennetyt rivit ovat lohkojen <LocationMatch>/<Directory> sisällä (esimerkiksi WAF:n poiskytkentä phpMyAdminia varten) eivätkä määritä globaalia tilaa.
Sudoersin käyttäjän on vastattava FPM-poolin käyttäjää: tavallisessa Apache/Debianissa se on www-data, HestiaCP:ssä sivuston pool toimii sivuston omistajan alla (esimerkiksi admin) — tarkista grep -E '^user' /etc/php/*/fpm/pool.d/monitor.example.com.conf.
Jos sivusto on Nginx-välityspalvelimen takana (HestiaCP), Apache näkee asiakkaana itse välityspalvelimen — dashboard ottaa hyökkääjän todellisen IP-osoitteen otsakkeesta X-Forwarded-For. Tilastoihin päätyvät vain transaktiot, joissa sääntö laukesi: direktiivi SecAuditLogRelevantStatus kirjaa auditointilokiin kaikki 4xx/5xx-vastaukset, joten sinne päätyvät myös tavalliset 403/500 — dashboard ei laske niitä WAF-tapahtumiksi.
Lohkoa ---RULES--- tarvitaan osiossa ”Kaikki aktiiviset säännöt” — dashboard näyttää paitsi lauenneet, myös kaikki ladatut CRS-säännöt + mukautetut. Kolme polkua silmukassa for f in … ovat tyypillisiä paikkoja CRS-säännöille ja paikallisille lisäyksille; jos sinulla on toinen sijoittelu (paketti asentaa tiedostot omaan hakemistoonsa tai mukautetut säännöt eivät ole tiedostossa /etc/modsecurity/custom-rules.conf), etsi todelliset polut komennolla sudo grep -rl 'IncludeOptional\|^Include ' /etc/apache2/mods-enabled/security2.conf /etc/apache2/conf-enabled/*.conf 2>/dev/null ja lisää ne luetteloon. Jos kääre on vanha (ilman tätä osiota) — osio näyttää vain varoituksen ”ei saatavilla”, sivun muu osa toimii kuten ennenkin.

20. Auditd:n asennus

Auditd (Linux Audit Daemon) tallentaa järjestelmäkutsut ytimen tasolla: sisään- ja uloskirjautumiset, sudo-komennot, epäonnistuneet todennusyritykset ja tiedostomuutokset. Monitor näyttää tämän päivän kirjautumiset, epäonnistuneet yritykset ja sudo-komennot.

sudo apt install auditd audispd-plugins sudo systemctl enable --now auditd # Tarkista tila ja tapahtumat: sudo systemctl status auditd sudo ausearch -m USER_LOGIN -ts today
Monitor lukee tapahtumat ausearch-komennolla (/usr/sbin/ausearch) ja tarvittaessa tiedostosta /var/log/audit/audit.log tail-komennolla. Molempien on oltava sudoers-tiedostossa.

21. Monitin asennus

Valvoo palveluita (nginx, php-fpm, mysql jne.) ja käynnistää ne uudelleen kaatuessaan. Voi lähettää hälytyksiä sähköpostiin.

sudo apt install monit sudo systemctl enable --now monit # Konfiguraatiotiedostot: sudo nano /etc/monit/monitrc ls /etc/monit/conf.d/
Monitori hakee palveluluettelon komennolla monit status. Tiedostossa /etc/monit/monitrc on oltava käytössä HTTP-liittymä (lohko set httpd, jossa allow localhost), muuten monit status palauttaa virheen.
Dashboardissa lukee ”0 palvelua valvonnassa”? Kaksi syytä. (1) HTTP-liittymä on pois päältä — tiedostossa monitrc rivi set httpd on kommentoitu (oletuksena se on muodossa # set httpd port 2812 …). Poista lohkon kommentointi ja salli localhost. (2) Pelkkä käytössä oleva httpd ei valvo mitään — Monit laskee vain sen, mikä on määritetty check-lohkoilla; ilman niitä luettelo on tyhjä, vaikka liittymä toimisi. Minimaalinen toimiva konfiguraatio:
# /etc/monit/conf.d/00-httpd — HTTP-liittymä localhostille: set httpd port 2812 use address localhost allow localhost # esimerkkejä check-lohkoista (mitä valvotaan): 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 # tarkista syntaksi (Control file syntax OK) sudo systemctl reload monit sudo monit status
Automaattiasennus lisää valmiin conf.d-tiedoston, jossa httpd on portissa 2812 ja tarkistukset määritetty — uudessa asennuksessa ei tarvitse säätää käsin.
Palvelu tilassa ”Virheitä”? Monitori vain näyttää tilan eikä tarkoituksella käynnistä palveluita uudelleen verkkopaneelista (se olisi root-komentojen etäsuoritus turvapaneelissa). Diagnostiikka ja uudelleenkäynnistys — SSH:n kautta Monitilla:
sudo monit status <service> # virheen syy sudo monit restart <service> # uudelleenkäynnistys Monitin kautta # jos Monit ei saa palvelua käyntiin — katso sen omaa yksikköä: sudo systemctl status <unit> --no-pager sudo journalctl -u <unit> -n 50 --no-pager

22. PSAD:n asennus (porttiskannauksen havaitseminen)

PSAD analysoi iptablesin lokia ja havaitsee porttiskannaukset ja verkkohyökkäykset antaen jokaiselle lähteelle uhkatason (1–5). Täydentää fail2bania ja Suricataa.

sudo apt install psad # PSAD lukee iptablesin lokia — lokitus on kytkettävä päälle (UFW tekee sen itse). # Puhtaassa iptablesissa lisää LOG-säännöt INPUT/FORWARD-ketjuihin. sudo psad --sig-update sudo systemctl enable --now psad
Monitor lukee tiedot komennolla psad --Status (tarvitaan sudoers-tiedostossa). Ilman iptablesin lokitusta sivu on tyhjä — se on normaalia, kunnes skannauksia on tapahtunut.

23. AppArmor / SELinux (pääsynvalvonta)

Mandatory Access Control rajoittaa, mihin tiedostoihin ja resursseihin ohjelma pääsee, vaikka se olisi murrettu. Ubuntussa/Debianissa käytetään oletuksena AppArmoria (yleensä jo asennettu ja käytössä).

# AppArmor (Ubuntu/Debian): sudo apt install apparmor apparmor-utils sudo systemctl enable --now apparmor sudo aa-status # tarkista profiilit
Monitor lukee tilan komennolla aa-status (tarvitaan sudoers-tiedostossa). Näyttää enforce/complain-tilassa olevien profiilien määrän ja ilman profiilia olevat prosessit.

”Profiileja ladattu” on enemmän kuin enforce + complain — se on normaalia. AppArmor 4.x:ssä (Ubuntu 24.04 ja uudemmat) tuli tila unconfined: profiili on ladattu ytimeen, mutta se ei rajoita mitään. Ubuntu merkitsee näin kymmeniä profiileja ohjelmille, jotka käyttävät user namespaces -ominaisuutta (selaimet, torrent-asiakkaat ja vastaavat). Kun tällaisia profiileja on, kortti ”Profiileja ladattu” muuttuu keltaiseksi ja näyttää niiden määrän — esimerkiksi unconfined: 90, kun ladattuja on 120 ja enforce-tilassa 26. Todellisen suojan antavat vain enforce-tilan profiilit; Ubuntu 22.04:ssä (AppArmor 3.x) tätä tilaa ei ole ja luvut täsmäävät aina.

sudo aa-status | grep -E "profiles are" # erittely tiloittain sudo aa-enforce /etc/apparmor.d/profile-name # siirrä profiili enforce-tilaan
Ubuntun tarkoituksella unconfined-tilaan jättämiä profiileja kannattaa siirtää enforce-tilaan vain harkiten: ne eivät ole poissa käytöstä vahingossa, vaan siksi että muuten ohjelmien oma toiminta rikkoutuu. complain-tilan profiilit ovat toinen asia: niiden säännöt on jo kirjoitettu, mutta niitä ei vain sovelleta.

24. debsums-asennus (pakettien eheys)

debsums tarkistaa, että asennettujen pakettien tiedostot vastaavat repositoryn tarkistussummia — paljastaa vaihdetut järjestelmäbinaarit (täydentää AIDE:a). Täysi tarkistus kestää 1–2 minuuttia, joten se ajetaan cronilla, ja paneeli lukee tuloksen tiedostosta data/debsums/debsums.log ja luokittelee sen itse (tärkeitä ovat vain binaarit ja kirjastot).

Tehtävä lisätään root-croniin (sudo crontab -e). Valmis kääre debsums-scan.sh sijoitetaan hakemistoon /usr/local/bin/ (chmod +x; ks. cron-tehtävien yhteenveto) ja kirjoittaa raportin itse paneelin hakemistoon data/debsums/.

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

Kääre debsums-scan.sh löytää paneelin data/-hakemiston itse — polkua ei tarvitse määrittää.

Muutokset hakemistoissa /etc/ (konfiguraatiot) ja /usr/share/ (resurssit) ovat palvelimella yleensä normaaleja — paneeli merkitsee ne omalla värillään. Hälyttäviä ovat binaarien ja kirjastojen muutokset (/bin, /sbin, /usr/lib jne.) — kortti ”Binaarit / kirjastot” näyttää juuri ne.

25. Lynis-raporttien määritys

Lynis käynnistetään manuaalisesti tai cronilla. Raportti tulee tallentaa projektin kansioon data/lynis/ — monitori lukee tiedoston lynis-report.dat.

# Kertaluontoinen käynnistys (korvaa omalla polulla paneelin juureen): sudo lynis audit system --report-file /path/to/monitor/data/lynis/lynis-report.dat # Päivittäinen auditointi — cron-rivi (valmis lynis-scan.sh-kääre kansiossa /usr/local/bin/, ks. yhteenveto): 0 3 * * * /usr/local/bin/lynis-scan.sh >> /path/to/monitor/logs/cron.log 2>&1
Ensimmäisen käynnistyksen jälkeen sivu ”Lynis-auditointi” näyttää heti hardening-indeksin, varoitukset ja suositukset.
”Käynnistä auditointi” -painike Lynis-sivulla. Se käynnistää lynis-scan.sh-skriptin taustalla suoraan paneelista (odottamatta cronia): näyttää ”Skannataan…” ja päivittää raportin itse valmistuttuaan. Tätä varten web-käyttäjä tarvitsee sudoers-rivin skriptin ajamiseen — asennusohjelma lisää sen automaattisesti tiedostoon /etc/sudoers.d/monitor. Jos paneeli on asennettu manuaalisesti tai aiemmin, lisää rivi samalla käyttäjällä, joka on jo mainittu tiedostossa:
u=$(sudo awk '/NOPASSWD/ && !/lynis-scan/ {print $1; exit}' /etc/sudoers.d/monitor) [ -n "$u" ] && echo "$u ALL=(ALL) NOPASSWD: /usr/local/bin/lynis-scan.sh" | sudo tee -a /etc/sudoers.d/monitor sudo visudo -c && sudo chmod 440 /etc/sudoers.d/monitor

26. Logwatch-raporttien asetukset

Logwatchin tulee tallentaa päivittäiset raportit projektin kansioon data/logwatch/ muodossa .txt. Monitor näyttää viimeisimmän raportin ja arkiston.

# Päivittäin (6:00) — cron-rivi (valmis kääre logwatch_daily.sh sijainnissa /usr/local/bin/, ks. yhteenveto): 0 6 * * * /usr/local/bin/logwatch_daily.sh >> /path/to/monitor/logs/cron.log 2>&1

Paneelin moduulit

27. Verkkomonitori (sisäänrakennettu)

Verkkomonitori ei vaadi asennusta — se on sisäänrakennettu paneelin sivu. Se näyttää palvelimen verkkotilan paikallisista lähteistä:

  • liitännät ja liikenne — lähteestä /proc/net/dev;
  • linkkien tila (UP/DOWN) ja IP — komennolla ip;
  • yhteydet ja kuuntelevat portit — komennolla ss;
  • ytimen verkkotapahtumat 24 tunnilta — komennolla journalctl -k.

Kolme ensimmäistä lähdettä toimivat ilman sudoa, joten liitännät, liikenne, yhteydet ja portit näkyvät heti. Lohko ”Ytimen tapahtumat” käyttää komentoa journalctl -k — se luetaan ryhmän systemd-journal kautta (”sudon määritys”, kohta 2), sudoa ei tarvita. Tarkista, että kaikki on verkkokäyttäjän saatavilla:

# Tarkistus www-data-käyttäjänä (sen alla PHP toimii): 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
Lohko ”Ytimen verkkotapahtumat” näyttää ytimen verkkopinon tapahtumat (linkin tilan vaihto up/down, kantoaaltovirheet, ”network unreachable”). Palomuurin UFW BLOCK -merkinnät eivät päädy tänne — ne ovat sivuilla ”UFW-palomuuri” ja ”Hyökkäyskartta”. Tyhjä lohko vihreällä merkillä = vuorokauden aikana ei ollut verkkohäiriöitä.

28. Levy ja SMART

Sisäänrakennettu sivu näyttää kolme asiaa:

  • Tiedostojärjestelmät — osioiden täyttöaste (df); mittari muuttuu punaiseksi, kun ≥90 %;
  • Asemat — levyjen luettelo (lsblk), vain todelliset (loop/snap piilotettu);
  • Kunto (SMART) — levyn tila ja attribuutit (smartctl).

Tila ja laiteluettelo toimivat heti ilman määrityksiä. SMART vaatii paketin smartmontools. Web-prosessilla ei ole suoraa pääsyä levylaitteisiin, joten SMART luetaan cronilla tiedostoon data/disk/smart.txt, ja paneeli lukee sen.

Ajastus tehdään root-croniin (sudo crontab -e). Valmis kääre smart-scan.sh sijoitetaan hakemistoon /usr/local/bin/ (chmod +x; ks. cron-tehtävien yhteenveto) ja kirjoittaa itse paneelin hakemistoon data/disk/.

sudo apt install smartmontools # Cron-rivi (30 minuutin välein): */30 * * * * /usr/local/bin/smart-scan.sh >> /path/to/monitor/logs/cron.log 2>&1

Kääre smart-scan.sh löytää itse paneelin data/-hakemiston — polkua ei tarvitse määrittää. Sisäisesti lsblk -e7,11 jättää pois loop/cdrom.

Virtuaalilevyillä (QEMU/KVM ja vastaavilla) on yleensä saatavilla vain yleinen tila ”kunto: OK”, kun taas lämpötila, käyttötunnit ja uudelleensijoitetut sektorit voivat olla tyhjiä — se on normaalia. Fyysisellä palvelimella näytetään kaikki attribuutit.

29. Suorituskyky (CPU/RAM/verkko/levy)

Sivu näyttää palvelimen kuormitushistorian viimeisten 24 tunnin ajalta — Load Average, CPU:n käyttöasteen ja I/O-odotuksen, RAM/Swap, verkkoliikenteen (vastaanotto/lähetys), levyn I/O (luku/kirjoitus), levyn ja inodejen täyttöasteen, avoimet tiedostokahvat ja MySQL-yhteydet sekä nykyisen TCP-yhteyksien ja prosessien määrän.

Tiedot kerää cron/collect_metrics.php — se kirjoittaa 5 minuutin välein yhden ”raa'an” laskurien tilannekuvan (/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') tietokantatauluun system_metrics; prosentit ja nopeudet sivu laskee itse peräkkäisten tilannekuvien erotuksesta (levyn/inodejen/kahvojen täyttöaste ja MySQL-yhteydet ovat hetkellisiä arvoja, ilman uudelleenlaskentaa). Sudoa ei tarvita — lähteet luetaan ilman root-oikeuksia. Yli 24 tuntia vanhat pisteet poistetaan automaattisesti jokaisen kirjoituksen yhteydessä.

# Cron-rivi (viiden minuutin välein): */5 * * * * /usr/local/bin/collect-metrics-all.sh >> /path/to/monitor/logs/cron.log 2>&1

Kääre collect-metrics-all.sh (ks. cron-tehtävien yhteenveto) löytää itse kaikki palvelimelle asennetut paneelin instanssit ja käynnistää kunkin cron/collect_metrics.php:n sivuston omistajan nimissä.

Kunnes kerääjä on ajanut vähintään kahdesti (ensimmäiset ~10 minuuttia asennuksen jälkeen), sivu näyttää tekstin ”tietoja kerätään” — kaaviot tarvitsevat vähintään yhden peräkkäisen pisteparin voidakseen laskea nopeudet ja prosentit.

Kuormitushälytykset (kohta ”Asetukset” → ”Kuormitushälytykset”) — kun CPU:n/RAM:n/levyn/inodejen kynnysarvo ylittyy, paneeli lähettää ilmoituksen Telegramiin/sähköpostiin (samat kanavat kuin päivittäisessä raportissa — niitä ei tarvitse erikseen ottaa käyttöön hälytyksiä varten) ja vielä yhden, kun metriikka palaa normaaliksi. Kynnyksen ollessa ylitettynä ilmoituksia ei toisteta: seuraava ilmoitus tulee vasta syklin ”palautui → ylittyi uudelleen” jälkeen.

Kynnysarvot tarkistaa sama collect_metrics.php jokaisella ajolla (viiden minuutin välein) — erillistä cronia ei tarvita. Tila ”jo ilmoitettu / ei vielä” säilytetään tiedostossa data/alerts_state.json, kynnysarvot paneelin asetuksissa.

30. Hyökkäyskartta (GeoIP)

”Hyökkäyskartta”-sivu tunnistaa maan IP-osoitteesta komennolla geoiplookup. Ilman GeoIP-pakettia maita ei tunnisteta eivätkä pisteet ilmesty kartalle:

sudo apt install geoip-bin geoip-database # Tarkistus: geoiplookup 8.8.8.8
Sudoa ei tarvita — tietokannan /usr/share/GeoIP/GeoIP.dat voivat lukea kaikki, ja tulokset tallennetaan välimuistiin tiedostoon tmp/geoip_cache.json. Itse kartta (Leaflet + OpenStreetMap-ruudut) ladataan selaimessa — internet tarvitaan tietokoneella, jossa dashboard on avattuna.

31. Ulkoinen näkyvyys, päivitykset ja automaattipäivitykset

Kaksi sisäänrakennettua dashboard-korttia, jotka eivät näytä työkalun ”päällä/pois” -tilaa vaan palvelimen todellista suojaustasoa. Eivät vaadi asennusta, luetaan paikallisesti ilman sudoa.

Ulkoinen näkyvyys — kuinka moni palvelu kuuntelee kaikkia rajapintoja (0.0.0.0/[::]) ja on saavutettavissa ulkoa. Korostaa punaisella, jos ulos näkyvät tietokannat tai välimuisti (MySQL, PostgreSQL, Redis, MongoDB, Memcached, Elasticsearch) — se on suora aukko (−10 turvallisuusarvioon). Lähde: ss -tuln.

Jos kortti on punainen — sulje tietokanta ulkomaailmalta: sido osoitteeseen 127.0.0.1 (bind-address MySQL:n/PostgreSQL:n konfiguraatiossa, bind 127.0.0.1 Redisissä) tai sulje portti UFW:ssä.
”Avoin portti” ≠ ”saavutettavissa ulkoa”. Palvelu, joka kuuntelee osoitetta 127.0.0.1 (loopback), näkyy vain itse palvelimelle — sinne ei pääse ulkoa, vaikka portti olisi ”avoin”. Siksi loopbackiin sidottu Postfix portissa 25 on turvallinen: automaattiasetus asettaa inet_interfaces = loopback-only (sekä neutraalin smtpd_banner — sulkee Lynisin huomautuksen MAIL-8818 versiotietojen paljastumisesta). ”Ulkoinen näkyvyys” -kortti laskee ulospäin vain sen, mikä kuuntelee osoitetta 0.0.0.0/[::]; loopback-palvelut eivät sinne kuulu.
Lynis MAIL-8818 käsin (jos asensit postin itse): tiedostossa /etc/postfix/main.cf aseta smtpd_banner = $myhostname ESMTP (ilman versiota ja käyttöjärjestelmää) sekä inet_interfaces = loopback-only, sitten sudo systemctl restart postfix.

Tietoturvapäivitykset — kuinka monta tietoturvakorjausta odottaa asennusta ja tarvitaanko ytimen päivityksen jälkeen uudelleenkäynnistys (−5 turvallisuusarvioon, jos korjauksia on). Lähde: /usr/lib/update-notifier/apt-check, tiedosto /var/run/reboot-required. Yksityiskohtainen luettelo — sivulla ”Tietoturvapäivitykset”.

# Asenna päivitykset: sudo apt update && sudo apt upgrade # Tarkista, mikä kuuntelee ulospäin: ss -tuln | grep -E '0\.0\.0\.0|\[::\]'
Päivityskortti toimii Ubuntussa/Debianissa (update-notifier-common). Jos apt-check puuttuu — monitori laskee korjaukset komennolla apt-get -s upgrade.

Automaattiset tietoturvapäivitykset (unattended-upgrades) — sivulla ”Tietoturvapäivitykset” erillinen kortti näyttää, onko tietoturvakorjausten automaattinen asennus käytössä ja milloin se viimeksi ajettiin. Sudoa ei tarvita — tila luetaan komennolla apt-config dump.

sudo apt install unattended-upgrades sudo dpkg-reconfigure -plow unattended-upgrades # ota käyttöön # Tarkista, mikä on käytössä: apt-config dump | grep Unattended-Upgrade

Ylläpito

32. Varmuuskopiointi

Varmuuskopio on tärkein turva: tietojen menetys on pahempaa kuin mikään murto. Tarvitaan kaksi asiaa — palvelimen/sivustojen varmuuskopio ja erikseen hallintapaneelin tietokannan varmuuskopio (siellä ovat käyttäjät, WebAuthn-avaimet, asetukset ja lisenssi).

Vaihtoehto A — HestiaCP: käyttäjän Backup-välilehti → varmuuskopion luontipainike (tai ajastettuna palvelimen asetuksissa). Varmuuskopio sisältää sivustot ja niiden tietokannat.

Vaihtoehto B — käsin (cron): tietokannan dump + paneelin data/-hakemiston arkisto:

# root-cron (sudo crontab -e) — päivittäinen varmuuskopio klo 2:30 (korvaa omilla nimillä/poluilla): 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 # Poista yli 14 päivää vanhat arkistot: 0 3 * * * find /var/backups -name 'monitor-*' -mtime +14 -delete
Varmuuskopio samalla palvelimella suojaa virheiltä, mutta ei palvelimen menetykseltä. Kopioi arkistot ulkoiseen tallennukseen (toinen palvelin, S3, rclone pilveen). Varmista, että palautus todella toimii.

33. Paneelin päivitys ja siirto

Päivitys uuteen versioon. Tee ensin varmuuskopio. Lataa sitten koodiedostot uudelleen ja säilytä omat tietosi:

  • korvaa (koodi): public/, includes/, assets/, cron/, database/ sekä juuritason .htaccess (etuohjain — reititystä ei saa jättää vanhasta versiosta), manifest.json, sw.js;
  • älä koske: config.php (tietokannan tiedot), data/ (raportit), logs/, tmp/ (istunnot ja välimuisti).
# Latauksen jälkeen — tyhjennä PHP:n välimuisti (jos opcache on käytössä): sudo systemctl reload php*-fpm
FileZilla ilmoittaa SSH_FX_PERMISSION_DENIEDPermission denied. Paneelin tiedostot kuuluvat www-data-käyttäjälle (näin ne asetettiin asennuksessa), kun taas SFTP-asiakas yhdistää omalla käyttäjätunnuksellasi, jolla ei ole kirjoitusoikeutta. Koko paneelin antaminen www-data-käyttäjälle ”jotta toimisi” on juuri se, mikä aiheuttaa tämän virheen; alla kolme tapaa, joista mikä tahansa ratkaisee ongelman.
# Vaihtoehto A (suositeltava) — erota omistajat: koodi sinun, työhakemistot verkkopalvelimen. # Verkkopalvelin ei saa lainkaan kirjoitusoikeutta paneelin KOODIIN: 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 # Vaihtoehto B — ACL nykyisten omistajien päälle (mitään ei siirretä): 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 # Vaihtoehto C — www-data-ryhmän kautta. Yksinkertaisempi, mutta kirjoitusoikeuden # paneelin tiedostoihin saa myös verkkopalvelin (PHP-haavoittuvuudella koodi korvattavissa): 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
Miksi vaihtoehto A on turvallinen. Paneeli kirjoittaa vain kolmeen hakemistoon — data/ (raportit), tmp/ (istunnot ja välimuisti), logs/; ne jäävät www-data-käyttäjälle. Loput on koodia, ja verkkopalvelin tarvitsee siihen vain lukuoikeuden, jonka antaa www-data-ryhmä oikeuksilla 644. Sivuhyöty: PHP-haavoittuvuuden yhteydessä paneelin tiedostoja ei voi enää korvata. Hosting-paneeleissa (HestiaCP ja vastaavat) vaihtoehtoa A ei tarvita: siellä sivuston tiedostot kuuluvat jo tilille, jolla kirjaudut SFTP:llä, ja verkkopalvelin lukee ne ryhmän kautta.
Vaihtoehdon B sudenkuoppa: mikä tahansa myöhempi chmod tiedostoihin nollaa ACL-maskin, ja pääsy katoaa huomaamatta. Jos ”oikeuksien siivoamisen” jälkeen lataus törmää taas Permission denied -virheeseen — toista molemmat setfacl-komennot.
Bitti 2 vaihtoehdossa C on setgid: SFTP:llä ladatut tiedostot pysyvät www-data-ryhmässä, muuten paneeli ei pysty korvaamaan niitä. Vaihtoehdon C jälkeen yhdistä FileZillassa uudelleen — uusi ryhmä tulee voimaan vasta uudella kirjautumisella. Tarkistus: id deploy (ryhmän www-data pitää näkyä) ja ls -ld /path/to/monitor (drwxrwsr-x — kirjain s tarkoittaa, että setgid on asetettu).

Siirto toiselle palvelimelle:

  1. Pystytä uudelle palvelimelle sivusto + HTTPS (ks. manuaalisen asennuksen sivu).
  2. Kopioi kaikki paneelin tiedostot yhdessä config.php- ja data/-hakemistojen kanssa.
  3. Siirrä tietokanta: mysqldump vanhalla → tuonti uudella; korjaa tietokannan tiedot config.php-tiedostoon.
  4. Toista uudella palvelimella: sudoers, adm-ryhmän jäsenyys, cron-tehtävät.
  5. Lisenssi on sidottu verkkotunnukseen — jos verkkotunnus on sama, avain toimii edelleen.

34. Pääsyn palautus (kadonnut avain, salasana, IP-esto)

Jos et pääse kirjautumaan sisään — kaikki korjataan suoraan tietokannassa palvelimelta. Avaa tietokanta (nimi — tiedostosta config.php):

sudo mysql MY_DB

WebAuthn-avain kadonnut (toinen tekijä ei mene läpi) — poista 2FA käytöstä, kirjaudu salasanalla ja rekisteröi uusi avain:

UPDATE users SET webauthn_enabled = 0;

Unohdit salasanan — aseta uusi tiiviste (luo se palvelimella ja lisää se tähän):

# Luo uuden salasanan tiiviste: php -r "echo password_hash('NEW_PASSWORD', PASSWORD_BCRYPT), \"\n\";" # Tietokantaan (lisää saatu tiiviste): # UPDATE users SET password = '$2y$10$...' WHERE username = 'admin';

Estit itsesi IP-suodattimella — poista rajoitus käytöstä:

UPDATE settings SET value = '0' WHERE name = 'ip_restriction_enabled';
Tietokantaan on aina pääsy: sudo mysql palvelimella tai phpMyAdmin / hosting-paneelin tietokantaosio. Palautuksen jälkeen ota WebAuthn ja IP-suodatin uudelleen käyttöön.

35. Kaikki cron-tehtävät yhdessä paikassa

Tehtävien yhteenveto — palvelimen root-cronissa (lisätään komennolla sudo crontab -e). Jätä vain niiden työkalujen rivit, joita käytät; korjaa polut oman palvelimesi mukaisiksi.

# Monitorin palvelinkron (root) — lisää komennolla: sudo crontab -e # 01:30 — ClamAV-skannaus vaarallisilla poluilla (web, home, temp) → kortit ”Tarkistettuja tiedostoja” ja ”Viimeisin skannaus” 30 1 * * * /usr/local/bin/clamav-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 02:00 — AIDE-tiedostoeheystarkistus (vaatii nimenomaisen --config) 0 2 * * * /usr/bin/aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1 # käynnistyksessä — palauta /var/lib/aide-oikeudet (paketin tmpfiles-tiedosto # aide-common.conf nollaa ne arvoon 0700, jolloin paneeli ei enää näe tietokantaa) @reboot chmod 755 /var/lib/aide # 03:00 — Lynis-tietoturva-auditointi 0 3 * * * /usr/local/bin/lynis-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 04:00 — ipsum-estolistan päivitys (level 1) 0 4 * * * /usr/local/bin/load-ipsum.sh >> /path/to/monitor/logs/cron.log 2>&1 # ipsum-joukon nostaa käynnistyksessä ipsum-load.service (ENNEN palomuuria, muuten # UFW ei näe joukkoa before.rules-tiedostossa) — ei cron. Tässä vain päivittäinen virkistys yllä. # 06:00 — Logwatch-raportti 0 6 * * * /usr/local/bin/logwatch_daily.sh >> /path/to/monitor/logs/cron.log 2>&1 # 30 min välein — SMART-levytarkistus */30 * * * * /usr/local/bin/smart-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 04:30 — debsums-pakettieheys 30 4 * * * /usr/local/bin/debsums-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 08:00 — aikataulutettu raportti sähköpostiin ja Telegramiin 0 8 * * * /usr/local/bin/daily-report-all.sh >> /path/to/monitor/logs/cron.log 2>&1 # tunneittain — pakettiluetteloiden päivitys (”Tietoturvapäivitykset”-korttia varten) 0 * * * * /usr/bin/apt-get update -qq >/dev/null 2>&1 # 5 min välein — resurssien tilannekuva (CPU/RAM/verkko/levy) ”Suorituskyky”-sivulle */5 * * * * /usr/local/bin/collect-metrics-all.sh >> /path/to/monitor/logs/cron.log 2>&1
Tarkemmat tiedot kustakin — vastaavissa osioissa. Varmuuskopiotehtävät (edellinen osio) lisätään tähän samaan croniin. Tarkista muokkausten jälkeen: sudo crontab -l ja että cron-palvelu on aktiivinen.
Cronin aika = palvelimen aikavyöhyke, ei config.php-tiedoston TIMEZONE. Vakio TIMEZONE vaikuttaa vain PHP:hen (miten paneeli näyttää päivämäärät), mutta cron-demoni käynnistää tehtävät käyttöjärjestelmän kellonajan mukaan. Jos palvelimen vyöhyke ei täsmää omaasi, ”08:00”-raportti tulee väärään aikaan. Esimerkki: palvelin on eri vyöhykkeellä (Europe/Berlin, UTC+2) ja sinä Helsingissä (UTC+3) → ”08:00”-raportti tulee sinun aikaasi klo 09:00. Tarkista ja tarvittaessa aseta järjestelmän vyöhyke omaksesi:
# Tarkista palvelimen nykyinen vyöhyke: timedatectl # Aseta oma vyöhyke (esimerkki) ja käynnistä cron uudelleen: sudo timedatectl set-timezone Europe/Helsinki sudo systemctl restart cron
Tämän jälkeen rivi 0 8 * * * laukeaa klo 08:00 paikallista aikaa. Muuten cronia itseään pitäisi siirtää, mutta talvi-/kesäaikaan vaihdettaessa siirtymä menisi taas pieleen — siksi on oikeampaa asettaa järjestelmän vyöhyke.
Valmiit wrapper-skriptit. Niiden toimivat kopiot ja crontab-malli (crontab.txt) ovat kansiossa system/ projektin vieressä, ulkopuolella public_html. Tämä ei ole osa sivustoa — niitä ei tarvitse ladata web-juureen; sijoita ne palvelimelle järjestelmäpolkuihin (kuten crontabissa yllä):
  • lynis-scan.sh/usr/local/bin/ (chmod +x) — ajaa lynis audit system, asettaa skannauksen ajaksi lipun /tmp/lynis-running ja kopioi lynis-report.dat paneelin kansioon data/lynis/;
  • logwatch_daily.sh/usr/local/bin/ (chmod +x) — muodostaa päivittäisen Logwatch-raportin (sshd, fail2ban, sudo, postfix) kansioon data/logwatch/;
  • smart-scan.sh/usr/local/bin/ (chmod +x) — tallentaa levyjen tilan (smartctl) kansioon data/disk/;
  • debsums-scan.sh/usr/local/bin/ (chmod +x) — tarkistaa pakettien eheyden (debsums) kansioon data/debsums/;
  • clamav-scan.sh/usr/local/bin/ (chmod +x) — ClamAV-virustorjuntaskannaus vaarallisilla poluilla (web, home, temp); kirjoittaa yhteenvedon tiedostoon /var/log/clamav/scan.log, josta ClamAV-sivu lukee sen (rivi 01:30 crontabissa yllä);
  • load-ipsum.sh/usr/local/bin/ (chmod +x) — päivittää ipset-joukon ipsum (level 1) paikallaan rikkomatta voimassa olevia palomuurisääntöjä (rivi 04:00 crontabissa yllä);
  • daily-report-all.sh/usr/local/bin/ (chmod +x) — ajaa paneelin raportin cron/daily_report.php (rivi 08:00 crontabissa yllä);
  • daily_report.php — sisältyy jo paneeliin (cron/daily_report.php), ajetaan skriptin daily-report-all.sh kautta, sitä ei tarvitse asentaa erikseen;
  • collect-metrics-all.sh/usr/local/bin/ (chmod +x) — ajaa paneelin skriptin cron/collect_metrics.php (”Suorituskyky”-sivu, rivi */5 crontabissa yllä); collect_metrics.php sisältyy jo paneeliin, sitä ei tarvitse asentaa erikseen;
  • crontab.txt (system/cron/) — tehtävämalli; lisää tarvittavat rivit komennolla sudo crontab -e.
Skriptin polun crontabissa on täsmättävä siihen, mihin sen sijoitit.
Näin sijoitat skriptin kansioon /usr/local/bin/. Suoraan FileZillasta sinne ei voi kirjoittaa — kansio kuuluu käyttäjälle root, ja SFTP-asiakas saa vastaukseksi SSH_FX_PERMISSION_DENIED. Järjestys on tämä: lataa tiedosto ensin kansioon /tmp (johon kaikki voivat kirjoittaa), siirrä se sitten paikalleen yhdellä komennolla:
# FileZillassa: kirjoita ”Etäsivusto”-kenttään /tmp ja lataa skripti sinne, # sitten SSH:lla (install asettaa heti omistajan ja oikeudet, chown/chmod ei tarvita): sudo install -o root -g root -m 755 /tmp/lynis-scan.sh /usr/local/bin/lynis-scan.sh rm -f /tmp/lynis-scan.sh # tarkistus: tiedosto paikallaan, oikeudet rwxr-xr-x, syntaksi ehjä bash -n /usr/local/bin/lynis-scan.sh && ls -l /usr/local/bin/lynis-scan.sh
Älä sekoita kansioita: tarvitaan /tmp palvelimen juuressa — ei /var/tmp eikä tmp/ itse paneelin sisällä (viimeksi mainittu kuuluu käyttäjälle www-data ja on suljettu käyttäjältäsi). FileZillan puussa /tmp on ylimmän tason haara, kansion var vieressä, ei sen sisällä.
Asensitko palvelimen automaattiasennuksella? Nämä wrapperit ja niiden cron-tehtävät on jo asennettu skriptillä (kansioon /usr/local/bin/, loki — /var/log/arciveo-cron.log) — käsin ei tarvitse tehdä mitään.
Mistä skriptit etsivät paneelia. Wrapperit ovat verkkotunnusneutraaleja: ne löytävät paneelin asennukset käymällä läpi polut /home/*/web/*/public_html ja /var/www/*, ja tallentavat raportit niiden kansioon data/. Jos paneeli on toisessa polussa — lisää se skriptien riville for app in …, muuten Lynis-/SMART-/debsums-/Logwatch-raportit eivät päädy paneeliin.
cron.log ja käyttöoikeudet. Tiedoston logs/cron.log luo ensimmäisenä root-cron — se kuuluu käyttäjälle root, eikä paneelin ”Cron-loki”-välilehti pysty lukemaan eikä tyhjentämään sitä. Luo tiedosto etukäteen web-käyttäjän nimissä (sivustokansion omistaja; HestiaCP:ssä tämä on tili, esim. admin) — silloin root-cron vain lisää loppuun muuttamatta omistajaa:
# luo etukäteen web-käyttäjänä (ennen cron-rivien lisäystä): sudo -u OWNER touch /path/to/monitor/logs/cron.log # jos cron.log on jo root-cronin luoma — anna se web-käyttäjälle: sudo chown OWNER:OWNER /path/to/monitor/logs/cron.log sudo chmod 644 /path/to/monitor/logs/cron.log
Kansion omistajan selvittäminen: stat -c %U /path/to/monitor.
Hallinta paneelista. Osiossa ”Järjestelmä” on sivu ”Crontab” — tehtäviä voi katsella ja lisätä ilman SSH:ta. Paneeli muokkaa vain sen itsensä kautta lisättyjä tehtäviä (erillinen lohko root-crontabissa, merkitty huoltokommentein); kaikki mikä on jo crontabissa (luettelo yllä) näytetään siellä vain luku -tilaisena luettelona ”Palvelimen muut tehtävät” painikkeineen ”Kopioi editoriin” — se vain siirtää aikataulun/komennon lisäyslomakkeeseen, alkuperäistä riviä koskematta. Jos haluat ”siirtää” olemassa olevan tehtävän paneelin hallintaan — kopioi se editoriin, tallenna, ja poista sitten vanha rivi käsin (sudo crontab -e), muuten se suoritetaan kahdesti.
Kertaluontoinen asetus palvelimella. Sivu tarvitsee etuoikeutetun wrapper-skriptin — ei paljasta sudo crontab -komentoa (se olisi suora eskalointi root-oikeuksiin kenelle tahansa, joka pääsee paneelin istuntoon), vaan suppean skriptin kahdella komennolla (list/set), joka koskee vain omaa lohkoaan huoltokommenttien välissä. Asenna kerran:
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
Web-käyttäjä voi poiketa käyttäjästä www-data — tarkista, minkä käyttäjän alaisuudessa sivuston PHP-FPM-pooli toimii (ps -o user= -C php-fpm), ja korvaa se sudoers-riville.
Uusi tiedosto latautui väärällä omistajalla — sivu vastaa ”Access denied.”. Jos tiedosto public/crontab_monitor.php on ladattu FTP:llä/SFTP:llä eri järjestelmäkäyttäjän alaisuudessa (esimerkiksi root) kuin sivuston muut tiedostot, web-palvelin ei pysty lukemaan sitä. Vertaa omistajaa ja oikeuksia viereisen tiedoston kanssa ja korjaa ne vastaamaan:
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

Diagnostiikka

36. Työkalu on asennettu, mutta näytöllä lukee ”Ei asennettu”

Monitor tunnistaa työkalut dpkg-query-komennolla APT:n pakettitietokannasta. Jos työkalua ei ole asennettu apt-komennolla (käsin, snap-paketista tai lähdekoodista), dpkg ei näe sitä.

# Tarkista dpkg:llä: dpkg -l fail2ban | grep '^ii' dpkg -l auditd | grep '^ii' # Etsi binäärin polku: which ufw fail2ban-client auditctl # Testaa sudo www-data-käyttäjänä: sudo -u www-data sudo fail2ban-client status sudo -u www-data sudo ufw status verbose

37. Ongelmien ratkaisu (500, ei tietoja)

Virhe 500 — tarkista PHP:n, nginx:n ja itse monitorin lokit:

tail -50 /var/log/nginx/error.log tail -50 /var/log/php*-fpm.log # Monitorin lokit: tail -50 logs/monitor_$(date +%Y-%m-%d).log # Kansioiden oikeudet: ls -la data/ tmp/ logs/
Paneeli hallintapaneelissa (HestiaCP, ISPmanager, cPanel)? Siellä PHP ei toimi käyttäjänä www-data, vaan käyttäjän tilillä (esimerkiksi admin — sivuston hakemiston omistaja). Kaikki sudo-säännöt ja ryhmäjäsenyydet (adm, systemd-journal) on määritettävä tälle käyttäjälle, muuten moduulit näyttävät ”Ei aktiivinen / 0”, vaikka palvelut ovat käynnissä. Selvitä PHP:n todellinen käyttäjä: ps -o user= -C php-fpm | sort -u tai sivuston hakemiston omistaja stat -c '%U' /path/to/monitor. Korvaa jatkossa kaikissa alla olevissa komennoissa www-data sillä. Automaattiasennus tunnistaa web-käyttäjän itse ja määrittää sudoersin sille.

Tiedot eivät näy — lähes aina kyse on määrittämättömistä sudo-oikeuksista. Tarkista tietty komento web-käyttäjän nimissä (korvaa www-data omallasi). Lippu -n = ilman salasanaa, kuten PHP:llä — jos komento pyytää salasanaa, sääntöä ei ole sudoersissa:

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
Moduuli näyttää ”Ei aktiivinen” / ”0”, vaikka työkalu toimii (esimerkiksi sudo aa-status näyttää päätteessä profiilit, mutta ”AppArmor”-sivu näyttää ”Ei aktiivinen”). Syy: web-käyttäjällä ei ole sudo-oikeutta tämän moduulin komentoon. Tarkista se yllä olevasta listasta: jos komento pyytää salasanaa — lisää puuttuva rivi tiedostoon /etc/sudoers.d/monitor (”Sudon määritys”). Yleiset ”uudet” komennot: /usr/sbin/aa-status (MAC), /usr/sbin/psad --Status (PSAD).
Jos jokin sivu (Falco, ModSecurity, Auditd, avoimet UFW-portit) on tyhjä — vertaa listaan sudo-osiossa: todennäköisesti ei ole sallittu apache2ctl, ausearch, aa-status tai ss, tai web-käyttäjä ei ole ryhmissä adm/systemd-journal (sieltä luetaan fail2ban/auth/modsec-lokit ja journalctl — Falco ja ytimen tapahtumat).

38. Sivu on tyhjä, vaikka palvelimella on tietoja

Oire: palvelimella on tietoja (näkyvät shellissä), mutta sivu näyttää tekstin ”ei tietoja” tai virheellisen tilan — esimerkiksi AIDE ilmoittaa ”Ei alustettu”, vaikka tietokanta on luotu.

Syynä on open_basedir: monet paneelit ja webhotellit rajoittavat PHP-FPM-poolin domainin hakemistoon, joten PHP-funktiot file_exists(), file_get_contents() ja filemtime() estetään järjestelmäpoluissa (/var/lib/aide, /var/log, /proc…). Monitor kiertää tämän lukemalla tällaiset polut vakiona olevilla järjestelmäkomennoilla (cat, test, stat).

# Näkyykö tiedosto shellin kautta (näin monitor lukee sen): sudo -u www-data bash -lc 'test -e /var/lib/aide/aide.db && echo VISIBLE || echo NO' # open_basedir-arvo domainin poolille tällä hetkellä: grep -ri open_basedir /etc/php/*/fpm/pool.d/ 2>/dev/null
Jos shell ”näkee” tiedoston (VISIBLE), mutta sivu ei — kyseessä on open_basedir. Oikea ratkaisu on lukeminen järjestelmäkomennoilla (jo tehty AIDE:lle ja Verkkomonitorille). Ei ole tarpeen laajentaa open_basedir-asetusta poluille /var, /proc, ja se on myös vähemmän turvallista.

39. SSL-sivu ei toimi

Monitor tarkistaa varmenteet ottamalla yhteyden verkkotunnuksiin suoraan portin 443 kautta. Jos verkkotunnus ei ole tavoitettavissa itse palvelimelta tai portti on suljettu palomuurilla, tarkistus epäonnistuu.

# Tarkista varmenne manuaalisesti: echo | openssl s_client -connect monitor.example.com:443 2>/dev/null \ | openssl x509 -noout -dates # Tarkista tavoitettavuus: curl -I https://monitor.example.com
Monitor hakee verkkotunnukset automaattisesti Nginxin (/etc/nginx/sites-enabled/, /etc/nginx/conf.d/) ja Apachen (/etc/apache2/sites-enabled/) konfiguraatioista sekä nykyisen isännän kohteesta HTTP_HOST.
Aliverkkotunnusten automaattinen tunnistus. Aliverkkotunnukset tunnistetaan automaattisesti julkisista Certificate Transparency -lokeista ja tarkistetaan verkon kautta — vaikka ne olisivat muilla palvelimilla. Manuaalisesti ei tarvitse lisätä mitään.

40. Näkyvissä vain yksi tietokanta useasta

Monitor muodostaa yhteyden MySQL:ään config.php-tiedoston käyttäjällä, jolla on pääsy vain omaan tietokantaansa. MySQL näyttää information_schema-taulussa vain ne tietokannat, joihin on oikeudet — siksi muut eivät näy.

Jotta monitor näkisi kaikki tietokannat, myönnä tälle käyttäjälle vain lukuoikeus (kerran rootina; korvaa käyttäjänimi config.php-tiedostosta):

sudo mysql -u root GRANT SELECT, PROCESS, SHOW DATABASES ON *.* TO 'DB_USER'@'localhost'; FLUSH PRIVILEGES; EXIT;
SELECT ON *.* antaa vain lukuoikeuden — mitään ei voi muuttaa, poistaa tai luoda, joten se on turvallinen valvontaa varten.
Ilman tätä GRANT-komentoa dashboard näkee vain oman tietokantansa — tämä ei ole virhe vaan oikeuksien rajoitus. Dashboard ei käytä mitään sudo mysql -komentoa: tietokantaluettelo haetaan sen omalla PDO-yhteydellä.

41. PostgreSQL ei näy Tietokanta-sivulla

PostgreSQL vaatii postgres-käyttäjän tason oikeudet, joita panelin verkkokäyttäjällä ei ole. Laajan sudo psql-oikeuden avaaminen PHP:stä on turvatonta — sen sijaan paneli kutsuu kapeaa parametritonta kääreskriptiä, joka tulostaa vain version, yhteyksien määrän ja tietokantojen listan kokoineen. Luo se:

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 # tiedostossa /etc/sudoers.d/monitor (käyttäjä = se, jolla PHP-FPM toimii): # www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-pgstat
Jos et käytä PostgreSQL:ää — poista monitor-pgstat-rivi sudoers-tiedostosta (manuaalisen asennuksen vaihe 13) äläkä luo itse skriptiä: PostgreSQL-kortti jää vain passiiviseksi.

42. Hälytys laukesi — mitä tehdä

Panel näyttää, mitä tapahtuu; alla on kerrottu, mitä tehdä tavallisimmissa tilanteissa. Yleisperiaate: älä panikoi, vertaa laillisen toiminnan kanssa (omat toimesi, päivitykset, varmuuskopiot) ja reagoi vakavuuden mukaan.

  • Hyökkäyskartta / paljon fail2ban-estoja — tämä on normaalia mille tahansa internetissä olevalle palvelimelle (botit kokeilevat jatkuvasti SSH/verkkotunnuksia). Tärkeintä on, että estot toimivat. Varmista, että SSH-kirjautuminen tapahtuu vain avaimella (salasana pois käytöstä) ja että IP-osoitteesi on ignoreip-listalla.
  • ModSecurity esti pyyntöjä — WAF torjuu sivustoon kohdistuvia hyökkäyksiä, se on sen tehtävä. Jos laillinen liikenteesi estyy (väärä positiivinen), etsi rule id tiedoista ja lisää poikkeus CRS-asetuksiin.
  • AIDE: tiedostoja muutettu — vertaa listaa siihen, mitä olet tehnyt (pakettien päivitys, asetusten muokkaus on normaalia). Sellaisten järjestelmäbinäärien muutokset, joita et ole koskettanut, ovat syy varautua. Laillisten muutosten jälkeen päivitä AIDE-tietokanta.
  • debsums: binäärit/kirjastot muutettu (/etc-hakemiston ja /usr/share-hakemiston ulkopuolella) — mahdollinen väärennös. Tarkista paketti: debsums PACKAGE_NAME, ja jos epäilet, asenna se uudelleen (apt install --reinstall).
  • ClamAV / maldet: uhka löydetty — tarkista karanteenissa oleva tiedosto, älä avaa sitä. Jos kyseessä on web-shell sivuston hakemistossa, eristä palvelin ja etsi tunkeutumiskohta (haavoittuva liitännäinen, käyttöoikeuksien vuoto).
  • Falco: kriittiset tapahtumat (shellin käynnistys kontissa, arkaluontoisten tiedostojen käyttö) — selvitä tapahtuma: kenen prosessi, mitä käynnisti. Usein kyse on laillisesta ylläpitotoiminnasta.
  • Ulkoinen altistuminen: tietokanta/välimuisti punaisella — sulje välittömästi: sido palvelu osoitteeseen 127.0.0.1 tai sulje portti UFW:ssä. Tämä on todellinen aukko.
  • SSL vanhenee / on vanhentunut — uusi varmenne (Let's Encrypt uusiutuu itse; jos ei, tarkista certbot renew tai asetukset panelissa).
  • Tietoturvapäivitykset odottavat — asenna: sudo apt update && sudo apt upgrade; ytimen päivityksen jälkeen käynnistä palvelin uudelleen.
Todellisen tunkeutumisen merkit (tuntemattomat prosessit/käyttäjät, muutetut binäärit, lähtevä roskaposti, tuntemattomat cron-tehtävät): katkaise palvelimen ulkoinen yhteys, ota varmuuskopio analyysiä varten ja jos tiedot ovat kriittisiä, pystytä puhdas palvelin luotettavasta varmuuskopiosta — juurikittiä on vaikea siivota luotettavasti.
Arcivéo - Security Monitor © 2026