Dziś zrobimy kolejny krok i zaimplementujemy solidną strategię wdrażania bez przestojów (Zero Downtime Deployment, ZDD) przy użyciu GitHub Actions. To podejście zapewnia, że Twoja aplikacja pozostaje dostępna dla użytkowników nawet podczas wdrożeń.
📋 Spis treści
- Czym jest wdrażanie bez przestojów?
- Dlaczego GitHub Actions do wdrażania?
- Wymagania wstępne
- Konfiguracja serwera
- Utworzenie użytkownika wdrożeniowego
- Instalacja wymaganych pakietów
- Konfiguracja Nginx
- Konfiguracja PHP-FPM
- Konfiguracja PHP
- Konfiguracja struktury katalogów
- Konfiguracja klucza SSH dla GitHub Actions
- Konfiguracja Supervisora
- Dodanie sekretów GitHub
- Utworzenie workflow GitHub Actions
- Skrypt wdrożeniowy
- Konfiguracja SSL z Let's Encrypt
- Zagadnienia bezpieczeństwa
- Rozwiązywanie problemów
- Podsumowanie
- Kod źródłowy
Czym jest wdrażanie bez przestojów?
Wdrażanie bez przestojów (Zero Downtime Deployment, ZDD) to strategia wdrażania, która zapewnia, że Twoja aplikacja pozostaje dostępna dla użytkowników przez cały proces wdrażania. W przeciwieństwie do tradycyjnych wdrożeń, gdzie aplikacja jest całkowicie niedostępna podczas aktualizacji, ZDD utrzymuje ciągłość usługi poprzez:
- Wdrażanie nowej wersji podczas gdy stara wersja nadal działa
- Testowanie nowej wersji przed przekierowaniem do niej ruchu
- Stopniowe przenoszenie ruchu ze starej wersji do nowej
- Utrzymywanie starej wersji jako kopii zapasowej w przypadku problemów
To podejście minimalizuje ryzyko przerwania usługi i zapewnia płynne doświadczenie dla Twoich użytkowników.
Dlaczego GitHub Actions do wdrażania?
GitHub Actions oferuje kilka zalet przy implementacji ZDD:
- Integracja z GitHub: Bezproblemowa integracja z Twoim repozytorium kodu
- Automatyzacja workflow: Definiowanie procesów wdrażania jako kod
- Sekrety środowiskowe: Bezpieczne przechowywanie wrażliwych danych uwierzytelniających
- Budowanie macierzowe: Testowanie w wielu środowiskach jednocześnie
- Zarządzanie artefaktami: Przechowywanie i pobieranie artefaktów budowania między zadaniami
- Akcje społeczności: Wykorzystanie gotowych akcji do typowych zadań wdrażania
Wymagania wstępne
Przed implementacją ZDD z GitHub Actions, upewnij się, że masz:
- Repozytorium GitHub: Hostujące Twoją aplikację Laravel
- Serwer VPS: Działający na Ubuntu/Debian (w tym przewodniku użyjemy Ubuntu)
- Dostęp SSH: Do Twojego serwera VPS
- Nazwa domeny: Wskazująca na adres IP Twojego serwera
- Certyfikat SSL: Dla bezpiecznych połączeń HTTPS (zalecany Let's Encrypt)
Konfiguracja serwera
1. Utworzenie użytkownika wdrożeniowego
Najpierw utwórz dedykowanego użytkownika do wdrożeń:
# Utwórz nowego użytkownika
sudo adduser deployer
sudo usermod -aG www-data deployer
# Dodaj uprawnienia dla użytkownika deployer
sudo bash -c 'cat > /etc/sudoers.d/deployer <<EOF
deployer ALL=(ALL) NOPASSWD:/usr/bin/chmod, /usr/bin/chown
deployer ALL=(ALL) NOPASSWD:/usr/bin/systemctl restart php8.3-fpm
deployer ALL=(ALL) NOPASSWD:/usr/bin/systemctl restart nginx
deployer ALL=(ALL) NOPASSWD:/usr/bin/systemctl reload nginx
deployer ALL=(ALL) NOPASSWD:/usr/bin/supervisorctl restart all
EOF'
# Ustaw uprawnienia
sudo chmod 440 /etc/sudoers.d/deployer
sudo visudo -c
# Sprawdzanie uprawnień
sudo -U deployer -l
2. Instalacja wymaganych pakietów
2.1 Instalacja niezbędnych pakietów oprogramowania:
# Aktualizacja systemu
sudo apt update
sudo apt install nginx php-fpm mariadb-server ufw fail2ban acl supervisor redis-server
sudo apt install php8.3-cli php8.3-common php8.3-curl php8.3-xml php8.3-mbstring php8.3-zip php8.3-mysql php8.3-gd php8.3-intl php8.3-bcmath php8.3-redis php8.3-imagick php8.3-pgsql php8.3-sqlite3 php8.3-tokenizer php8.3-dom php8.3-fileinfo php8.3-iconv php8.3-simplexml php8.3-opcache
2.2 Instalacja Node + PM2 dla SSR (opcjonalnie, jako deployer)
# Pobierz i zainstaluj nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
# bez restartowania powłoki
\. "$HOME/.nvm/nvm.sh"
# Pobierz i zainstaluj Node.js:
nvm install 22
# Zainstaluj PM2
npm install -g pm2
# Skonfiguruj PM2
pm2 startup
pm2 save --force
3. Konfiguracja Nginx
Utwórz nowy plik konfiguracyjny Nginx:
sudo nano /etc/nginx/sites-available/laravel
Dodaj następującą konfigurację:
server {
listen 80;
listen [::]:80;
server_name __;
root /home/deployer/laravel/current/public;
index index.php;
access_log /home/deployer/laravel/shared/storage/logs/nginx_access.log;
error_log /home/deployer/laravel/shared/storage/logs/nginx_error.log;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin-when-cross-origin";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Permissions-Policy "geolocation=(), midi=(), sync-xhr=(), microphone=(), camera=(), magnetometer=(), gyroscope=(), fullscreen=(self), payment=()";
server_tokens off;
charset utf-8;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
client_max_body_size 100M;
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot|webp)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
log_not_found off;
try_files $uri =404;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ ^/index\.php(/|$) {
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_read_timeout 300;
fastcgi_hide_header X-Powered-By;
}
location ~ /\.(?!well-known).* {
deny all;
access_log off;
log_not_found off;
}
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;
gzip_min_length 1024;
gzip_buffers 16 8k;
gzip_disable "MSIE [1-6]\.";
}
Włącz stronę:
sudo ln -s /etc/nginx/sites-available/laravel /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
4. Konfiguracja PHP-FPM
Zaktualizuj konfigurację PHP-FPM:
sudo nano /etc/php/8.3/fpm/pool.d/www.conf
Dodaj następującą konfigurację:
[www]
user = deployer
group = www-data
listen = /var/run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 8
pm.process_idle_timeout = 10s
pm.max_requests = 500
access.log = /home/deployer/laravel/shared/storage/logs/php-fpm-access.log
slowlog = /home/deployer/laravel/shared/storage/logs/php-fpm-slow.log
php_admin_value[error_log] = /home/deployer/laravel/shared/storage/logs/php-fpm-error.log
php_admin_flag[log_errors] = on
php_admin_value[open_basedir] = /home/deployer/laravel/current/:/home/deployer/laravel/releases/:/home/deployer/laravel/shared/:/tmp/:/var/lib/php/sessions/
php_admin_value[disable_functions] = "exec,passthru,shell_exec,system,proc_open,popen"
php_admin_flag[expose_php] = off
php_admin_value[memory_limit] = 256M
php_admin_value[max_execution_time] = 120
php_admin_value[realpath_cache_size] = 4096K
php_admin_value[realpath_cache_ttl] = 600
php_admin_value[opcache.enable] = 1
php_admin_value[opcache.memory_consumption] = 128
Restart serwera PHP-FPM
sudo php-fpm8.3 -t
sudo systemctl restart php8.3-fpm
5. Konfiguracja PHP
Zaktualizuj konfigurację PHP:
sudo nano /etc/php/8.3/fpm/php.ini
Dodaj następującą konfigurację:
[PHP]
expose_php = Off
max_execution_time = 30
max_input_time = 60
memory_limit = 256M
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /var/log/php8.3-fpm.log
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=32
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
opcache.enable_cli=0
opcache.jit_buffer_size=256M
opcache.jit=1235
realpath_cache_size=4096K
realpath_cache_ttl=600
session.gc_probability=1
session.gc_divisor=100
session.gc_maxlifetime=1440
6. Konfiguracja struktury katalogów
Utwórz strukturę katalogów dla wdrożeń:
# Utwórz strukturę z odpowiednimi uprawnieniami
sudo mkdir -p /home/deployer/laravel/{releases,shared}
sudo chown -R deployer:www-data /home/deployer/laravel
sudo chmod 755 /home/deployer
# Konfiguracja folderów współdzielonych
sudo mkdir -p /home/deployer/laravel/shared/storage/{app,framework,logs}
sudo mkdir -p /home/deployer/laravel/shared/storage/framework/{cache,sessions,views}
sudo mkdir -p /home/deployer/laravel/shared/public
sudo chmod -R 775 /home/deployer/laravel/shared
sudo chmod -R 775 /home/deployer/laravel/shared/storage
sudo chown -R deployer:www-data /home/deployer/laravel
# Ustaw ACL dla przyszłych plików
sudo setfacl -Rdm g:www-data:rwx /home/deployer/laravel
7. Konfiguracja klucza SSH dla GitHub Actions (jako użytkownik deployer)
# Utwórz katalog SSH
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# Wygeneruj klucz SSH
ssh-keygen -t rsa -b 4096 -C "github-actions-deploy"
# Dodaj klucz publiczny do authorized_keys
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
# Wyświetl klucz prywatny
cat ~/.ssh/id_rsa
8. Konfiguracja Supervisora
# Utwórz plik konfiguracyjny Supervisora
sudo nano /etc/supervisor/conf.d/laravel.conf
[program:laravel-worker]
command=/usr/bin/php /home/deployer/laravel/current/artisan queue:work --timeout=3600 --tries=3 --sleep=3 --stop-when-empty
autostart=true
autorestart=true
user=deployer
numprocs=1
stdout_logfile=/home/deployer/laravel/shared/storage/logs/laravel-worker.log
stderr_logfile=/home/deployer/laravel/shared/storage/logs/laravel-worker.log
# Zaktualizuj główny plik konfiguracyjny Supervisora
sudo nano /etc/supervisor/supervisord.conf
; supervisor config file
[unix_http_server]
file=/var/run/supervisor.sock ; (the path to the socket file)
chmod=0700 ; sockef file mode (default 0700)
[supervisord]
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP)
; the below section must remain in the config file for RPC
; (supervisorctl/web interface) to work, additional interfaces may be
; added by defining them in separate rpcinterface: sections
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket
; The [include] section can just contain the "files" setting. This
; setting can list multiple files (separated by whitespace or
; newlines). It can also contain wildcards. The filenames are
; interpreted as relative to this file. Included files *cannot*
; include files themselves.
[include]
files = /etc/supervisor/conf.d/*.con
# Uruchom Supervisora
sudo supervisorctl start all
# Użyteczne polecenia
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl restart all
sudo supervisorctl status
9. Dodanie sekretów GitHub
Dodaj następujące sekrety do swojego repozytorium GitHub:
SSH_HOST
: Adres IP lub domena Twojego serwera VPSSSH_USER
: Nazwa użytkownika na VPSSSH_KEY
: Prywatny klucz SSH wygenerowany powyżejSSH_PORT
: Port SSH (domyślnie 22)
Dodaj zmienną dla pliku .env produkcyjnego
ENV_FILE
: Zawartość Twojego pliku .env
10. Utworzenie workflow GitHub Actions
Utwórz nowy plik .github/workflows/workflow.yml
w swoim repozytorium:
name: Wdrażanie bez przestojów
on:
push:
branches:
- main
jobs:
test:
name: 🧪 Testy i Lint
runs-on: ubuntu-latest
steps:
- name: Pobierz kod
uses: actions/checkout@v4
- name: Konfiguracja PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, dom, fileinfo, sqlite3, zip, gd, intl, redis, imagick
coverage: xdebug
tools: composer:v2
- name: Konfiguracja Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- name: Kopiuj .env.testing
run: cp .env.testing .env
- name: Pobierz katalog cache Composera
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache zależności Composera
uses: actions/cache@v4
with:
path: |
vendor
${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Instalacja zależności Composera
run: composer install --prefer-dist --no-progress
- name: Instalacja zależności NPM
run: npm ci
- name: Budowanie zasobów dla testów
run: npm run build
- name: Generowanie konfiguracji Ziggy dla testów
run: php artisan ziggy:generate
- name: Uruchomienie sprawdzeń jakości kodu
run: |
composer larastan
composer pint
npm run format
npm run types
npm run lint
- name: Uruchomienie testów (z Pest)
env:
DB_CONNECTION: sqlite
DB_DATABASE: ':memory:'
SESSION_DRIVER: array
run: ./vendor/bin/pest
build:
name: 🏗️ Budowanie wydania
needs: test
runs-on: ubuntu-latest
steps:
- name: Pobierz kod
uses: actions/checkout@v4
- name: Utwórz plik .env z zmiennych GitHub
run: |
echo "${{ vars.ENV_FILE }}" > .env
- name: Konfiguracja PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, dom, fileinfo, sqlite3, zip, gd, intl, redis, imagick
tools: composer:v2
- name: Instalacja zależności Composera
run: composer install --optimize-autoloader --no-dev --prefer-dist --no-interaction --no-progress
- name: Generowanie konfiguracji Ziggy
run: php artisan ziggy:generate
- name: Konfiguracja Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- name: Instalacja zależności NPM
run: npm ci
- name: Instalacja dotenv-cli
run: npm install -g dotenv-cli
- name: Budowanie zasobów i SSR
run: dotenv -e .env -- npm run build:ssr
- name: Tworzenie archiwum wydania
run: |
mkdir release
shopt -s extglob
cp -r !(release|.git|tests|node_modules|release.tar.gz) release/
tar -czf release.tar.gz -C release .
rm -rf release
- name: Przesłanie artefaktu wydania
uses: actions/upload-artifact@v4
with:
name: release
path: release.tar.gz
deploy:
name: 🚀 Wdrożenie na serwer
needs: build
runs-on: ubuntu-latest
steps:
- name: Pobierz kod
uses: actions/checkout@v4
- name: Konfiguracja klucza SSH
uses: webfactory/[email protected]
with:
ssh-private-key: ${{ secrets.SSH_KEY }}
- name: Konfiguracja known_hosts
run: |
mkdir -p ~/.ssh
ssh-keyscan -p ${{ secrets.SSH_PORT }} ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
- name: Pobierz artefakt wydania
uses: actions/download-artifact@v4
with:
name: release
path: .
- name: Utwórz plik .env z zmiennych GitHub
run: |
echo "${{ vars.ENV_FILE }}" > .env
- name: Prześlij wydanie na serwer
run: |
scp -vvv -P ${{ secrets.SSH_PORT }} release.tar.gz ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:/home/${{ secrets.SSH_USER }}/laravel/
- name: Prześlij plik .env do katalogu współdzielonego
run: |
scp -P ${{ secrets.SSH_PORT }} .env ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:/home/${{ secrets.SSH_USER }}/laravel/shared/.env
- name: Uruchom skrypt wdrożeniowy na serwerze
run: |
ssh -p ${{ secrets.SSH_PORT }} ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} 'bash -s' < ./deploy.sh
11. Skrypt wdrożeniowy (deploy.sh)
#!/bin/bash
set -e
set -o pipefail
APP_USER="deployer"
APP_GROUP="www-data"
APP_BASE="/home/$APP_USER/laravel"
RELEASES_DIR="$APP_BASE/releases"
SHARED_DIR="$APP_BASE/shared"
CURRENT_LINK="$APP_BASE/current"
NOW=$(date +%Y-%m-%d-%H%M%S)-$(openssl rand -hex 3)
RELEASE_DIR="$RELEASES_DIR/$NOW"
ARCHIVE_NAME="release.tar.gz"
# Load NVM and get current Node.js version
export NVM_DIR="/home/$APP_USER/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
NODE_VERSION=$(nvm current)
PM2="$NVM_DIR/versions/node/$NODE_VERSION/bin/pm2"
echo "▶️ Using Node.js version: $NODE_VERSION"
echo "▶️ PM2 path: $PM2"
# Verify PM2 exists
if [ ! -f "$PM2" ]; then
echo "❌ PM2 not found at $PM2"
exit 1
fi
echo "▶️ Create directories..."
mkdir -p "$RELEASES_DIR" "$SHARED_DIR/storage" "$SHARED_DIR/bootstrap_cache"
mkdir -p "$SHARED_DIR/storage/framework/"{views,cache,sessions}
mkdir -p "$SHARED_DIR/storage/logs"
echo "▶️ Unpacking release..."
mkdir -p "$RELEASE_DIR"
tar -xzf "$APP_BASE/$ARCHIVE_NAME" -C "$RELEASE_DIR"
rm -f "$APP_BASE/$ARCHIVE_NAME"
echo "▶️ Setting up symlinks..."
rm -rf "$RELEASE_DIR/storage"
ln -s "$SHARED_DIR/storage" "$RELEASE_DIR/storage"
rm -rf "$RELEASE_DIR/bootstrap/cache"
ln -s "$SHARED_DIR/bootstrap_cache" "$RELEASE_DIR/bootstrap/cache"
ln -sf "$SHARED_DIR/.env" "$RELEASE_DIR/.env"
ln -sf "$SHARED_DIR/database/database.sqlite" "$RELEASE_DIR/database/database.sqlite"
ln -sf "$SHARED_DIR/public/sitemap.xml" "$RELEASE_DIR/public/sitemap.xml"
echo "▶️ Optimizing application..."
cd "$RELEASE_DIR"
php artisan optimize:clear
# Reset opcache if available
if command -v opcache_reset &> /dev/null; then
echo "▶️ Resetting OPcache..."
php -r "opcache_reset();" || true
fi
# Reset Redis cache if available
if command -v redis-cli &> /dev/null; then
echo "▶️ Flushing Redis cache..."
redis-cli FLUSHALL || true
fi
php artisan optimize
php artisan storage:link
echo "▶️ Running database migrations..."
php artisan migrate --force
echo "▶️ Managing SSR server with PM2..."
# Stop current SSR server gracefully
$PM2 stop laravel 2>/dev/null || echo "No previous SSR server to stop"
# Update symlink first
echo "▶️ Updating current symlink..."
ln -sfn "$RELEASE_DIR" "$CURRENT_LINK"
echo "▶️ Restarting PHP-FPM to apply new code..."
if sudo systemctl restart php8.3-fpm; then
echo "✅ PHP-FPM restarted successfully"
else
echo "❌ Failed to restart PHP-FPM!"
exit 1
fi
# Start SSR server from new release
cd "$CURRENT_LINK"
echo "▶️ Starting SSR server..."
$PM2 delete laravel 2>/dev/null || true
$PM2 start ecosystem.config.json
# Save PM2 process list
$PM2 save
# Wait a moment for SSR to start
sleep 3
# Verify SSR is running
echo "▶️ Verifying SSR server..."
if ! $PM2 describe laravel &>/dev/null; then
echo "❌ SSR server failed to start!"
exit 1
fi
echo "▶️ Cleaning old releases (keeping 5 latest)..."
cd "$RELEASES_DIR"
ls -dt */ | tail -n +6 | xargs -r rm -rf
echo "▶️ Current deployment status:"
$PM2 list
echo "▶️ Restarting Supervisor services..."
sudo supervisorctl restart all
echo "▶️ Checking health status..."
curl http://localhost/health
echo "✅ Deployment successful: $NOW"
exit 0
12. Konfiguracja SSL z Let's Encrypt
Zainstaluj i skonfiguruj SSL:
# Zainstaluj Certbot
sudo apt install -y certbot python3-certbot-nginx
# Uzyskaj certyfikat SSL
sudo certbot --nginx -d twoja-domena.com
# Skonfiguruj automatyczne odnowienie
sudo systemctl status certbot.timer
13. Laravel Scout - Typesense (opcjonalne)
Instalacja Typesense
curl -O https://dl.typesense.org/releases/0.24.1/typesense-server-0.24.1-amd64.deb
sudo apt install ./typesense-server-0.24.1-amd64.deb
sudo systemctl start typesense-server
sudo systemctl enable typesense-server
Aktualizacja pliku konfiguracyjnego
sudo nano /etc/typesense/typesense-server.ini
Restart
sudo systemctl restart typesense-server
Zagadnienia bezpieczeństwa
1. Zarządzanie kluczami SSH
Przechowuj swoje klucze SSH bezpiecznie w sekretach GitHub:
# Wygeneruj klucz SSH
ssh-keygen -t rsa -b 4096 -C "github-actions-deploy"
# Dodaj do sekretów GitHub
# SSH_HOST: Adres IP serwera
# SSH_USER: deployer
# SSH_KEY: Zawartość klucza prywatnego
2. Zmienne środowiskowe
Przechowuj wrażliwe informacje w sekretach GitHub:
# Dodaj do sekretów GitHub
# ENV_FILE: Zawartość Twojego pliku .env
3. Uprawnienia plików
Zapewnij odpowiednie uprawnienia plików:
chmod -R 775 /home/deployer/laravel/current/storage
chmod -R 775 /home/deployer/laravel/current/bootstrap/cache
4. Konfiguracja zapory
Skonfiguruj zaporę serwera:
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Rozwiązywanie problemów
Typowe problemy i rozwiązania
-
Błędy odmowy dostępu
- Sprawdź właściciela plików:
sudo chown -R deployer:www-data /home/deployer/laravel
- Sprawdź uprawnienia plików:
sudo chmod -R 775 /home/deployer/laravel
- Sprawdź właściciela plików:
-
Błędy migracji bazy danych
- Sprawdź dane dostępowe do bazy w
.env
- Uruchom migracje ręcznie:
php artisan migrate --force
- Sprawdź dane dostępowe do bazy w
-
Problemy z konfiguracją Nginx
- Przetestuj konfigurację Nginx:
sudo nginx -t
- Sprawdź logi Nginx:
sudo tail -f /home/deployer/laravel/shared/storage/logs/nginx_error.log
- Przetestuj konfigurację Nginx:
-
Problemy z PHP-FPM
- Sprawdź status PHP-FPM:
sudo systemctl status php8.3-fpm
- Sprawdź logi PHP-FPM:
sudo tail -f /home/deployer/laravel/shared/storage/logs/php-fpm-error.log
- Sprawdź status PHP-FPM:
-
Problemy z dowiązaniami symbolicznymi
- Upewnij się, że dowiązania są utworzone poprawnie:
ls -la /home/deployer/laravel/current
- Utwórz dowiązania ręcznie w razie potrzeby
- Upewnij się, że dowiązania są utworzone poprawnie:
Debugowanie wdrożenia
Aby debugować problemy z wdrożeniem:
-
Włącz szczegółowe wyświetlanie
- Dodaj
-v
do komend composera - Dodaj
--verbose
do komend artisan
- Dodaj
-
Sprawdź logi GitHub Actions
- Przejrzyj pełne logi workflow w GitHub
- Szukaj konkretnych komunikatów o błędach
-
Połącz się przez SSH z serwerem podczas wdrożenia
- Dodaj krok do workflow, aby utrzymać połączenie otwarte
- Sprawdź stan serwera podczas wdrożenia
Kod źródłowy
Pełny kod z tego artykułu znajdziesz na GitHub. Możesz go sklonować i użyć jako punkt wyjścia dla własnych projektów.
Śledź mnie na LinkedIn, aby otrzymywać więcej wskazówek o Laravel i DevOps!
Czy chciałbyś dowiedzieć się więcej o jakimś konkretnym aspekcie wdrażania bez przestojów? Daj znać w komentarzach poniżej!