- Krok 9 (tmux): tee -> tee -a (nie nadpisuj configu), dodano focus-events on, poprawiono nazwę sesji na "bootstrap" - Krok 10: struktura katalogów odzwierciedla stan faktyczny (/srv i /srv/infra już istnieją, brakuje apps i data) - Krok 12: Claude Code oznaczony jako wykonany 20-08-2026, instalator natywny bez Node.js - Nowy Krok 14: audyt po bootstrapie (SSH, ufw, fail2ban, unattended-upgrades, swap, Docker, porty, klucze) - HANDOFF.md: poprawiona numeracja sekcji 6
5.9 KiB
SECURITY.md — bezpieczeństwo serwera
Zasada porządkująca: serwer jest tak bezpieczny, jak jego najsłabsza wystawiona usługa. Utwardzony SSH nie ma znaczenia, jeśli obok stoi panel administracyjny bez hasła.
1. Warstwy
| Warstwa | Czym chronimy | Gdzie skonfigurowane |
|---|---|---|
| Dostęp do maszyny | SSH tylko na klucz, root wyłączony | /etc/ssh/sshd_config.d/99-hardening.conf |
| Sieć | ufw: deny incoming, allow 22/80/443 | ufw status verbose |
| Automatyczne ataki | fail2ban na sshd | /etc/fail2ban/jail.local |
| Aktualizacje | unattended-upgrades (security) | /etc/apt/apt.conf.d/50unattended-upgrades |
| Izolacja aplikacji | osobne sieci Dockera, brak publikowanych portów | compose każdego stacka |
| Transport | TLS z Let's Encrypt na wszystkim | Traefik |
| Sekrety | pliki .env, chmod 600, poza repo |
obok każdego stacka |
2. SSH
Docelowa konfiguracja:
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AllowUsers ubuntu
X11Forwarding no
MaxAuthTries 3
Reguła bezwzględna przy każdej zmianie w sshd: otwierasz drugą sesję SSH i sprawdzasz,
że logowanie działa, zanim zamkniesz pierwszą. Błąd w sshd_config przy zamkniętej
sesji oznacza odzyskiwanie dostępu przez konsolę KVM w panelu OVH.
Port zostawiamy na 22. Przenoszenie na 2222 to kosmetyka — odsiewa hałas w logach, ale nie zatrzymuje nikogo, kto celuje w konkretną maszynę. fail2ban robi tu realną robotę.
Klucze
- osobny klucz na każde urządzenie,
ed25519, z komentarzem identyfikującym sprzęt - klucz prywatny nigdy nie trafia na serwer ani do repo
- rejestr kluczy:
SERVER.md, sekcja 4 - przy zgubieniu urządzenia: usuwasz jego linię z
~/.ssh/authorized_keys, koniec
iOS: Termius lub Blink. Wchodzisz przez tmux attach -t claude do tej samej sesji,
którą zostawiłeś na Macu.
3. Sekrety
| Zasada | Dlaczego |
|---|---|
.env obok stacka, chmod 600, właściciel ubuntu |
inni użytkownicy systemu nie odczytają |
.env w .gitignore, w repo tylko .env.example |
sekret w historii gita zostaje tam na zawsze |
Hasła generowane, nie wymyślane — openssl rand -base64 32 |
brak ponownego użycia |
| Osobny sekret na usługę | wyciek jednego nie kompromituje reszty |
Jeśli sekret przypadkiem trafi do repo: nie wystarczy commit usuwający go. Trzeba go unieważnić i wygenerować nowy — historia gita pamięta, a jeśli poszła na mirror GitHuba, to jest już poza Twoją kontrolą.
4. Usługi administracyjne
Panel Traefika, bazy danych, narzędzia debugowe — nie wystawiamy publicznie. Dostęp przez tunel SSH:
ssh -L 8080:127.0.0.1:8080 ubuntu@dfkk.cloud
# potem localhost:8080 w przeglądarce
Jeśli coś musi być publiczne (np. status.dfkk.cloud, żeby działało z telefonu),
to za basic auth w Traefiku, z hasłem z generatora.
Gitea: rejestracja nowych użytkowników wyłączona natychmiast po instalacji. Otwarta rejestracja na publicznej instancji to zaproszenie dla botów, które w kilka dni zamienią ją w hosting spamu.
5. Aktualizacje
| Co | Jak | Kiedy |
|---|---|---|
| Poprawki bezpieczeństwa Ubuntu | unattended-upgrades, automatycznie |
codziennie |
| Reszta pakietów systemu | ręcznie, apt upgrade |
miesięczny przegląd |
| Obrazy Dockera | ręcznie, podniesienie tagu wersji w compose | miesięczny przegląd |
| Restart po aktualizacji kernela | ręcznie, po snapshocie | gdy /var/run/reboot-required |
Automatyczny restart po aktualizacji jest wyłączony. Nie chcemy, żeby maszyna sama się przeładowała w środku pracy albo w trakcie działania czegoś produkcyjnego.
Obrazy pinujemy do konkretnych wersji. latest oznacza, że najbliższy docker compose pull
może podmienić działającą aplikację na wersję z breaking changes — bez ostrzeżenia.
6. Co monitorujemy
| Sygnał | Próg | Reakcja |
|---|---|---|
| Zajętość dysku | 75% | sprzątanie wg 40-utrzymanie.md |
| Usługa nie odpowiada | 2 nieudane sprawdzenia | alert mailem |
| Certyfikat wygasa | < 14 dni | sprawdzić DNS-01 i klucze OVH |
| Nietypowe wpisy w logach SSH | — | przegląd przy miesięcznym audycie |
Alerty idą na k.kruszka@hotmail.com przez zewnętrzny SMTP.
Serwera pocztowego tu nie stawiamy — OVH blokuje port 25.
7. Podejrzenie włamania
Kolejność ma znaczenie. Nie restartuj i nie „posprzątaj" najpierw — zniszczysz ślady i stracisz możliwość ustalenia, czym weszli.
- Odetnij ruch:
ufw default deny incomingi zatrzymaj wystawione kontenery - Zrób snapshot OVH — to Twój materiał dowodowy
- Zbierz:
last,journalctl -u ssh,docker ps -a,crontab -ldla wszystkich użytkowników,ls -la /tmp /var/tmp, nietypowe procesy i połączenia (ss -tulpn) - Unieważnij wszystko: klucze SSH, tokeny API OVH, token GitHub, hasła w
.env - Oceń zakres — jeśli atakujący miał roota, maszyna jest spalona.
Postawienie od zera z repo
infra+ backup danych jest szybsze i pewniejsze niż czyszczenie. Dlatego repoinframusi być kompletne. - Dopiero potem: odbudowa, i wpis do
SERVER.mdco się stało
8. Braki, które trzeba domknąć
Uczciwa lista rzeczy, których jeszcze nie ma. Przeglądać przy miesięcznym audycie.
- Backup off-site (restic). Snapshot OVH to rollback, nie backup — jeden slot, ręczny, nadpisywany, w tej samej infrastrukturze. Do domknięcia zanim na serwerze pojawią się pierwsze prawdziwe dane.
- Test odtworzenia z backupu. Backup, którego nie odtworzyłeś, nie istnieje.
- Mirror repo
infrana GitHub. Bez tego awaria serwera zabiera kod, historię i konfigurację potrzebną do odtworzenia serwera — naraz. - 2FA na koncie OVH. Panel OVH może zrobić z maszyną wszystko, łącznie z reinstalacją. Jest w praktyce ważniejszy niż dostęp SSH.
- 2FA na koncie GitHub.