FAQ

To jest przewodnik po instalacji, konfiguracji i obsłudze Arcivéo Monitor. Sekcje pogrupowano: ogólny przegląd, wdrożenie panelu, podłączenie narzędzi bezpieczeństwa, wbudowane moduły i diagnostyka. Polecenia można kopiować przyciskiem po prawej.

Od czego zacząć

01. Instalacja panelu — wybierz metodę

Instalacja panelu opisana jest na osobnych stronach krok po kroku. Wybierz metodę:

Jeśli nie masz pewności — wybierz automatyczną. Ten poradnik pozostaje jednym źródłem wiedzy o SSL, narzędziach, cron i diagnostyce — strony instalacji odsyłają do jego sekcji, niczego nie powielając.

Przegląd

02. Czym jest Arcivéo Monitor

Arcivéo Monitor — panel bezpieczeństwa serwera. Zbiera dane z zainstalowanych narzędzi (Fail2ban, UFW, Lynis, ModSecurity, AIDE, ClamAV, Auditd, CrowdSec, Suricata, Falco i in.) i wyświetla je w jednym interfejsie z pulpitem, mapą ataków oraz szczegółowymi stronami dla każdego narzędzia.

Monitor nie jest aktywnym środkiem ochrony — sam nie blokuje ataków. Jego zadaniem jest agregowanie informacji z już działających narzędzi i przedstawianie ich w wygodnej formie.

03. Jak monitor działa na serwerze

Monitor działa tylko lokalnie — musi być zainstalowany na tym samym serwerze, który monitoruje. Nie ma żadnego SSH ani zdalnego API.

Wszystkie polecenia (fail2ban-client, ufw status, ipset list itd.) panel wykonuje w imieniu użytkownika serwera WWW (zwykle www-data, na panelach hostingowych — konto witryny) z wąskim zestawem uprawnień sudo — tylko do konkretnych narzędzi, bez ogólnego dostępu root. Wyniki są parsowane i wyświetlane w przeglądarce.

W przypadku wielu serwerów instaluj monitor na każdym z osobna, z unikalną domeną.

04. Jak obliczana jest Ocena bezpieczeństwa

Ocena zaczyna się od maksimum i spada za każdy wykryty problem:

  • UFW nieaktywna — −30
  • Fail2ban nie uruchomiony (brak aktywnych jail) — −25
  • Brak kluczy WebAuthn — −15
  • Lynis hardening index < 60 — −20; 60–79 — −10
  • IPset ipsum nie załadowany — −10
  • Zagrożenia wykryte przez ClamAV — −20
  • Zmiany plików AIDE — −15
  • SSL wygasł — −30, wygasa za <14 dni — −15, <30 dni — −5
  • CrowdSec zainstalowany, ale nie uruchomiony — −5
  • Suricata zainstalowana, ale nie uruchomiona — −5
  • Bazy danych/pamięć podręczna (MySQL, PostgreSQL, Redis…) dostępne z zewnątrz — −10
  • Włączone logowanie root przez SSH (PermitRootLogin yes) — −20
  • Oczekujące aktualizacje zabezpieczeń — −5

Wynik: 80+ = Zabezpieczony, 60–79 = Uwaga, <60 = Zagrożony.

Odliczenia za ClamAV, AIDE, CrowdSec i Suricata stosowane są tylko wtedy, gdy narzędzie jest zainstalowane. Lynis i AIDE bez zainicjalizowanej bazy wyświetlane są jako „brak danych” i nie obniżają wyniku. Liczba ataków z dzisiaj pokazywana jest na pulpicie, ale nie wpływa na Ocenę bezpieczeństwa.

Ustawienia i licencja

05. WebAuthn — uwierzytelnianie dwuskładnikowe

WebAuthn to standard uwierzytelniania bez hasła za pomocą sprzętowego klucza. Obsługuje YubiKey, Touch ID, Face ID, Windows Hello, Passkey.

Po zalogowaniu hasłem system prosi o potwierdzenie zarejestrowanym kluczem. Nawet jeśli hasło wycieknie — bez fizycznego klucza lub biometrii logowanie jest niemożliwe.

Aby to skonfigurować, otwórz Klucze WebAuthn w menu bocznym i kliknij „Zarejestruj klucz”. Proszę od razu zarejestrować dwa klucze: jeśli jedyny klucz zostanie zgubiony lub uszkodzony, logowanie nim do panelu będzie niemożliwe.

WebAuthn działa wyłącznie przez HTTPS. Przy połączeniu HTTP rejestracja i logowanie kluczem są niedostępne.

06. Powiadomienia: Telegram i Email

Panel potrafi wysyłać raport bezpieczeństwa do Telegrama i na e-mail (przyciskiem lub według harmonogramu). Konfiguruje się to w sekcji „Ustawienia”.

Telegram. Potrzebne są token bota oraz chat id:

  1. W Telegramie napisz do @BotFather/newbot → otrzymasz token w postaci 123456:ABC....
  2. Napisz do swojego nowego bota dowolną wiadomość (aby mógł odpowiadać).
  3. Poznaj swój chat id: napisz do bota @userinfobot lub otwórz https://api.telegram.org/bot<TOKEN>/getUpdates i znajdź "chat":{"id":...}.
  4. Wklej token i chat id w „Ustawienia” → Telegram, kliknij „Zapisz i wyślij test”.

Email. Dwa sposoby do wyboru w „Ustawienia” → Email:

  • SMTP — host, port (465/SSL lub 587/TLS), login i hasło Pana skrzynki pocztowej;
  • Resend — nowoczesne API: podaj klucz API (re_...) oraz zweryfikowaną domenę nadawcy.
Przycisk „Wyślij test” od razu sprawdzi kanał. Harmonogram automatycznego raportu — przez cron (sekcja „Wszystkie zadania cron”): wywołuje on wysyłkę, a kanały pobierane są z ustawień.

Status raportu: „UWAGA” lub „OK”. Nagłówek staje się „UWAGA” tylko przy realnym problemie lub oczekującym działaniu: wykryto zagrożenie ClamAV, zmiany plików w AIDE, krytyczne zdarzenia Falco (Emergency/Alert/Critical z ostatnich 24 h), padłą usługę w Monit, wymagany restart, wygasający SSL (≤14 dni) lub oczekujące aktualizacje zabezpieczeń. Szum tła — próby zgadywania SSH przez boty, adresy IP zbanowane przez fail2ban, alerty Suricata, ostrzeżenia Lynis i już odparte żądania ModSecurity — nie podnosi statusu, dlatego takie liczby w raporcie same w sobie nie oznaczają „UWAGA”.

07. Licencja — wprowadzenie i aktywacja

Szczegółowe moduły monitorowania (Lynis, UFW, ModSecurity, mapa ataków, AIDE, ClamAV i inne) odblokowują się po posiadaniu ważnej licencji. Bez niej dashboard, ustawienia i konto działają, a moduły pokazują kartę „Wymagana licencja”.

Po zakupie w panelu klienta ma Pan/Pani kod aktywacyjny w postaci ARCIVEO-XXXX-XXXX-XXXX-XXXX. Trzeba go „aktywować” na domenę swojego panelu — zmieni to kod w podpisany plik licencyjny (blok [license]), który wkleja Pan/Pani do panelu.

Jak aktywować (3 kroki):

  1. Weź kod aktywacyjny. Panel klienta my.arciveo.com → sekcja „Licencje” / „Aktywacja licencji” — skopiuj kod ARCIVEO-….
  2. Aktywuj kod na swoją domenę. W tym samym panelu otwórz „Aktywacja licencji”, wprowadź: kod aktywacyjny, swój email i domenę panelu (adres, pod którym otwiera się monitor, np. monitor.example.com). Naciśnij aktywuj — system wygeneruje plik licencyjny powiązany z tą domeną i pokaże go w polu z przyciskiem „Kopiuj”.
  3. Wklej klucz do panelu. Skopiuj cały tekst licencji → w panelu otwórz „Ustawienia” → blok „Licencja”, wklej i naciśnij „Zapisz”. Moduły odblokują się natychmiast.

Panel weryfikuje klucz kryptograficznie: podpis, powiązanie z domeną i termin ważności.

Domena przy aktywacji musi dokładnie odpowiadać adresowi panelu. Weź ją ze stałej APP_URL w config.php i wprowadź tylko nazwę hosta — bez https:// i bez prefiksu www. Aktywacja jest jednorazowa: kod zmienia się w licencję dla wprowadzonej domeny i nie da się go aktywować ponownie — przy błędzie w domenie klucz nie będzie pasował do Pańskiego panelu, a kod zostanie zużyty. Dlatego proszę wprowadzać domenę uważnie.
Termin upłynął lub zmieniła się domena — w nagłówku panelu pojawi się ostrzeżenie. Licencja jest powiązana z domeną na stałe i nie przenosi się na inną domenę: na nowy termin lub nową domenę potrzebny jest nowy klucz (kupowany w panelu klienta i aktywowany jednorazowo).

08. Plik config.php — wszystkie ustawienia panelu

Wszystkie podstawowe parametry panelu są zdefiniowane w jednym pliku config.php w katalogu głównym (obok folderu public/) za pomocą zwykłych stałych define(). Plik jest tworzony podczas instalacji; ręczna edycja jest rzadko potrzebna — głównie przy zmianie domeny, przenoszeniu lub podłączaniu do innej bazy. Po każdej zmianie uruchom ponownie PHP-FPM (w przeciwnym razie zmiany nie zostaną zastosowane z powodu OPcache).

Wstaw własne wartości w podświetlonych miejscach; resztę pozostaw bez zmian:

// --- Baza danych --- define('DB_HOST', 'localhost'); // pozostaw define('DB_NAME', 'db_name'); // ustawione przy tworzeniu bazy define('DB_USER', 'user'); // ustawione przy tworzeniu bazy define('DB_PASS', 'db_password'); // ustawione przy tworzeniu bazy define('DB_CHARSET', 'utf8mb4'); // pozostaw // --- Aplikacja --- define('APP_URL', 'https://monitor.example.com'); // adres panelu, bez ukośnika na końcu define('TIMEZONE', 'Europe/Warsaw'); // Pana/Pani strefa czasowa // --- Czas sesji --- define('SESSION_LIFETIME', 28800); // bezczynność do ponownego logowania, s (28800 = 8 h)

Baza danych. Dane połączenia z MySQL/MariaDB:

  • DB_HOST — host bazy danych, prawie zawsze localhost;
  • DB_NAME — nazwa bazy danych panelu;
  • DB_USER — użytkownik bazy (dostęp tylko do własnej bazy);
  • DB_PASS — hasło tego użytkownika;
  • DB_CHARSET — kodowanie połączenia, pozostaw utf8mb4.

Aplikacja.

  • APP_URL — pełny adres panelu (np. https://monitor.example.com). Musi być zgodny z domeną, na którą aktywowano licencję — w przeciwnym razie klucz zostanie odrzucony (zob. sekcję „Licencja”);
  • TIMEZONE — strefa czasowa PHP: wpływa tylko na to, jak panel wyświetla daty i godziny. Na czas uruchamiania zadań cron nie wpływa — tam obowiązuje strefa systemu (zob. „Wszystkie zadania cron”).

Czas sesji. SESSION_LIFETIME — limit bezczynności sesji w sekundach (przesuwny: odnawia się przy aktywności). Domyślnie 28800 = 8 godzin; po tym czasie bezczynności panel poprosi o ponowne zalogowanie. Na przykład 3600 = 1 godzina, 86400 = doba.

Rejestrowanie błędów. Błędy nigdy nie są pokazywane odwiedzającym, lecz zapisywane w logs/php_errors.log — widać je na stronie „Logi aplikacji”. Tych wierszy (display_errors=0, log_errors=1, ścieżka error_log) zwykle nie trzeba zmieniać — ustawienia są zdefiniowane bezpośrednio w pliku i nie zależą od php.ini.

config.php — plik poufny. Zawiera hasło do bazy danych. Znajduje się w katalogu głównym panelu (obok public/), a w tym panelu katalog główny serwera (DocumentRoot) to właśnie katalog główny panelu, a nie public/. Sam plik nie „wycieka”: w głównym .htaccess ma dla niego ustawiony jawny zakaz (Require all denied) — serwer zwraca 403. Nawet bez tej reguły kod źródłowy by nie wyciekł: to PHP — serwer go wykonuje, a nie wysyła jako tekst. Na wszelki wypadek: nie publikuj go w publicznych repozytoriach i nie przekazuj do pomocy technicznej z prawdziwym hasłem. Uprawnienia pliku — 640.
Przy przenoszeniu lub przywracaniu dostępu ten plik jest głównym źródłem danych: nazwa bazy, użytkownik i hasło pochodzą właśnie stąd (zob. sekcje „Aktualizacja i przenoszenie panelu” oraz „Przywracanie dostępu”).

Narzędzia bezpieczeństwa

09. Zapora UFW

UFW (Uncomplicated Firewall) to prosty interfejs do nftables/iptables. Blokuje wszystkie porty przychodzące poza jawnie dozwolonymi. Strona „Zapora UFW” pokazuje status i reguły.

sudo apt install ufw # Zezwól na SSH (koniecznie PRZED włączeniem!) oraz na ruch WWW sudo ufw allow OpenSSH sudo ufw allow 80,443/tcp # Zablokuj dostęp do bazy z zewnątrz (dostęp tylko lokalny) sudo ufw deny 3306 # Włącz i sprawdź sudo ufw enable sudo ufw status verbose
Przed ufw enable koniecznie zezwól na SSH (ufw allow OpenSSH), w przeciwnym razie utracisz Pan dostęp do serwera.
„Ekspozycja zewnętrzna” w panelu uwzględnia UFW: port zablokowany regułą deny nie jest uznawany za dostępny z zewnątrz.
Skipping adding existing rule — to nie błąd. W ten sposób UFW informuje, że dokładnie taka reguła już istnieje i nie dodaje jej ponownie. Przy ponownym uruchomieniu autokonfiguracji (jest idempotentna) to standardowy komunikat — nie trzeba reagować.

10. Instalacja Fail2ban

Automatycznie blokuje adres IP po przekroczeniu liczby nieudanych prób logowania. Analizuje logi SSH, nginx, Apache i innych usług.

sudo apt install fail2ban sudo systemctl enable --now fail2ban # Sprawdź status: sudo fail2ban-client status
Działająca konfiguracja (jail.local z dziesiątkami jaili i automatycznym banowaniem z ipsum) — w następnej sekcji.

11. Działająca konfiguracja Fail2ban + ipsum

Instalacja podstawowa — powyżej. Tutaj — działająca konfiguracja dająca dziesiątki aktywnych jaili i tysiące blokad: ustawienia ogólne, kluczowe jaile oraz automatyczny ban złośliwych IP z listy ipsum.

Plik /etc/fail2ban/jail.local — ustawienia ogólne i najważniejsze jaile:

[DEFAULT] bantime = 1w findtime = 900 maxretry = 3 backend = systemd banaction = nftables-multiport ignoreip = 127.0.0.1/8 ::1 <YOUR_IP> <TRUSTED_NETS> # Ban progresywny: każde ponowienie — dłużej bantime.increment = true bantime.factor = 2 bantime.maxtime = 5w bantime.rndtime = 300 [sshd] enabled = true maxretry = 5 bantime = -1 # trwały ban za brute-force SSH findtime = 3600 # Recydywiści: kto złapał kilka banów — banowany na zawsze [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 # Usługi webowe (apache-*, nginx-*, php-url-fopen, phpmyadmin-syslog): [nginx-http-auth] enabled = true port = http,https [apache-badbots] enabled = true port = http,https # … i pozostałe jaile według usług (dovecot, exim, postfix-sasl, # mysqld-auth, vsftpd, portscan, pam-generic) — enabled = true
W ignoreip koniecznie wpisz swój IP i zaufane sieci, w przeciwnym razie można zbanować samego siebie. Po zmianach: sudo fail2ban-client reload.

Automatyczne wczytywanie listy blokad ipsum — w cronie root (sudo crontab -e): level 1 (ponad 100 tysięcy IP) ładuje się do zbioru ipsum, który jest odcinany na zaporze (więcej — w sekcji „Lista blokad IPset”):

# 04:00 — aktualizacja ipset ipsum (level 1, maksymalny zasięg): 0 4 * * * /usr/local/bin/load-ipsum.sh >> /path/to/monitor/logs/cron.log 2>&1
Zbiór musi nazywać się ipsum — właśnie jego odczytuje dashboard (karta „IPset ipsum”). Poziomy: levels/1.txt — maksymalny zasięg, levels/3.txt — dokładniejszy (3+ źródła).

Dlaczego „Monitor bezpieczeństwa” jest podzielony na dwie strefy. Ochrona działa na dwóch poziomach, a dashboard ich nie miesza:

  • Rzeczywiste ataki (reakcja) — wszystko, co złapał fail2ban: żywe próby włamania (jaile sshd, apache-*, nginx-* itp.) oraz groźni recydywiści (jail recidive — ci, którzy byli już banowani kilka razy). To adresy IP, które naprawdę się do Pana dobijały — są na mapie ataków i „Osi czasu”.
  • Blokada prewencyjna (proaktywna) — publiczna lista blokad znanych złośliwych IP ipset ipsum, odcinana na zaporze regułą DROP. Te adresy w większości nawet nie dotknęły Pana serwera — są odcinane z wyprzedzeniem; licznik „IPset ipsum” pokazuje, ile odcięto prewencyjnie.

Różnica jest prosta: reakcja — „ci zaatakowali i dostali bana”, prewencja — „tych zablokowano jeszcze przed próbą”. Wcześniej do recidive sztucznie wciągano list-3 ipsum (stąd dawny podział „recidive z listy”); teraz recidive to tylko prawdziwi recydywiści, a prewencja w całości na zaporze.

12. Lista blokad IPset (ipsum)

ipsum — publiczna lista złośliwych adresów IP, aktualizowana codziennie. Monitor pokazuje liczbę załadowanych adresów na pulpicie i mapie ataków oraz uwzględnia ją w Ocenie bezpieczeństwa (−10, jeśli zestaw nie jest załadowany).

Minimalny wariant bez fail2ban — osobny zestaw ipsum z blokowaniem przez iptables:

# Utwórz zestaw (jednorazowo): sudo ipset create ipsum hash:ip # Skrypt aktualizacji /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, codziennie o 4:00): 0 4 * * * /usr/local/bin/update-ipsum.sh
Rozszerzony wariant z fail2ban-recidive — w sekcji „Robocza konfiguracja Fail2ban + ipsum”.
ipset działa w pamięci i znika po ponownym uruchomieniu. Sam codzienny cron pozostawi zestaw pusty od momentu restartu do następnego uruchomienia (pulpit pokaże 0). Ładuj zestaw także przy starcie — przenieś ładowanie do skryptu i podepnij je pod @reboot. Przy okazji polecenie create … -exist ustawia limit maxelem 300000 (domyślnie 65536 — level 1 się nie mieści, wystąpi „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 — codziennie o 04:00 ORAZ przy każdym starcie: 0 4 * * * /usr/local/bin/load-ipsum.sh @reboot sleep 60 && /usr/local/bin/load-ipsum.sh
Jak to działa przy automatycznej instalacji. Skrypt ładuje pełną listę level 1 (100+ tysięcy IP) do zestawu ipsum i — jeśli zaporą zarządza instalator (świeży VPS — profile „Pełna”/„Odchudzona”) — podłącza zestaw do UFW regułą DROP, dzięki czemu ruch z tych IP jest faktycznie blokowany. Reguła znajduje się po ESTABLISHED,RELATED, więc bieżące połączenia (w tym Pana SSH) nie są zrywane — blokowane są tylko nowe połączenia z listy. Zestaw jest odtwarzany przy uruchomieniu usługi ipsum-load.service przed zaporą (inaczej UFW by się nie podniosło) i aktualizowany cronem o 04:00. Na już skonfigurowanym serwerze (panel, własna zapora) instalator nie ingeruje w zaporę — tam ipsum pozostaje listą dla pulpitu i mapy ataków, a regułę DROP w razie potrzeby dodaje się ręcznie (minimalny wariant z iptables … --match-set ipsum … -j DROP — powyżej). Przy automatycznej instalacji nie trzeba nic robić ręcznie.

13. Instalacja CrowdSec

Nowoczesny zamiennik Fail2ban z kolektywnym threat intelligence: blokady od społeczności oraz własne reguły. Wymaga osobnego bouncera do stosowania blokad w zaporze.

curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash sudo apt install crowdsec sudo systemctl enable --now crowdsec # Bouncer dla iptables/nftables: sudo apt install crowdsec-firewall-bouncer-iptables # Sprawdź status: sudo systemctl status crowdsec sudo cscli decisions list sudo cscli bouncers list
Status „Nie uruchomiono” w panelu = pakiet zainstalowany, ale usługa nie jest aktywna (monitor sprawdza ją przez systemctl is-active crowdsec). Uruchom: sudo systemctl enable --now crowdsec; przy awarii sprawdź sudo journalctl -u crowdsec -n 30. Ta sama zasada dotyczy każdej usługi w statusie „Nie uruchomiono” (Suricata, Falco, Monit, MySQL).
„0 scenariuszy” lub „0 bouncers” na pulpicie. CrowdSec zaraz po instalacji jest niemal pusty — bez kolekcji nic nie wykrywa, a bez zarejestrowanego bouncera blokady nie są stosowane w zaporze. Zainstaluj podstawowe kolekcje i upewnij się, że bouncer jest na liście:
# Podstawowe kolekcje (Linux + SSH + serwer WWW): sudo cscli collections install crowdsecurity/linux crowdsecurity/sshd crowdsecurity/base-http-scenarios sudo systemctl reload crowdsec # Bouncer powinien być na liście i mieć status aktywnego połączenia: sudo cscli bouncers list
W logu bouncera stream halted / blokady nie są stosowane. To osierocony klucz API: bouncer został usunięty z cscli bouncers list, ale jego stary klucz pozostał w /etc/crowdsec/bouncers/*.yaml. Ponownie zarejestruj bouncera i wpisz świeży klucz:
sudo cscli bouncers add fw-bouncer # wyświetli nowy api_key # wpisz ten klucz w api_key: w /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml sudo systemctl restart crowdsec-firewall-bouncer
Automatyczna instalacja (profil „Pełna ochrona”) sama instaluje kolekcje i rejestruje firewall-bouncer — ręcznie jest to potrzebne tylko przy instalacji ręcznej lub po ręcznej ingerencji w CrowdSec.

14. Instalacja AIDE

AIDE (Advanced Intrusion Detection Environment) tworzy migawkę systemu plików i przy każdym sprawdzeniu zgłasza zmiany w /etc, /bin, /usr. Po instalacji konieczna jest inicjalizacja bazy (aideinit).

sudo apt install aide # Inicjalizacja bazy (5–15 minut): sudo aideinit sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db # Ubuntu 24.04: katalog /var/lib/aide jest tworzony w trybie 700 (właściciel _aide), # a panel (www-data) nie widzi bazy → pokazuje „Nie zainicjalizowana”. # Otwórz katalog do przejścia (pliki bazy pozostają 600): sudo chmod 755 /var/lib/aide # Pierwsze sprawdzenie Z ZAPISEM do logu, który czyta monitor. # Na Ubuntu/Debian aide wymaga jawnego --config (inaczej „missing configuration”; # plik binarny aide.wrapper nie jest dostarczany w nowszych wersjach): sudo bash -c 'aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1'
Podczas aideinit terminal przez 5–15 minut stoi na linii Running aide --init... — to normalne (haszowanie całego systemu plików, obciążenie dysku). Nie przerywaj klawiszami Ctrl+C. Jeśli proces „wisi”, ale nic nie wypisuje — możliwe, że czeka na odpowiedź na ukryte zapytanie Overwrite existing aide.db.new [Yn]? (naciśnij Y). Sprawdź aktywność z innej sesji: pgrep -af aide.
Błąd aideinit: „21_aide_spamassassin … printf: invalid number” (return code 20) — znany błąd fragmentu konfiguracji AIDE w Ubuntu 22.04. Baza nie zostaje utworzona. Wynieś uszkodzony fragment i powtórz:
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
Statusy na pulpicie. „Nie zainicjalizowana” = panel nie widzi pliku bazy: albo aideinit nie był uruchomiony, albo (Ubuntu 24.04) katalog /var/lib/aide został utworzony w trybie 700 i jest niedostępny dla www-data — naprawisz to poleceniem sudo chmod 755 /var/lib/aide (patrz blok powyżej). „Brak sprawdzeń” = baza istnieje, ale sprawdzenie nie zostało jeszcze wykonane — to nie błąd. Wyniki monitor czyta z /var/log/aide/aide.log.
Regularne sprawdzenie → log dla panelu. Standardowy /etc/cron.daily/aide na nowych Ubuntu/Debian może nie zapisywać /var/log/aide/aide.log we właściwej postaci (a aide.wrapper już w nich nie ma). Pewniejsze jest dodanie własnego crona z jawnym --config — zapisuje on log od root w trybie 644, a monitor czyta go bez dodatkowych grup:
# sudo crontab -e — codzienne sprawdzenie o 02:00: 0 2 * * * /usr/bin/aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1 # Uruchom teraz, nie czekając na harmonogram: sudo bash -c 'aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1'
Automatyczna instalacja robi już to wszystko: chmod 755 /var/lib/aide i cron sprawdzania o 02:00 — ręcznie nic nie trzeba.
Pierwszą inicjalizację wykonaj na czystym serwerze — przed instalacją aplikacji webowych. Po legalnych zmianach odtwórz bazę: sudo aideinit && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db.

15. Instalacja ClamAV

Skaner antywirusowy dla Linux. Szczególnie przydatny do sprawdzania /var/www pod kątem PHP-shelli i złośliwego kodu.

sudo apt install clamav clamav-daemon sudo systemctl enable --now clamav-daemon # Zaktualizuj bazę sygnatur: sudo freshclam # Przeskanuj katalog ręcznie: sudo clamscan -r /var/www --infected
Demon clamd pokazuje „Nieaktywny” po enable --now? Trzy typowe przyczyny:

1. W konfiguracji pozostał wiersz Example — clamd nie uruchomi się, dopóki tam jest:

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

2. Nie pobrano bazy sygnatur — clamd nie uruchomi się bez niej:

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

3. Po prostu się ładuje — clamd wczytuje ~8 mln sygnatur do pamięci przez 30–60 s. Proszę poczekać i sprawdzić: systemctl is-active clamav-daemon (status activating → nadal ładuje).

Diagnostyka: sudo journalctl -u clamav-daemon -n 30 --no-pager.
Na dashboardzie „Sprawdzonych plików: 0” / „Ostatnie skanowanie: —”? Demon clamd tylko trzyma sygnatury w pamięci, sam niczego nie skanuje według harmonogramu. Panel pokazuje wyniki zaplanowanego skanowania, dlatego potrzebny jest cron, który skanuje i zapisuje log. Automatyczna instalacja dodaje nakładkę /usr/local/bin/clamav-scan.sh oraz cron o 01:30 — po pierwszym uruchomieniu wypełnią się „Sprawdzonych plików” i „Ostatnie skanowanie”. Aby uruchomić od razu, bez czekania na harmonogram: sudo /usr/local/bin/clamav-scan.sh.

16. Instalacja Linux Malware Detect (maldet)

Linux Malware Detect (LMD) — skaner złośliwego oprogramowania nastawiony na zagrożenia webowe: powłoki PHP, webowe backdoory, loadery. Wykorzystuje silnik ClamAV i uzupełnia go własnymi sygnaturami.

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 # Zaktualizuj sygnatury: sudo maldet -u # Skanuj /var/www: sudo maldet -a /var/www
LMD i ClamAV dobrze działają w parze. Ostatni raport: maldet --report.
Podczas instalacji może pojawić się wiersz update-rc.d: error: unable to read /etc/init.d/maldet — jest on nieszkodliwy. maldet nie korzysta z init.d, aktualizacja sygnatur i skany uruchamiane są przez /etc/cron.daily/maldet. Jeśli poniżej widać installation completed — wszystko się zainstalowało.
Na stronie LMD wyświetla „Nie zainstalowano”, choć jest zainstalowany? maldet instaluje się nie przez apt, lecz w /usr/local/maldetect, a przy włączonym open_basedir jego obecność sprawdzana jest przez powłokę — zob. sekcję „Strona jest pusta, choć dane na serwerze istnieją”.

17. Instalacja Suricata

Sieciowy system wykrywania włamań: analizuje ruch na poziomie pakietów i zna tysiące sygnatur ataków. Uzupełnia ModSecurity (ten działa na poziomie HTTP, Suricata — na poziomie TCP/IP).

sudo add-apt-repository ppa:oisf/suricata-stable sudo apt update && sudo apt install suricata # Pobierz aktualne reguły: sudo suricata-update sudo systemctl enable --now suricata
Suricata „Aktywna”, ale panel nie pokazuje alertów / liczba zdarzeń wynosi 0? Suricata zapisuje /var/log/suricata/eve.json jako root w trybie 750 dla katalogu, a serwer WWW (www-data) nie może go odczytać. Otwórz katalog na przejście — pliki wewnątrz pozostają chronione:
sudo chmod o+rx /var/log/suricata
Automatyczna instalacja robi to sama — ręcznie nie trzeba.

18. Instalacja Falco

Przechwytuje wywołania systemowe przez eBPF/kernel module i wykrywa anomalie w czasie rzeczywistym: shell z nginx, odczyt /etc/passwd przez proces webowy, zapis do /bin itd.

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
Monitor odczytuje zdarzenia Falco przez journalctl -u falco (bez sudo — przez grupę systemd-journal). Proszę upewnić się, że www-data należy do tej grupy — patrz „Konfiguracja sudo” (pkt 2) na stronie instalacji ręcznej.
„0 zdarzeń w ciągu 24 godzin” to norma, a nie błąd. Falco jest event-driven: milczy, gdy wszystko jest w porządku, i zapisuje zdarzenie tylko przy anomalii (shell z procesu webowego, odczyt /etc/passwd, zapis do katalogów systemowych). Zero zdarzeń krytycznych w ciągu doby na spokojnym serwerze to zdrowy stan.
Dla panelu pewniejszy jest zapis do pliku. Odczyt przez journalctl wymaga uprawnień do dziennika; aby panel widział zdarzenia stabilnie, autoinstalacja włącza w Falco file_output/var/log/falco/falco.log, a usłudze ustawia UMask=0022 (log odczytywany przez serwer WWW). Przy nowej instalacji nie trzeba tego konfigurować ręcznie.

19. Instalacja ModSecurity (WAF)

ModSecurity — zapora webowa (WAF) dla Apache lub Nginx. Blokuje ataki na poziomie aplikacji: wstrzyknięcia SQL, XSS, obejście ścieżek, skanery.

# Apache: sudo apt install libapache2-mod-security2 sudo a2enmod security2 # Zestaw reguł OWASP Core Rule Set: sudo apt install modsecurity-crs # OBOWIĄZKOWO: bez tego pliku silnik reguł jest wyłączony 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 # Sprawdzenie: powinno zwrócić 403 curl -s -o /dev/null -w '%{http_code}\n' "https://monitor.example.com/?id=1%20UNION%20SELECT%201,2--"
Sama instalacja pakietu niczego nie chroni. Apache dołącza konfiguracje wierszem IncludeOptional /etc/modsecurity/*.conf, a pakiet umieszcza tylko modsecurity.conf-recommended — pod maskę *.conf ten plik nie pasuje. Jeśli nie skopiuje go Pan do modsecurity.conf, SecRuleEngine pozostaje Off: moduł jest załadowany, reguły CRS załadowane, ale ruch nie jest sprawdzany, a log audytu nie powstaje. Tryb pośredni DetectionOnly tylko zapisuje zdarzenia do logu, nie blokując żądań — panel pokazuje go na żółto.

Dostęp panelu do logu audytu. Log /var/log/apache2/modsec_audit.log należy do root (uprawnienia 640), użytkownik webowy go nie odczyta. Panel pobiera dane przez nakładkę — proszę ją utworzyć:

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 # w /etc/sudoers.d/monitor (użytkownik = ten, pod którym działa PHP-FPM): # www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-modsec
Nakładka pobiera ostatnią dyrektywę SecRuleEngine bez wcięcia: wiersze z wcięciem znajdują się wewnątrz bloków <LocationMatch>/<Directory> (na przykład wyłączenie WAF dla phpMyAdmin) i nie określają trybu globalnego.
Użytkownik w sudoers musi być zgodny z użytkownikiem puli FPM: na zwykłym Apache/Debian jest to www-data, w HestiaCP pula witryny działa jako właściciel witryny (na przykład admin) — proszę sprawdzić grep -E '^user' /etc/php/*/fpm/pool.d/monitor.example.com.conf.
Jeśli witryna stoi za proxy Nginx (HestiaCP), Apache widzi jako klienta samo proxy — panel pobiera prawdziwy IP atakującego z nagłówka X-Forwarded-For. Do statystyk trafiają tylko transakcje z wyzwoloną regułą: dyrektywa SecAuditLogRelevantStatus zapisuje w logu audytu wszelkie odpowiedzi 4xx/5xx, dlatego trafiają tam także zwykłe 403/500 — panel nie traktuje ich jako zdarzeń WAF.
Blok ---RULES--- jest potrzebny sekcji „Wszystkie aktywne reguły” — panel pokazuje nie tylko wyzwolone, ale w ogóle wszystkie załadowane reguły CRS + niestandardowe. Trzy ścieżki w pętli for f in … to typowe miejsca dla reguł CRS i lokalnych dodatków; jeśli ma Pan inny układ (pakiet umieszcza pliki we własnym katalogu lub reguły niestandardowe leżą nie w /etc/modsecurity/custom-rules.conf), proszę znaleźć rzeczywiste ścieżki poleceniem sudo grep -rl 'IncludeOptional\|^Include ' /etc/apache2/mods-enabled/security2.conf /etc/apache2/conf-enabled/*.conf 2>/dev/null i podstawić je na liście. Jeśli nakładka jest stara (bez tej sekcji) — sekcja po prostu pokaże ostrzeżenie „niedostępne”, reszta strony działa jak wcześniej.

20. Instalacja Auditd

Auditd (Linux Audit Daemon) rejestruje wywołania systemowe na poziomie jądra: logowania i wylogowania, polecenia sudo, nieudane próby uwierzytelniania, zmiany plików. Monitor pokazuje logowania, nieudane próby i polecenia sudo z dzisiaj.

sudo apt install auditd audispd-plugins sudo systemctl enable --now auditd # Sprawdź status i zdarzenia: sudo systemctl status auditd sudo ausearch -m USER_LOGIN -ts today
Monitor odczytuje zdarzenia przez ausearch (/usr/sbin/ausearch), a w razie potrzeby z /var/log/audit/audit.log poleceniem tail. Oba muszą znajdować się w sudoers.

21. Instalacja Monit

Monitoruje usługi (nginx, php-fpm, mysql itd.) i restartuje je po awarii. Może wysyłać alerty na e-mail.

sudo apt install monit sudo systemctl enable --now monit # Pliki konfiguracyjne: sudo nano /etc/monit/monitrc ls /etc/monit/conf.d/
Monitor pobiera listę usług przez monit status. W /etc/monit/monitrc musi być włączony interfejs HTTP (blok set httpd z allow localhost), w przeciwnym razie monit status zwróci błąd.
Na pulpicie widnieje „0 usług pod nadzorem”? Dwie przyczyny. (1) Interfejs HTTP jest wyłączony — w monitrc wiersz set httpd jest zakomentowany (domyślnie jako # set httpd port 2812 …). Odkomentuj blok i zezwól na localhost. (2) Samo włączenie httpd niczego nie monitoruje — Monit liczy tylko to, co opisano stansami check; bez nich lista jest pusta nawet przy działającym interfejsie. Minimalna działająca konfiguracja:
# /etc/monit/conf.d/00-httpd — interfejs HTTP dla localhost: set httpd port 2812 use address localhost allow localhost # przykłady stansów check (co monitorować): 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 # sprawdź składnię (Control file syntax OK) sudo systemctl reload monit sudo monit status
Automatyczna instalacja umieszcza gotowy conf.d z httpd na 2812 i zestawem sprawdzeń — przy nowej instalacji nie trzeba nic konfigurować ręcznie.
Usługa w statusie „Z błędami”? Monitor tylko pokazuje stan i celowo nie restartuje usług z panelu webowego (byłoby to zdalne wykonywanie poleceń roota w panelu bezpieczeństwa). Diagnostyka i restart — przez SSH za pomocą Monit:
sudo monit status <service> # przyczyna błędu sudo monit restart <service> # restart przez Monit # jeśli Monit nie podnosi usługi — sprawdź jej własny unit: sudo systemctl status <unit> --no-pager sudo journalctl -u <unit> -n 50 --no-pager

22. Instalacja PSAD (wykrywanie skanowania portów)

PSAD analizuje dziennik iptables i wykrywa skanowanie portów oraz ataki sieciowe, przypisując każdemu źródłu poziom zagrożenia (1–5). Uzupełnia fail2ban i Suricata.

sudo apt install psad # PSAD czyta dziennik iptables — trzeba włączyć logowanie (UFW robi to sam). # Dla czystego iptables dodaj reguły LOG do łańcuchów INPUT/FORWARD. sudo psad --sig-update sudo systemctl enable --now psad
Monitor odczytuje dane przez psad --Status (wymagany w sudoers). Bez logowania iptables strona będzie pusta — to normalne, dopóki nie wystąpiły skanowania.

23. AppArmor / SELinux (kontrola dostępu)

Mandatory Access Control ogranicza, do jakich plików i zasobów może sięgać program, nawet jeśli został przejęty. W Ubuntu/Debian domyślnie używany jest AppArmor (zwykle już zainstalowany i aktywny).

# AppArmor (Ubuntu/Debian): sudo apt install apparmor apparmor-utils sudo systemctl enable --now apparmor sudo aa-status # sprawdź profile
Monitor odczytuje status przez aa-status (wymagany w sudoers). Pokazuje liczbę profili w trybie enforce/complain oraz procesy bez profilu.

„Załadowanych profili” jest więcej niż enforce + complain — to normalne. W AppArmor 4.x (Ubuntu 24.04 i nowsze) pojawił się tryb unconfined: profil jest załadowany do jądra, ale niczego nie ogranicza. Ubuntu oznacza w ten sposób dziesiątki profili dla programów korzystających z user namespaces (przeglądarki, klienty torrent i podobne). Gdy takie profile występują, karta „Załadowanych profili” zmienia kolor na bursztynowy i pokazuje ich liczbę — na przykład unconfined: 90 przy 120 załadowanych i 26 w enforce. Realnie chronią tylko profile w enforce; w Ubuntu 22.04 (AppArmor 3.x) tego trybu nie ma i liczby zawsze się zgadzają.

sudo aa-status | grep -E "profiles are" # podział na tryby sudo aa-enforce /etc/apparmor.d/profile-name # przełącz profil w tryb enforce
Przełączanie w tryb enforce profili, które Ubuntu celowo zostawiła w unconfined, warto robić tylko świadomie: nie są one wyłączone przez pomyłkę, lecz dlatego, że inaczej psuje się działanie samych programów. Profile w complain to inna sprawa: reguły są już napisane, tylko nie są stosowane.

24. Instalacja debsums (integralność pakietów)

debsums sprawdza, czy pliki zainstalowanych pakietów zgadzają się z sumami kontrolnymi z repozytorium — wykrywa podmienione systemowe pliki binarne (uzupełnia AIDE). Pełne sprawdzenie trwa 1–2 minuty, dlatego uruchamiane jest przez cron, a panel odczytuje wynik z data/debsums/debsums.log i sam porządkuje go według kategorii (istotne są tylko pliki binarne i biblioteki).

Zadanie umieszcza się w cronie roota (sudo crontab -e). Gotowy skrypt debsums-scan.sh należy umieścić w /usr/local/bin/ (chmod +x; zob. podsumowanie zadań cron) i sam zapisuje raport w katalogu data/debsums/ panelu.

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

Skrypt debsums-scan.sh sam odnajduje katalog data/ panelu — nie trzeba podawać ścieżki.

Zmiany w /etc/ (konfiguracje) i /usr/share/ (zasoby) na serwerze są zwykle normalne — panel oznacza je osobnym kolorem. Niepokojące są zmiany plików binarnych i bibliotek (/bin, /sbin, /usr/lib itp.) — karta „Pliki binarne / biblioteki” pokazuje właśnie je.

25. Konfiguracja raportów Lynis

Lynis uruchamia się ręcznie lub przez cron. Raport musi być zapisywany w folderze data/lynis/ projektu — monitor odczytuje plik lynis-report.dat.

# Jednorazowe uruchomienie (podstaw własną ścieżkę do katalogu głównego panelu): sudo lynis audit system --report-file /path/to/monitor/data/lynis/lynis-report.dat # Codzienny audyt — wiersz cron (gotowy wrapper lynis-scan.sh w /usr/local/bin/, patrz podsumowanie): 0 3 * * * /usr/local/bin/lynis-scan.sh >> /path/to/monitor/logs/cron.log 2>&1
Po pierwszym uruchomieniu strona „Audyt Lynis” od razu pokaże hardening index, ostrzeżenia i rekomendacje.
Przycisk „Uruchom audyt” na stronie Lynis. Uruchamia on lynis-scan.sh w tle bezpośrednio z panelu (bez czekania na cron): pokazuje „Skanowanie…”, a po zakończeniu sam odświeża raport. Wymaga to wiersza sudoers dla użytkownika serwera WWW na uruchomienie skryptu — instalator dodaje go automatycznie do /etc/sudoers.d/monitor. Jeśli panel był instalowany ręcznie/wcześniej, dopisz go dla tego samego użytkownika, który jest już wskazany w pliku:
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. Konfiguracja raportów Logwatch

Logwatch powinien zapisywać dzienne raporty w folderze data/logwatch/ projektu w formacie .txt. Monitor pokazuje ostatni raport oraz archiwum.

# Codziennie (6:00) — linia cron (gotowa nakładka logwatch_daily.sh w /usr/local/bin/, patrz podsumowanie): 0 6 * * * /usr/local/bin/logwatch_daily.sh >> /path/to/monitor/logs/cron.log 2>&1

Moduły panelu

27. Monitor sieci (wbudowany)

Monitor sieci nie wymaga instalacji — to wbudowana strona panelu. Pokazuje stan sieci serwera z lokalnych źródeł:

  • interfejsy i ruch — z /proc/net/dev;
  • stan łączy (UP/DOWN) i IP — przez ip;
  • połączenia i nasłuchujące porty — przez ss;
  • sieciowe zdarzenia jądra z ostatnich 24 h — przez journalctl -k.

Pierwsze trzy źródła działają bez sudo, dlatego interfejsy, ruch, połączenia i porty są widoczne od razu. Blok „Zdarzenia jądra” korzysta z journalctl -k — odczyt odbywa się przez grupę systemd-journal („Konfiguracja sudo”, p.2), sudo nie jest potrzebne. Aby sprawdzić, czy wszystko jest dostępne dla użytkownika WWW:

# Sprawdzenie jako www-data (pod nim działa PHP): sudo -u www-data bash -c 'cat /proc/net/dev' sudo -u www-data bash -c 'ip -o link show' sudo -u www-data bash -c 'ss -s' sudo -u www-data journalctl -k --no-pager -n 5
Blok „Sieciowe zdarzenia jądra” pokazuje zdarzenia stosu sieciowego jądra (zmiana łącza up/down, błędy nośnej, „network unreachable”). Wpisy zapory UFW BLOCK tutaj nie trafiają — są na stronach „Zapora UFW” i „Mapa ataków”. Pusty blok z zielonym znaczkiem = w ciągu doby nie było awarii sieci.

28. Dysk i SMART

Wbudowana strona pokazuje trzy rzeczy:

  • Systemy plików — zapełnienie partycji (df); skala czerwienieje przy ≥90%;
  • Nośniki — lista dysków (lsblk), tylko rzeczywiste (loop/snap ukryte);
  • Kondycja (SMART) — status dysku i atrybuty (smartctl).

Miejsce i lista urządzeń działają od razu, bez konfiguracji. Dla SMART potrzebny jest pakiet smartmontools. Proces webowy nie ma bezpośredniego dostępu do urządzeń dyskowych, dlatego SMART jest zbierany przez cron do pliku data/disk/smart.txt, a panel go odczytuje.

Zadanie umieszcza się w root-cronie (sudo crontab -e). Gotowa nakładka smart-scan.sh jest umieszczana w /usr/local/bin/ (chmod +x; zob. zestawienie zadań cron) i sama zapisuje do data/disk/ panelu.

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

Nakładka smart-scan.sh sama znajduje data/ panelu — ścieżki nie trzeba podawać. Wewnątrz lsblk -e7,11 wyklucza loop/cdrom.

Na dyskach wirtualnych (QEMU/KVM i podobnych) zwykle dostępny jest tylko ogólny status „kondycja: OK”, a temperatura, godziny pracy i realokowane sektory mogą być puste — to normalne. Na serwerze fizycznym wyświetlane są wszystkie atrybuty.

29. Wydajność (CPU/RAM/Sieć/Dysk)

Strona pokazuje historię obciążenia serwera z ostatnich 24 godzin — Load Average, zajętość CPU i oczekiwanie I/O, RAM/Swap, ruch sieciowy (odbiór/wysyłka), I/O dysku (odczyt/zapis), zapełnienie dysku i i-węzłów, otwarte deskryptory plików i połączenia MySQL, a także bieżącą liczbę połączeń TCP i procesów.

Dane zbiera cron/collect_metrics.php — co 5 minut zapisuje jeden „surowy” zrzut liczników (/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') do tabeli bazy system_metrics; procenty i prędkości strona liczy sama na podstawie różnicy między sąsiednimi zrzutami (zapełnienie dysku/i-węzłów/deskryptorów/połączenia MySQL — wartości chwilowe, bez przeliczania). Sudo nie jest wymagane — źródła są odczytywane bez uprawnień root. Punkty starsze niż 24 godziny są usuwane automatycznie przy każdym zapisie.

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

Nakładka collect-metrics-all.sh (zob. zestawienie zadań cron) sama wykrywa wszystkie zainstalowane instancje panelu na serwerze i uruchamia cron/collect_metrics.php każdej z nich w imieniu właściciela witryny.

Dopóki kolektor nie zadziała co najmniej dwa razy (pierwsze ~10 minut po instalacji), strona pokazuje „trwa zbieranie danych” — wykresy potrzebują minimum jednej pary sąsiednich punktów, aby obliczyć prędkości i procenty.

Alerty o obciążeniu (sekcja „Ustawienia” → „Alerty o obciążeniu”) — po przekroczeniu progu CPU/RAM/dysku/i-węzłów panel wysyła powiadomienie na Telegram/Email (te same kanały, co raport dzienny — nie trzeba włączać ich osobno dla alertów), a kolejne — gdy metryka wróci do normy. Podczas utrzymywania się przekroczenia progu nie spamuje ponownie: następne powiadomienie przyjdzie dopiero po cyklu „wróciło do normy → ponownie przekroczyło”.

Progi są sprawdzane przez ten sam collect_metrics.php przy każdym uruchomieniu (co 5 minut) — osobny cron nie jest potrzebny. Stan „już powiadomiono / jeszcze nie” jest przechowywany w data/alerts_state.json, a progi — w ustawieniach panelu.

30. Mapa ataków (GeoIP)

Strona „Mapa ataków” określa kraj na podstawie IP za pomocą polecenia geoiplookup. Bez pakietu GeoIP kraje nie zostaną określone, a punkty na mapie się nie pojawią:

sudo apt install geoip-bin geoip-database # Sprawdzenie: geoiplookup 8.8.8.8
Sudo nie jest wymagane — baza /usr/share/GeoIP/GeoIP.dat jest czytelna dla wszystkich, a wyniki są buforowane w tmp/geoip_cache.json. Sama mapa (Leaflet + kafelki OpenStreetMap) ładuje się w przeglądarce — potrzebny jest internet na komputerze, na którym otwarto panel.

31. Ekspozycja zewnętrzna, aktualizacje i automatyczne aktualizacje

Dwie wbudowane karty pulpitu, które pokazują nie „wł./wył.” narzędzia, lecz rzeczywisty poziom zabezpieczenia serwera. Nie wymagają instalacji, są odczytywane lokalnie bez sudo.

Ekspozycja zewnętrzna — ile usług nasłuchuje na wszystkich interfejsach (0.0.0.0/[::]) i jest dostępnych z zewnątrz. Zaznacza na czerwono, jeśli na zewnątrz wystawione są bazy danych lub cache (MySQL, PostgreSQL, Redis, MongoDB, Memcached, Elasticsearch) — to bezpośrednia luka (−10 do Oceny bezpieczeństwa). Źródło: ss -tuln.

Jeśli karta jest czerwona — zamknij bazy danych przed światem zewnętrznym: przypisz do 127.0.0.1 (bind-address w konfiguracji MySQL/PostgreSQL, bind 127.0.0.1 w Redis) lub zamknij port w UFW.
„Otwarty port” ≠ „dostępny z zewnątrz”. Usługa nasłuchująca na 127.0.0.1 (loopback) jest widoczna tylko dla samego serwera — z zewnątrz nie da się do niej dotrzeć, nawet jeśli port jest „otwarty”. Dlatego Postfix na porcie 25 przypisany do loopback jest bezpieczny: automatyczna konfiguracja ustawia inet_interfaces = loopback-only (plus neutralny smtpd_banner — usuwa uwagę Lynis MAIL-8818 o ujawnianiu wersji). Karta „Ekspozycja zewnętrzna” liczy jako zewnętrzne tylko to, co nasłuchuje na 0.0.0.0/[::]; usługi loopback tam nie trafiają.
Lynis MAIL-8818 ręcznie (jeśli pocztę konfigurował Pan samodzielnie): w /etc/postfix/main.cf ustaw smtpd_banner = $myhostname ESMTP (bez wersji i systemu) oraz inet_interfaces = loopback-only, następnie sudo systemctl restart postfix.

Aktualizacje zabezpieczeń — ile poprawek bezpieczeństwa czeka na instalację i czy po aktualizacji jądra wymagany jest restart (−5 do Oceny bezpieczeństwa przy dostępnych poprawkach). Źródło: /usr/lib/update-notifier/apt-check, plik /var/run/reboot-required. Szczegółowa lista — na stronie „Aktualizacje zabezpieczeń”.

# Zainstaluj aktualizacje: sudo apt update && sudo apt upgrade # Sprawdź, co nasłuchuje na zewnątrz: ss -tuln | grep -E '0\.0\.0\.0|\[::\]'
Karta aktualizacji działa na Ubuntu/Debian (update-notifier-common). Jeśli apt-check jest niedostępny — monitor liczy poprawki poprzez apt-get -s upgrade.

Automatyczne aktualizacje zabezpieczeń (unattended-upgrades) — na stronie „Aktualizacje zabezpieczeń” osobna karta pokazuje, czy automatyczna instalacja poprawek bezpieczeństwa jest włączona i kiedy uruchomiono ją ostatnio. Sudo nie jest potrzebne — status jest odczytywany przez apt-config dump.

sudo apt install unattended-upgrades sudo dpkg-reconfigure -plow unattended-upgrades # włącz # Sprawdź, co jest włączone: apt-config dump | grep Unattended-Upgrade

Konserwacja

32. Kopie zapasowe

Kopia zapasowa to główne zabezpieczenie: utrata danych jest gorsza niż każde włamanie. Potrzebne są dwie rzeczy — kopia serwera/witryn oraz osobno kopia bazy danych panelu (tam znajdują się użytkownicy, klucze WebAuthn, ustawienia, licencja).

Wariant A — HestiaCP: zakładka Backup u użytkownika → przycisk tworzenia kopii (lub według harmonogramu w ustawieniach serwera). Kopia obejmuje witryny i ich bazy danych.

Wariant B — ręcznie (cron): zrzut bazy danych + archiwum katalogu data/ panelu:

# cron roota (sudo crontab -e) — codzienna kopia o 2:30 (wstaw własne nazwy/ścieżki): 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 # Usuwaj archiwa starsze niż 14 dni: 0 3 * * * find /var/backups -name 'monitor-*' -mtime +14 -delete
Kopia na tym samym serwerze chroni przed błędami, ale nie przed utratą serwera. Kopiuj archiwa do zewnętrznego magazynu (inny serwer, S3, rclone do chmury). Sprawdzaj, czy przywracanie faktycznie działa.

33. Aktualizacja i migracja panelu

Aktualizacja do nowej wersji. Najpierw proszę wykonać kopię zapasową. Następnie proszę ponownie wgrać pliki kodu, zachowując swoje dane:

  • nadpisać (kod): public/, includes/, assets/, cron/, database/, a także główne .htaccess (kontroler frontowy — routingu nie można pozostawić z poprzedniej wersji), manifest.json, sw.js;
  • nie ruszać: config.php (dane bazy danych), data/ (raporty), logs/, tmp/ (sesje i pamięć podręczna).
# Po wgraniu — wyczyścić pamięć podręczną PHP (jeśli opcache jest włączony): sudo systemctl reload php*-fpm
FileZilla zgłasza SSH_FX_PERMISSION_DENIEDPermission denied. Pliki panelu należą do www-data (tak zostały ustawione przy instalacji), a klient SFTP łączy się na własnym użytkowniku, który nie ma prawa zapisu. Oddanie www-data całego panelu „żeby działało” to właśnie to, co prowadzi do tego błędu; poniżej trzy sposoby, każdy rozwiązuje problem.
# Wariant A (zalecany) — rozdzielić właścicieli: kod Pański, katalogi robocze serwera WWW. # Serwer WWW nie dostaje prawa zapisu do KODU panelu w ogóle: 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 # Wariant B — ACL na istniejących właścicielach (nic nie przenosimy): 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 # Wariant C — przez grupę www-data. Prostszy, ale prawo zapisu do plików panelu # dostaje również serwer WWW (przy podatności w PHP kod da się podmienić): 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
Dlaczego wariant A jest bezpieczny. Panel zapisuje tylko do trzech katalogów — data/ (raporty), tmp/ (sesje i pamięć podręczna), logs/; pozostają one przy www-data. Reszta to kod, a serwer WWW potrzebuje go jedynie do odczytu, który zapewnia grupa www-data z prawami 644. Dodatkowa korzyść: przy podatności w PHP plików panelu już nie da się nadpisać. Na panelach hostingowych (HestiaCP i podobnych) wariant A nie jest potrzebny: tam pliki witryny i tak należą do konta, na które Pan loguje się przez SFTP, a serwer WWW czyta je po grupie.
Pułapka wariantu B: każdy kolejny chmod na plikach resetuje maskę ACL i dostęp po cichu znika. Jeśli po „uporządkowaniu praw” wgrywanie znów natrafia na Permission denied — proszę powtórzyć obie komendy setfacl.
Bit 2 w wariancie C to setgid: pliki wgrane przez SFTP pozostają w grupie www-data, inaczej panel nie będzie mógł ich nadpisać. Po wariancie C proszę połączyć się ponownie w FileZilli — nowa grupa działa dopiero przy nowym logowaniu. Sprawdzenie: id deploy (musi pojawić się grupa www-data) oraz ls -ld /path/to/monitor (drwxrwsr-x — litera s oznacza, że setgid jest ustawiony).

Migracja na inny serwer:

  1. Na nowym serwerze proszę uruchomić witrynę + HTTPS (zob. stronę ręcznej instalacji).
  2. Proszę skopiować wszystkie pliki panelu wraz z config.php, data/.
  3. Proszę przenieść bazę danych: mysqldump na starym → import na nowym; proszę poprawić dane bazy danych w config.php.
  4. Proszę powtórzyć na nowym serwerze: sudoers, przynależność do grupy adm, zadania cron.
  5. Licencja jest powiązana z domeną — jeśli domena jest ta sama, klucz będzie działał nadal.

34. Odzyskiwanie dostępu (utracony klucz, hasło, blokada IP)

Jeśli nie może się Pan zalogować — wszystko naprawia się bezpośrednio w bazie danych z serwera. Proszę otworzyć bazę danych (nazwa — z config.php):

sudo mysql MY_DB

Utracony klucz WebAuthn (drugi składnik nie przechodzi) — proszę wyłączyć 2FA, zalogować się hasłem i zarejestrować nowy klucz:

UPDATE users SET webauthn_enabled = 0;

Zapomniane hasło — proszę ustawić nowy hash (wygeneruj go na serwerze i podstaw):

# Wygeneruj hash nowego hasła: php -r "echo password_hash('NEW_PASSWORD', PASSWORD_BCRYPT), \"\n\";" # W bazie danych (wstaw uzyskany hash): # UPDATE users SET password = '$2y$10$...' WHERE username = 'admin';

Zablokowanie samego siebie filtrem IP — proszę wyłączyć ograniczenie:

UPDATE settings SET value = '0' WHERE name = 'ip_restriction_enabled';
Dostęp do bazy danych jest zawsze możliwy: sudo mysql na serwerze albo phpMyAdmin / sekcja bazy danych w panelu hostingu. Po odzyskaniu proszę ponownie włączyć WebAuthn i filtr IP.

35. Wszystkie zadania cron w jednym miejscu

Zestawienie zadań — w cronie root serwera (dodawane przez sudo crontab -e). Proszę zostawić tylko wiersze narzędzi, których Pan/Pani używa; ścieżki dopasować do swojego serwera.

# Serwerowy cron monitora (root) — proszę wpisać przez: sudo crontab -e # 01:30 — skan ClamAV po niebezpiecznych ścieżkach (web, home, temp) → karty „Sprawdzonych plików” i „Ostatnie skanowanie” 30 1 * * * /usr/local/bin/clamav-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 02:00 — sprawdzenie integralności plików AIDE (wymagany jawny --config) 0 2 * * * /usr/bin/aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1 # przy starcie — przywrócić uprawnienia /var/lib/aide (pakietowy plik tmpfiles # aide-common.conf ustawia je na 0700 i panel przestaje widzieć bazę) @reboot chmod 755 /var/lib/aide # 03:00 — audyt bezpieczeństwa Lynis 0 3 * * * /usr/local/bin/lynis-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 04:00 — aktualizacja listy blokad ipsum (level 1) 0 4 * * * /usr/local/bin/load-ipsum.sh >> /path/to/monitor/logs/cron.log 2>&1 # zestaw ipsum przy starcie podnosi usługa ipsum-load.service (PRZED zaporą, inaczej # UFW nie zobaczy zestawu w before.rules) — nie cron. Tu tylko codzienne odświeżanie powyżej. # 06:00 — raport Logwatch 0 6 * * * /usr/local/bin/logwatch_daily.sh >> /path/to/monitor/logs/cron.log 2>&1 # co 30 min — sprawdzenie dysków SMART */30 * * * * /usr/local/bin/smart-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 04:30 — integralność pakietów debsums 30 4 * * * /usr/local/bin/debsums-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 08:00 — raport według harmonogramu na Email i Telegram 0 8 * * * /usr/local/bin/daily-report-all.sh >> /path/to/monitor/logs/cron.log 2>&1 # co godzinę — odświeżanie list pakietów (dla karty „Aktualizacje zabezpieczeń”) 0 * * * * /usr/bin/apt-get update -qq >/dev/null 2>&1 # co 5 min — zrzut zasobów (CPU/RAM/sieć/dysk) dla strony „Wydajność” */5 * * * * /usr/local/bin/collect-metrics-all.sh >> /path/to/monitor/logs/cron.log 2>&1
Szczegóły każdego — w odpowiednich sekcjach. Zadania kopii zapasowej (poprzednia sekcja) dodaje się do tego samego crona. Po zmianach proszę sprawdzić: sudo crontab -l oraz to, że usługa cron jest aktywna.
Czas cron = strefa czasowa serwera, a nie TIMEZONE z config.php. Stała TIMEZONE wpływa tylko na PHP (jak panel pokazuje daty), ale demon cron uruchamia zadania według czasu systemowego OS. Jeśli strefa serwera nie zgadza się z Pana/Pani strefą, raport „08:00” przyjdzie o innej porze. Przykład: serwer stoi w innej strefie (Europe/London, UTC+1), a Pan/Pani jest w Warszawie (UTC+2) → raport „08:00” przyjdzie o 09:00 według Pana/Pani czasu. Proszę sprawdzić i w razie potrzeby dostosować strefę systemu do swojej:
# Sprawdzić bieżącą strefę serwera: timedatectl # Ustawić swoją strefę (przykład) i zrestartować cron: sudo timedatectl set-timezone Europe/Warsaw sudo systemctl restart cron
Po tym wiersz 0 8 * * * zadziała o 08:00 czasu lokalnego. Inaczej trzeba by przesuwać sam cron, ale przy zmianie czasu zimowego/letniego przesunięcie znów się rozjedzie — dlatego właściwsze jest ustawienie strefy systemu.
Gotowe skrypty-nakładki. Ich robocze kopie i wzór crontab (crontab.txt) leżą w folderze system/ obok projektu, poza public_html. To nie część witryny — nie trzeba ich wgrywać do katalogu web; proszę umieścić je na serwerze pod ścieżkami systemowymi (jak w crontab powyżej):
  • lynis-scan.sh/usr/local/bin/ (chmod +x) — uruchamia lynis audit system, na czas skanu ustawia flagę /tmp/lynis-running i kopiuje lynis-report.dat do data/lynis/ panelu;
  • logwatch_daily.sh/usr/local/bin/ (chmod +x) — tworzy codzienny raport Logwatch (sshd, fail2ban, sudo, postfix) w data/logwatch/;
  • smart-scan.sh/usr/local/bin/ (chmod +x) — zbiera stan dysków (smartctl) w data/disk/;
  • debsums-scan.sh/usr/local/bin/ (chmod +x) — sprawdza integralność pakietów (debsums) w data/debsums/;
  • clamav-scan.sh/usr/local/bin/ (chmod +x) — skan antywirusowy ClamAV po niebezpiecznych ścieżkach (web, home, temp); zapisuje zestawienie do /var/log/clamav/scan.log, skąd czyta je strona ClamAV (wiersz 01:30 w crontab powyżej);
  • load-ipsum.sh/usr/local/bin/ (chmod +x) — aktualizuje zbiór ipset ipsum (level 1) w miejscu, bez zrywania aktywnych reguł zapory (wiersz 04:00 w crontabie powyżej);
  • daily-report-all.sh/usr/local/bin/ (chmod +x) — uruchamia raport cron/daily_report.php panelu (wiersz 08:00 w crontab powyżej);
  • daily_report.php — już wchodzi w skład panelu (cron/daily_report.php), uruchamiany przez daily-report-all.sh, nie trzeba go osobno instalować;
  • collect-metrics-all.sh/usr/local/bin/ (chmod +x) — uruchamia cron/collect_metrics.php panelu (strona „Wydajność”, wiersz */5 w crontab powyżej); collect_metrics.php już wchodzi w skład panelu, nie trzeba go osobno instalować;
  • crontab.txt (system/cron/) — wzór zadań; potrzebne wiersze proszę wpisać przez sudo crontab -e.
Ścieżka do skryptu w crontab musi zgadzać się z tym, gdzie go Pan/Pani umieścił.
Jak umieścić skrypt w /usr/local/bin/. Bezpośrednio z FileZilla nie da się tam zapisać — katalog należy do root, a klient SFTP otrzyma SSH_FX_PERMISSION_DENIED. Kolejność jest taka: najpierw wgrać plik do /tmp (tam piszą wszyscy), następnie przenieść go na miejsce jednym poleceniem:
# w FileZilla: w polu „Zdalny serwer” wpisać /tmp i wgrać tam skrypt, # następnie przez SSH (install od razu ustawia właściciela i uprawnienia, chown/chmod niepotrzebne): sudo install -o root -g root -m 755 /tmp/lynis-scan.sh /usr/local/bin/lynis-scan.sh rm -f /tmp/lynis-scan.sh # sprawdzenie: plik na miejscu, uprawnienia rwxr-xr-x, składnia cała bash -n /usr/local/bin/lynis-scan.sh && ls -l /usr/local/bin/lynis-scan.sh
Proszę nie pomylić katalogów: potrzebny jest /tmp w katalogu głównym serwera — nie /var/tmp i nie tmp/ wewnątrz samego panelu (ten ostatni należy do www-data i jest zamknięty dla Pana/Pani użytkownika). W drzewie FileZilla /tmp to gałąź najwyższego poziomu, obok var, a nie wewnątrz niej.
Stawiał Pan/Pani serwer autokonfiguracją? Te nakładki i ich zadania cron są już zainstalowane przez skrypt (w /usr/local/bin/, log — /var/log/arciveo-cron.log) — ręcznie nie trzeba nic robić.
Gdzie skrypty szukają panelu. Nakładki są neutralne domenowo: znajdują instalacje panelu, przeszukując /home/*/web/*/public_html i /var/www/*, i zapisują raporty do ich data/. Jeśli panel leży pod inną ścieżką — proszę dodać ją do wiersza for app in … wewnątrz skryptów, inaczej raporty Lynis/SMART/debsums/Logwatch nie trafią do panelu.
cron.log i uprawnienia dostępu. Plik logs/cron.log jako pierwszy tworzy cron root — będzie należał do root, a zakładka „Dziennik cron” w panelu nie będzie mogła go ani odczytać, ani wyczyścić. Proszę utworzyć plik wcześniej jako użytkownik web (właściciel katalogu witryny; w HestiaCP to konto, np. admin) — wtedy cron root będzie tylko dopisywać, nie zmieniając właściciela:
# utworzyć wcześniej jako użytkownik web (przed dodaniem wierszy cron): sudo -u OWNER touch /path/to/monitor/logs/cron.log # jeśli cron.log już utworzył cron root — przekazać użytkownikowi web: sudo chown OWNER:OWNER /path/to/monitor/logs/cron.log sudo chmod 644 /path/to/monitor/logs/cron.log
Sprawdzenie właściciela katalogu: stat -c %U /path/to/monitor.
Zarządzanie z panelu. W sekcji „System” jest strona „Crontab” — można oglądać i dodawać zadania bez SSH. Panel edytuje tylko zadania dodane przez niego samego (osobny blok w crontab root, oznaczony komentarzami służbowymi); wszystko, co już jest w crontab (lista powyżej), pokazane jest tam jako lista tylko do odczytu „Pozostałe zadania serwera” z przyciskiem „Skopiuj do edytora” — przenosi on tylko harmonogram/polecenie do formularza dodawania, nie ruszając wiersza źródłowego. Aby „przenieść” istniejące zadanie pod zarządzanie panelu — proszę skopiować je do edytora, zapisać, a następnie ręcznie usunąć stary wiersz (sudo crontab -e), inaczej będzie wykonywane dwa razy.
Jednorazowa konfiguracja na serwerze. Strona potrzebuje uprzywilejowanego skryptu-nakładki — nie gołego sudo crontab (to byłaby bezpośrednia eskalacja do root dla każdego, kto uzyska dostęp do sesji panelu), lecz wąskiego skryptu z dwoma poleceniami (list/set), który rusza tylko swój blok między komentarzami służbowymi. Proszę zainstalować raz:
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
Użytkownik web może różnić się od www-data — proszę sprawdzić, na kim działa pula PHP-FPM witryny (ps -o user= -C php-fpm), i podstawić go w wierszu sudoers.
Nowy plik wgrał się z niewłaściwym właścicielem — strona odpowiada „Access denied.”. Jeśli plik public/crontab_monitor.php został wgrany przez FTP/SFTP jako inny użytkownik systemowy (np. root) niż pozostałe pliki witryny, serwer web nie zdoła go odczytać. Proszę porównać właściciela i uprawnienia z sąsiednim plikiem i doprowadzić do zgodności:
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

Diagnostyka

36. Narzędzie jest zainstalowane, ale widnieje „Nie zainstalowano”

Monitor wykrywa obecność narzędzi za pomocą dpkg-query — bazy pakietów APT. Jeśli narzędzie nie zostało zainstalowane przez apt (ręcznie, ze snap lub ze źródeł), dpkg go nie widzi.

# Sprawdź za pomocą dpkg: dpkg -l fail2ban | grep '^ii' dpkg -l auditd | grep '^ii' # Znajdź ścieżkę do pliku binarnego: which ufw fail2ban-client auditctl # Test sudo od www-data: sudo -u www-data sudo fail2ban-client status sudo -u www-data sudo ufw status verbose

37. Rozwiązywanie problemów (500, brak danych)

Błąd 500 — proszę sprawdzić logi PHP, nginx oraz samego monitora:

tail -50 /var/log/nginx/error.log tail -50 /var/log/php*-fpm.log # Logi monitora: tail -50 logs/monitor_$(date +%Y-%m-%d).log # Uprawnienia do katalogów: ls -la data/ tmp/ logs/
Panel na panelu hostingowym (HestiaCP, ISPmanager, cPanel)? Tam PHP działa nie pod www-data, lecz pod kontem użytkownika (na przykład admin — właściciel katalogu witryny). Wszystkie reguły sudo i przynależność do grup (adm, systemd-journal) należy zapisać dla tego użytkownika, inaczej moduły pokażą „Nieaktywny / 0” przy działających usługach. Aby poznać rzeczywistego użytkownika PHP: ps -o user= -C php-fpm | sort -u lub właściciela katalogu witryny stat -c '%U' /path/to/monitor. Dalej we wszystkich poleceniach poniżej proszę podstawić go zamiast www-data. Automatyczna instalacja sama wykrywa użytkownika serwera WWW i zapisuje dla niego sudoers.

Dane się nie wyświetlają — prawie zawsze przyczyną są nieustawione uprawnienia sudo. Proszę sprawdzić konkretne polecenie jako użytkownik serwera WWW (zamieniając www-data na własnego). Flaga -n = bez hasła, tak jak w PHP — jeśli prosi o hasło, to znaczy, że reguły w sudoers nie ma:

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
Moduł pokazuje „Nieaktywny” / „0”, choć narzędzie działa (na przykład sudo aa-status w terminalu pokazuje profile, a strona „AppArmor” — „Nieaktywny”). Przyczyna: użytkownik serwera WWW nie ma uprawnienia sudo do polecenia tego modułu. Proszę je sprawdzić z listy powyżej: jeśli prosi o hasło — dodać brakujący wiersz do /etc/sudoers.d/monitor („Konfiguracja sudo”). Częste „nowe” polecenia: /usr/sbin/aa-status (MAC), /usr/sbin/psad --Status (PSAD).
Jeśli konkretna strona (Falco, ModSecurity, Auditd, otwarte porty UFW) jest pusta — proszę sprawdzić listę w sekcji o sudo: prawdopodobnie nie jest dozwolony apache2ctl, ausearch, aa-status lub ss, albo użytkownik serwera WWW nie należy do grup adm/systemd-journal (stamtąd czytane są logi fail2ban/auth/modsec oraz journalctl — Falco i zdarzenia jądra).

38. Strona jest pusta, choć dane na serwerze istnieją

Objaw: na serwerze dane są (widać je przez shell), a strona pokazuje „brak danych” lub nieprawidłowy status — na przykład AIDE wyświetla „Nie zainicjalizowana”, choć baza została utworzona.

Przyczyną jest open_basedir: wiele paneli i hostingów ogranicza pulę PHP-FPM do katalogu domeny, przez co funkcje PHP file_exists(), file_get_contents(), filemtime() na ścieżkach systemowych (/var/lib/aide, /var/log, /proc…) są blokowane. Monitor omija to, odczytując takie ścieżki standardowymi poleceniami systemowymi (cat, test, stat).

# Czy plik jest widoczny przez shell (tak odczytuje go monitor): sudo -u www-data bash -lc 'test -e /var/lib/aide/aide.db && echo VISIBLE || echo NO' # Bieżąca wartość open_basedir dla puli domeny: grep -ri open_basedir /etc/php/*/fpm/pool.d/ 2>/dev/null
Jeśli shell „widzi” plik (VISIBLE), a strona nie — to open_basedir. Właściwym rozwiązaniem jest odczyt poleceniami systemowymi (już zrobione dla AIDE i Monitora sieci). Rozszerzanie open_basedir na /var, /proc nie jest potrzebne i jest mniej bezpieczne.

39. Strona SSL nie działa

Monitor sprawdza certyfikaty, łącząc się z domenami bezpośrednio przez port 443. Jeśli domena jest niedostępna z samego serwera lub port jest zablokowany przez zaporę — sprawdzenie się nie powiedzie.

# Sprawdź certyfikat ręcznie: echo | openssl s_client -connect monitor.example.com:443 2>/dev/null \ | openssl x509 -noout -dates # Sprawdź dostępność: curl -I https://monitor.example.com
Domeny monitor pobiera automatycznie z konfiguracji nginx (/etc/nginx/sites-enabled/, /etc/nginx/conf.d/) i Apache (/etc/apache2/sites-enabled/) oraz z bieżącego hosta z HTTP_HOST.
Automatyczne wykrywanie subdomen. Subdomeny są wykrywane automatycznie z publicznych logów Certificate Transparency i sprawdzane przez sieć — nawet jeśli są hostowane na innych serwerach. Nie trzeba niczego dodawać ręcznie.

40. Widoczna tylko jedna baza z kilku

Monitor łączy się z MySQL jako użytkownik z config.php, który ma dostęp tylko do własnej bazy. MySQL pokazuje w information_schema jedynie bazy, do których użytkownik ma uprawnienia — dlatego pozostałe są niewidoczne.

Aby monitor widział wszystkie bazy, nadaj temu użytkownikowi prawo tylko do odczytu (jednorazowo jako root; wstaw nazwę użytkownika z config.php):

sudo mysql -u root GRANT SELECT, PROCESS, SHOW DATABASES ON *.* TO 'DB_USER'@'localhost'; FLUSH PRIVILEGES; EXIT;
SELECT ON *.* daje wyłącznie prawo odczytu — nie można niczego zmienić, usunąć ani utworzyć, więc jest to bezpieczne dla monitorowania.
Bez tego GRANT panel widzi tylko własną bazę — to nie błąd, lecz ograniczenie uprawnień. Panel nie używa żadnego sudo mysql: lista baz jest pobierana przez jego własne połączenie PDO.

41. PostgreSQL nie pojawia się na stronie „Baza danych”

PostgreSQL wymaga dostępu na poziomie użytkownika postgres, którego użytkownik sieciowy panelu nie posiada. Otwieranie z poziomu PHP szerokiego sudo psql jest niebezpieczne — zamiast tego panel wywołuje wąską nakładkę bez parametrów, która wypisuje jedynie wersję, liczbę połączeń oraz listę baz z ich rozmiarami. Proszę ją utworzyć:

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 # w /etc/sudoers.d/monitor (użytkownik = ten, pod którym działa PHP-FPM): # www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-pgstat
Jeśli nie używa Pan PostgreSQL — proszę usunąć wiersz monitor-pgstat z sudoers (krok 13 instalacji ręcznej) i nie tworzyć samego skryptu: karta PostgreSQL pozostanie po prostu nieaktywna.

42. Zadziałał alert — co robić

Panel pokazuje, co się dzieje; poniżej — co robić w typowych sytuacjach. Ogólna zasada: nie panikować, porównać z legalną aktywnością (Pana działania, aktualizacje, kopie zapasowe) i reagować odpowiednio do powagi.

  • Mapa ataków / dużo banów fail2ban — to norma dla każdego serwera w internecie (boty stale próbują SSH/web). Najważniejsze, żeby bany działały. Proszę się upewnić, że logowanie SSH odbywa się tylko kluczem (hasło wyłączone), a Pana IP jest w ignoreip.
  • ModSecurity zablokował żądania — WAF odpiera ataki na witrynę, to jego zadanie. Jeśli blokowany jest Pana legalny ruch (fałszywy alarm) — proszę znaleźć rule id w szczegółach i dodać wyjątek w konfiguracji CRS.
  • AIDE: zmienione pliki — proszę porównać listę z tym, co Pan robił (aktualizacja pakietów, edycja konfiguracji — norma). Zmiany systemowych plików binarnych, których Pan nie dotykał, to powód do czujności. Po legalnych zmianach proszę zaktualizować bazę AIDE.
  • debsums: zmienione pliki binarne/biblioteki (poza /etc, poza /usr/share) — potencjalnie podmiana. Proszę sprawdzić pakiet: debsums PACKAGE_NAME, w razie wątpliwości zainstalować go ponownie (apt install --reinstall).
  • ClamAV / maldet: znaleziono zagrożenie — proszę sprawdzić plik w kwarantannie, nie otwierać go. Jeśli to webshell w katalogu witryny — proszę odizolować serwer i szukać punktu wejścia (podatna wtyczka, wyciek dostępów).
  • Falco: krytyczne zdarzenia (uruchomienie shella w kontenerze, dostęp do wrażliwych plików) — proszę przeanalizować zdarzenie: czyj proces, co uruchamiał. Często jest to legalna aktywność administratora.
  • Ekspozycja zewnętrzna: na czerwono baza danych/cache — proszę natychmiast zamknąć: przypiąć usługę do 127.0.0.1 lub zamknąć port w UFW. To realna luka.
  • SSL wygasa / wygasł — proszę odnowić certyfikat (Let's Encrypt odnawia się sam; jeśli nie — proszę sprawdzić certbot renew lub ustawienia w panelu).
  • Oczekują aktualizacje zabezpieczeń — proszę zainstalować: sudo apt update && sudo apt upgrade; po aktualizacji jądra proszę zrestartować serwer.
Oznaki realnego włamania (nieznane procesy/użytkownicy, zmienione pliki binarne, wychodzący spam, nieznane zadania cron): proszę odłączyć serwer od dostępu zewnętrznego, wykonać kopię zapasową do analizy, a jeśli dane są krytyczne — postawić czysty serwer z zaufanej kopii zapasowej; niezawodne usunięcie rootkita jest trudne.
Arcivéo - Security Monitor © 2026