Przejdź do głównej zawartości

Serwer VPS — pierwsze uruchomienie (faza 0)

Dokument prowadzi przez przygotowanie serwera Hostinger KVM 8 pod aplikację po migracji z Cloudflare (plan: docs/plans/migracja-vps-sqlite-coolify.md, pkt 4.13, 7 i „Faza 0”). Część serwerowa jest zautomatyzowana skryptem deploy/bootstrap-vps.sh; reszta to kliknięcia w hPanelu, Coolify i Cloudflare Zero Trust, opisane krok po kroku.

👤 Instrukcja krok po kroku​

1. hPanel Hostingera (przed pierwszym logowaniem)​

  1. System: Ubuntu 24.04 LTS (szablon czysty, bez preinstalowanego Coolify — instaluje go skrypt, dzięki czemu wersja i konfiguracja są powtarzalne).
  2. Klucz SSH: VPS → Settings → SSH keys → Add SSH key. Na swoim komputerze:
    ssh-keygen -t ed25519 -C "imie@acepark.pl"
    cat ~/.ssh/id_ed25519.pub
    Wklej zawartość pliku .pub i zaznacz instalację na tym VPS. Sprawdź: ssh root@<IP> wchodzi bez hasła.
  3. Firewall hPanel (VPS → Firewall) — opcjonalny, warstwa dodatkowa: reguła Accept TCP 22 z Twojego adresu IP i nic więcej. Porty 80/443/8000 nie mogą być otwarte na świat, ale samego hPanela nie trzeba używać: skrypt zamyka je na maszynie regułą w łańcuchu DOCKER-USER (patrz „Firewall” niżej). Reguła hPanel z allowlistą IP ma sens tylko przy stałym adresie — przy dynamicznym odetnie Cię przy pierwszej zmianie IP.
  4. Backupy: włącz dzienny backup VPS (dodatek do planu) — obejmie konfigurację Coolify, GlitchTip i wolumeny.

2. Skrypt bootstrap (jedno polecenie jako root)​

ssh root@<IP>
apt-get install -y git
git clone --depth 1 --branch develop https://github.com/DMT-Softwares/Acepark_Rezerwacje.git /root/acepark
cd /root/acepark
DEPLOY_USER=deploy \
SSH_PUBLIC_KEY="ssh-ed25519 AAAA... imie@acepark.pl" \
ADMIN_IPS="<Twoje IP>" \
./deploy/bootstrap-vps.sh

Skrypt trwa 5–10 minut (instalator Coolify pobiera obrazy). Na końcu wypisuje dalsze kroki. Można go uruchamiać wielokrotnie — każdy krok sprawdza swój stan.

Co robi:

KrokEfekt
Pakietyapt upgrade, ufw, fail2ban, unattended-upgrades, curl, git, jq, sqlite3, htop
Strefa czasuhost w UTC (kontenery też, TZ=UTC — cały kod dat używa date-fns-tz)
Użytkownik deploysudo bez hasła, klucz z SSH_PUBLIC_KEY (ten sam klucz zostaje u roota — Coolify zarządza hostem przez SSH roota z własnym kluczem)
sshdtylko klucze, PermitRootLogin prohibit-password, 4 próby, keepalive
ufwdeny incoming, allow outgoing, 22 tylko z ADMIN_IPS (bez listy: 22 z limitem prób)
fail2banjail sshd: 5 prób / 10 min → ban na 1 h
Aktualizacjeautomatyczne poprawki bezpieczeństwa, bez automatycznego restartu
Wolumeny/data/acepark/{dev,qa,prod} i …/backups, właściciel uid 1000 (użytkownik node w obrazie aplikacji)
Coolifyoficjalny instalator (cdn.coollabs.io/coolify/install.sh) — instaluje Dockera i podnosi Coolify na localhost:8000; pomijany, gdy już działa
cloudflared na hościetylko gdy podasz CLOUDFLARE_TUNNEL_TOKEN — usługa systemd; docelowo to ten tunel obsługuje cały ruch (konfiguracja w /etc/cloudflared/config.yml), nie kontener w Coolify — patrz docs/infrastruktura-vps.md

3. Coolify — pierwsze logowanie i ustawienia​

  1. Panel nie jest wystawiony na świat. Zaloguj się przez tunel SSH:
    ssh -L 8000:localhost:8000 deploy@<IP>
    i otwórz http://localhost:8000. Załóż konto administratora (pierwsze konto jest właścicielem instancji).
  2. Settings → Instance: nazwa acepark-vps, 2FA dla konta administratora, Concurrent builds = 1 (build na tym samym hoście co produkcja, pkt 7).
  3. Sources → GitHub App: utwórz aplikację GitHub dla organizacji DMT-Softwares z dostępem do Acepark_Rezerwacje (deploy na push, preview deployments).
  4. Servers → localhost → Proxy: zostaw Traefik. Certyfikaty Let's Encrypt nie są potrzebne — TLS kończy się w Cloudflare (pkt 4.13).

4. Cloudflare Tunnel i Access​

  1. Zero Trust → Networks → Tunnels → Create tunnel (acepark-vps, typ Cloudflared). Skopiuj token.
  2. W Coolify: Projects → acepark-infra → Add resource → Cloudflared (szablon usługi), wklej token jako sekret TUNNEL_TOKEN, sieć: ta sama co coolify-proxy. Deploy.
  3. W tunelu dodaj hostname'y (Zero Trust tworzy rekordy CNAME sam):
    • coolify.acepark.pl → http://coolify:8000, polityka Access: SSO Google, tylko wskazane konta;
    • dev.acepark.pl, qa.acepark.pl, qa-panel.acepark.pl, klient.acepark.pl, panel.acepark.pl → http://coolify-proxy:80 (Access opcjonalnie dla dev);
    • glitchtip.acepark.pl i hc.acepark.pl → http://coolify-proxy:80, Access z bypassem dla /api/* (GlitchTip) i /ping/* (Healthchecks).
  4. Cloudflare → SSL/TLS: tryb Full (nie „Full (strict)”). Domeny w Coolify wpisuj jako https://… — inaczej pętla przekierowań.
  5. Od tej chwili panel Coolify jest dostępny pod https://coolify.acepark.pl za Access; tunel SSH z kroku 3 zostaje jako droga awaryjna.

5. GlitchTip i Healthchecks​

  1. Add resource → GlitchTip (szablon): domena https://glitchtip.acepark.pl, SMTP SendGrid (EMAIL_URL=smtp://apikey:<klucz>@smtp.sendgrid.net:587), GLITCHTIP_DOMAIN, rejestracja zamknięta. Projekt acepark z osobnymi środowiskami; DSN do zmiennych aplikacji w fazie 3.
  2. Add resource → Healthchecks (szablon): https://hc.acepark.pl, SMTP jak wyżej, projekt per środowisko; PING_KEY każdego projektu trafi do HEALTHCHECKS_PING_URL kontenera cron (http://healthchecks-<uuid>:8000/ping/<PING_KEY> — siecią Dockera, patrz infrastruktura-vps.md), klucz API do HEALTHCHECKS_API_KEY, a HEALTHCHECKS_API_URL to baza http://healthchecks-<uuid>:8000 (dla node dist/cron.js list --sync-healthchecks; przez hc.acepark.pl API jest za Access).

6. Backupy poza hostem​

  1. Cloudflare R2: bucket acepark-backups, token API z dostępem tylko do tego bucketu.
  2. Coolify: Settings → Backup (instance backup → S3/R2, codziennie) oraz backup bazy GlitchTip i Healthchecks (zasób → Backups → S3).
  3. Litestream dla acepark.db konfigurowany w fazie 3 (Compose każdego środowiska), z tym samym bucketem i prefiksem per środowisko.

7. Lista kontrolna po bootstrapie​

  • ssh deploy@<IP> działa, ssh root@<IP> działa kluczem, hasło odrzucane.
  • sudo ufw status pokazuje tylko port 22; sudo iptables -L DOCKER-USER -n pokazuje RETURN dla ESTABLISHED,RELATED i DROP.
  • docker ps pokazuje coolify, coolify-db, coolify-redis, coolify-proxy.
  • https://coolify.acepark.pl przechodzi przez Access, http://<IP>:8000 nie odpowiada.
  • ls -la /data/acepark — trzy katalogi środowisk z właścicielem uid 1000.
  • GlitchTip i Healthchecks odpowiadają przez tunel; testowy ping curl https://hc.acepark.pl/ping/<PING_KEY>/test?create=1 tworzy check.

🛠 Dokumentacja techniczna​

Dlaczego skrypt, a nie szablon „Coolify” z hPanelu​

Szablon Hostingera instaluje Coolify na obrazie, którego wersji i ustawień nie kontrolujemy (użytkownik, firewall, sshd). Skrypt w repozytorium jest przeglądany jak kod, wersjonowany i powtarzalny — ten sam bootstrap zadziała na innym dostawcy, co było jednym z założeń wyboru jednego serwera (łatwa przeprowadzka po migracji).

Firewall: ufw, DOCKER-USER i hPanel​

ufw chroni sam host (SSH). Docker wpina własne reguły iptables przed łańcuchem, którym rządzi ufw, więc port opublikowany przez kontener (80/443 Traefika, 8000 panelu Coolify) jest osiągalny z internetu mimo deny incoming.

Skrypt zamyka to na maszynie: wstawia do łańcucha DOCKER-USER regułę odrzucającą ruch przychodzący z interfejsu zewnętrznego (przepuszczając połączenia zestawione), a docker-firewall.service nakłada ją ponownie po każdym starcie Dockera — Docker przebudowuje swoje łańcuchy przy starcie i inaczej reguła by znikała. Weryfikacja: iptables -L DOCKER-USER -n pokazuje RETURN dla ESTABLISHED,RELATED i DROP poniżej.

Firewall hPanel jest wobec tego warstwą dodatkową, a nie warunkiem koniecznym. Ruch do aplikacji wchodzi wyłącznie tunelem, który jest połączeniem wychodzącym z serwera.

Dostęp roota​

Coolify zarządza „localhost” przez SSH jako root z kluczem, który sam generuje i dopisuje do /root/.ssh/authorized_keys. Stąd PermitRootLogin prohibit-password zamiast no. Logowanie hasłem jest wyłączone globalnie.

Idempotencja​

Każdy krok sprawdza stan: użytkownik tworzony tylko gdy nie istnieje, klucz dopisywany tylko gdy go nie ma, ufw --force reset odtwarza reguły od zera, instalator Coolify jest pomijany, gdy kontener coolify już działa, cloudflared instalowany tylko bez binarki. Ponowne uruchomienie po przerwanym kroku jest bezpieczne.

Co skrypt celowo pomija​

  • Konfigurację Coolify (konta, GitHub App, zasoby) — to stan w bazie Coolify, robiony przez UI lub API (https://coolify.acepark.pl/api/v1, token z Keys & Tokens).
  • Tunel aplikacji — jako usługa w Coolify, żeby restart i logi były w jednym miejscu z resztą zasobów.
  • Litestream i Compose środowisk — faza 3 planu (Dockerfile, docker-compose.yml, litestream.yml).