Bezpieczne wdrożenie Laravel to powtarzalny proces, w którym każda zmiana przechodzi przez te same etapy: kod trafia do repozytorium, automatyczne testy go sprawdzają, wersja jest publikowana na środowisku testowym, a na produkcję idzie przez przełączenie gotowego wydania z przygotowanym backupem i planem powrotu. Nawet dobrze napisany kod może zatrzymać sprzedaż, jeśli publikacja polega na ręcznym kopiowaniu plików i uruchamianiu migracji „na wyczucie”. Poniżej opisujemy, jak ułożyć taki proces w firmie, która na aplikacji Laravel prowadzi codzienną pracę – portal B2B, CRM, API dla partnerów czy sklep.
Środowiska: minimum trzy, każde z konkretną rolą
Podstawą jest rozdzielenie miejsc, w których kod powstaje, jest sprawdzany i działa dla klientów.
- Lokalne środowisko programisty – najlepiej w kontenerach (np. Docker lub Laravel Sail), z tą samą wersją PHP i bazy co produkcja. Różnica między PHP 8.3 lokalnie a starszą wersją na serwerze to klasyczne źródło błędów, które wychodzą dopiero po publikacji.
- Staging – kopia produkcji pod względem konfiguracji: te same usługi kolejek, cache, harmonogram zadań, podobny wolumen danych (zanonimizowanych). Tu biznes akceptuje zmiany i tu testuje się migracje na realnej strukturze bazy.
- Produkcja – środowisko, na które nikt nie wgrywa niczego ręcznie. Zmiany trafiają tam wyłącznie przez pipeline.
Konfigurację trzymamy w zmiennych środowiskowych, a nie w repozytorium. Plik `.env` produkcji nie powinien być dostępny dla każdego, kto ma dostęp do kodu – klucze API do ERP czy bramki płatności to dane, które warto przechowywać w menedżerze sekretów lub przynajmniej w zabezpieczonej konfiguracji serwera.
CI: co sprawdzać automatycznie przed każdym wydaniem
Pipeline ciągłej integracji uruchamia się przy każdym merge request. Nie musi być rozbudowany, żeby był skuteczny. Sensowny zestaw dla aplikacji firmowej:
- instalacja zależności z pliku `composer.lock` (nigdy `composer update` na etapie wdrożenia),
- analiza statyczna (np. PHPStan lub Larastan) i sprawdzenie stylu kodu,
- testy jednostkowe i funkcjonalne, w tym testy kluczowych ścieżek: logowanie, złożenie zamówienia, wyliczenie ceny, wysyłka do ERP,
- uruchomienie migracji na pustej bazie testowej, żeby wykryć błędy w kolejności,
- zbudowanie zasobów frontendu (Vite) i paczki wydania.
Jeśli którykolwiek krok się nie powiedzie, wydanie nie powstaje. To prosta zasada, która eliminuje większość wpadek typu „u mnie działało”.
Migracje bez przestoju: wzorzec expand–contract
Najbardziej ryzykowną częścią wdrożenia jest zmiana schematu bazy. Aplikacja przez chwilę działa w dwóch wersjach: stare procesy (workery kolejek, trwające żądania) korzystają z poprzedniego kodu, a nowe już z nowego. Dlatego migracje planujemy w dwóch krokach.
- Expand (rozszerzenie) – dodajemy nową kolumnę lub tabelę, nie usuwając starej. Nowa kolumna jest nullable albo ma wartość domyślną. Kod zapisuje dane w obu miejscach.
- Migracja danych – przepisanie istniejących rekordów robimy w jobie kolejki, porcjami, a nie w jednej migracji, która zablokuje dużą tabelę na kilka minut.
- Contract (zwężenie) – dopiero w kolejnym wydaniu, gdy nic już nie korzysta ze starej kolumny, usuwamy ją.
Przykład: zmiana pola `price` na osobne `net_price` i `gross_price`. Pierwsze wydanie dodaje nowe pola i zapisuje wszystkie trzy, job uzupełnia historię, drugie wydanie przełącza odczyt, trzecie usuwa stare pole. Każdy z tych kroków można wycofać, cofając kod – bez dotykania bazy.
Unikamy też operacji, które na dużych tabelach blokują zapis: zmiany typu kolumny, dodawania indeksu bez sprawdzenia, jak zachowa się konkretna wersja MySQL czy PostgreSQL, i zmiany nazw kolumn używanych przez działające procesy.
Feature flags: oddzielenie wdrożenia od włączenia
Wdrożenie kodu nie musi oznaczać, że klienci od razu zobaczą zmianę. Flagi funkcji pozwalają opublikować nowy moduł wyłączony, włączyć go dla zespołu wewnętrznego, potem dla kilku zaufanych kont, a na końcu dla wszystkich. W Laravel można do tego użyć pakietu Laravel Pennant albo prostej tabeli z ustawieniami.
Kiedy flagi mają największy sens:
- zmiana w koszyku, wyliczaniu cen lub procesie składania zamówień,
- nowa integracja, która zaczyna wysyłać dane do systemu zewnętrznego,
- przebudowa ekranu, z którego codziennie korzysta dział obsługi.
Flagi trzeba sprzątać. Po pełnym włączeniu funkcji usuwamy warunek z kodu, inaczej po roku aplikacja ma kilkadziesiąt martwych przełączników.
Sam deploy: wydanie jako całość, nie zestaw plików
Bezpieczny deploy przygotowuje nowe wydanie w osobnym katalogu, a potem jednym ruchem przełącza na nie aplikację. Tak działają narzędzia typu Deployer czy Envoyer, podobnie można to zbudować w pipeline. Typowa kolejność:
- utworzenie katalogu nowego wydania i rozpakowanie paczki z CI,
- podpięcie współdzielonych zasobów: `storage`, pliku konfiguracji, katalogu z uploadami,
- wykonanie backupu bazy (lub potwierdzenie, że automatyczna kopia z ostatnich minut jest dostępna),
- `php artisan migrate --force` – tylko migracje zgodne wstecz,
- zbudowanie cache: `php artisan optimize` (konfiguracja, trasy, widoki, zdarzenia),
- przełączenie dowiązania symbolicznego na nowe wydanie i przeładowanie PHP-FPM,
- restart workerów: `php artisan queue:restart` lub `php artisan horizon:terminate`,
- szybki test dymny: strona logowania, kluczowy endpoint API, podgląd kolejki.
Pamiętajmy o harmonogramie zadań. Jeśli w trakcie wdrożenia uruchamia się nocny import cennika, może trafić na niespójny stan. Długie zadania cykliczne warto chronić blokadą `withoutOverlapping()` i nie planować deployu na godziny, w których działają.
Backup i rollback: przećwiczone, nie tylko zapisane
Plan powrotu składa się z dwóch części. Rollback kodu to przełączenie dowiązania na poprzednie wydanie – kilka sekund, pod warunkiem że migracje były zgodne wstecz. Przywrócenie danych to ostateczność, bo oznacza utratę zamówień złożonych po backupie. Dlatego ważniejsze od samej kopii jest to, żeby rzadko jej potrzebować.
Kopie zapasowe mają sens tylko wtedy, gdy ktoś sprawdził, że da się je odtworzyć. Raz na jakiś czas warto odtworzyć backup na osobnym serwerze i zmierzyć, ile to trwa – to realny czas niedostępności w najgorszym scenariuszu.
Monitoring po publikacji
Pierwsza godzina po wdrożeniu to czas obserwacji. Patrzymy na:
- liczbę wyjątków w narzędziu do raportowania błędów w porównaniu z okresem sprzed wdrożenia,
- długość kolejek i liczbę nieudanych jobów (Horizon pokazuje to od razu),
- czasy odpowiedzi kluczowych endpointów,
- logi integracji – czy ERP i systemy partnerów przyjmują dane.
Jeśli integracje są dla firmy krytyczne, warto opisać, jak zbudowane są kolejki, ponowienia i idempotencja – piszemy o tym w artykule Integracje API Laravel z ERP i B2B.
Checklista release
Przed każdym wydaniem na produkcję:
- wszystkie kroki CI zakończone sukcesem, wersja zaakceptowana na stagingu,
- lista zmian i osoba odpowiedzialna za wydanie znana zespołowi,
- migracje sprawdzone pod kątem zgodności wstecz i czasu wykonania na dużych tabelach,
- nowe funkcje procesowe schowane za flagą,
- backup potwierdzony, poprzednie wydanie dostępne do przełączenia,
- termin poza godzinami importów, szczytu zamówień i zamknięcia miesiąca,
- po wydaniu: restart workerów, test dymny, obserwacja błędów i kolejek.
Typowe błędy
- Wdrożenie w piątek po południu bez nikogo dostępnego wieczorem.
- Nieaktualne zależności – aplikacja na PHP 8.1 (bez wsparcia bezpieczeństwa od końca 2025 roku) albo Laravel sprzed kilku wersji utrudnia bezpieczne publikowanie poprawek. Jeśli system dojrzał do aktualizacji, zobacz, jak podejść do tego etapami w tekście o modernizacji legacy PHP bez zatrzymywania firmy.
- Zapomniane workery działające na starym kodzie po deployu.
- Ręczne poprawki na produkcji, których nie ma w repozytorium i które znikają przy kolejnym wydaniu.
Następny krok
Spisz, jak dziś wygląda publikacja zmian w Twojej aplikacji: kto ją wykonuje, jakie komendy, gdzie jest backup i jak długo trwa powrót. Jeśli większość odpowiedzi brzmi „to zależy”, warto uporządkować proces, zanim kolejna zmiana trafi na produkcję. Pomagamy w tym jako software house Laravel – od konfiguracji CI po przejęcie utrzymania. Skontaktuj się z nami, a zaczniemy od przeglądu obecnego procesu wdrożeń.
Najczęstsze pytania
Czy każde wdrożenie Laravel wymaga trybu maintenance?
Nie. Przy wdrożeniu przez katalogi wydań i przełączenie dowiązania symbolicznego oraz migracjach zgodnych wstecz większość zmian publikuje się bez przerwy. Tryb maintenance zostawia się na rzadkie operacje, których nie da się rozbić na etapy.
Jak wycofać migrację bazy, która już poszła na produkcję?
Najbezpieczniej nie polegać na metodzie down, tylko projektować migracje tak, żeby stara wersja kodu działała na nowym schemacie. Wtedy rollback oznacza powrót do poprzedniego wydania kodu, a porządki w bazie robi się osobną migracją później.
Czy feature flags mają sens w małym zespole?
Tak, jeśli zmiana dotyczy procesu, z którego klienci korzystają codziennie, np. koszyka albo składania zamówień. Flaga pozwala wdrożyć kod wcześniej, włączyć go dla wybranych kont i wyłączyć bez nowego deployu.
Co zrobić z kolejkami podczas wdrożenia?
Po przełączeniu wydania trzeba zrestartować workery, np. poleceniem queue:restart albo horizon:terminate, żeby nie wykonywały zadań starym kodem. Warto też pilnować, by nowe zadania umiały obsłużyć dane zapisane przez starą wersję.
Jak przełożyć ten temat na projekt
W JiraSoft patrzymy na takie zagadnienia przez pryzmat realnego systemu: danych, backendu, integracji API, procesów B2B, widoczności w Google oraz przygotowania treści pod odpowiedzi AI. Dlatego artykuł jest punktem wyjścia do rozmowy o konkretnym workflow, a nie tylko ogólną notatką technologiczną.
