Laravel Projesini Sunucuya Deploy Etmek
Geliştirdiniz, test ettiniz, her şey local'de çalışıyor. Şimdi sıra canlıya almakta. Shared hosting'den VPS'e, Docker'dan PaaS'a kadar birkaç yol var. Bu yazıda VPS (Virtual Private Server) üzerinde Laravel deploy etmeyi anlatacağım — en çok kullandığım ve önerdiğim yöntem.
Sunucu Hazırlığı
Ubuntu 22.04 veya Debian 12 üzerinde çalıştığınızı varsayıyorum. Gerekli paketleri kuralım:
# Sistem güncellemesi
sudo apt update && sudo apt upgrade -y
# PHP 8.3 ve gerekli extension'lar
sudo apt install -y php8.3-fpm php8.3-cli php8.3-mbstring php8.3-xml \
php8.3-bcmath php8.3-curl php8.3-zip php8.3-gd php8.3-mysql \
php8.3-sqlite3 php8.3-intl php8.3-redis
# Nginx
sudo apt install -y nginx
# MySQL (veya MariaDB)
sudo apt install -y mysql-server
# Composer
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
# Node.js (frontend build için)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
# Git
sudo apt install -y git
# Redis (queue ve cache için)
sudo apt install -y redis-server
MySQL Veritabanı Oluşturma
sudo mysql -u root
CREATE DATABASE laravel_app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'laravel_user'@'localhost' IDENTIFIED BY 'güçlü-bir-şifre';
GRANT ALL PRIVILEGES ON laravel_app.* TO 'laravel_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Şifre için openssl rand -base64 32 ile güçlü bir şifre oluşturun. "123456" veya "password" kullanmayın — bunu söylememe gerek yok aslında ama söylüyorum.
Proje Dosyalarını Sunucuya Taşımak
Git ile (Önerilen)
# Web dizini oluştur
sudo mkdir -p /var/www/projeman
sudo chown $USER:www-data /var/www/projeman
# Repo'yu klonla
cd /var/www
git clone https://github.com/projeman/laravel-deploy-live.git projeman
cd projeman
# Bağımlılıkları kur
composer install --no-dev --optimize-autoloader --no-interaction
npm install && npm run build
--no-dev flag'i development bağımlılıklarını (phpunit, telescope, debugbar vb.) kurmaz. Production'da bunlar gereksiz ve güvenlik riski.
rsync ile (Alternatif)
rsync -avz --exclude='.git' --exclude='node_modules' --exclude='.env' \
/local/proje/ user@sunucu:/var/www/projeman/
Environment Dosyası
cp .env.example .env
nano .env
APP_NAME=ProjeMan
APP_ENV=production
APP_KEY=
APP_DEBUG=false
APP_URL=https://projeman.net
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_app
DB_USERNAME=laravel_user
DB_PASSWORD=güçlü-bir-şifre
CACHE_STORE=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailgun.org
MAIL_PORT=587
[email protected]
MAIL_PASSWORD=mail-şifresi
MAIL_ENCRYPTION=tls
[email protected]
MAIL_FROM_NAME="ProjeMan"
Kritik noktalar:
APP_DEBUG=false— Production'da MUTLAKA false. True bırakırsanız hata mesajlarında veritabanı şifreleri, API key'leri görünür.APP_ENV=production— Cache, logging ve hata davranışı buna göre değişir.- Key oluşturun:
php artisan key:generate
İzinler
sudo chown -R $USER:www-data /var/www/projeman
sudo chmod -R 775 storage bootstrap/cache
Storage ve bootstrap/cache dizinlerine PHP-FPM'in (www-data user'ı) yazma izni vermezseniz log yazamaz, cache oluşturamaz, dosya upload edemez — ve hata mesajları da belirsiz olur.
Nginx Yapılandırması
server {
listen 80;
server_name projeman.net www.projeman.net;
root /var/www/projeman/public;
index index.php;
charset utf-8;
# Gzip sıkıştırma
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
# .env ve hassas dosyaları engelle
location ~ /\.(?!well-known) {
deny all;
}
# Storage'a direkt erişimi engelle
location ~ ^/storage/.*\.php$ {
deny all;
}
# Static dosya cache
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}
# Site'yi aktifleştir
sudo ln -s /etc/nginx/sites-available/projeman /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
root /var/www/projeman/public olmalı — /var/www/projeman/ değil. Public dizinini root yapmak Laravel'in .env dosyasına ve diğer hassas dosyalara web üzerinden erişimi engeller.
SSL Sertifikası (Let's Encrypt)
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d projeman.net -d www.projeman.net
Certbot Nginx config'i otomatik günceller — HTTP'yi HTTPS'ye yönlendirir, sertifika ayarlarını ekler. Sertifika 90 günlük, otomatik yenileme cron'u kurulur.
Cloudflare kullanıyorsanız SSL ayarını "Full (Strict)" yapın ve origin sertifikası oluşturun.
Laravel Optimizasyonları
# Config cache — .env'i PHP array'e derler, her istekte parse etmez
php artisan config:cache
# Route cache — route'ları derler, her istekte regex eşleştirme yapmaz
php artisan route:cache
# View cache — Blade template'lerini PHP'ye derler
php artisan view:cache
# Event cache
php artisan event:cache
# Autoload optimize
composer dump-autoload --optimize
Bu komutlar production'da performansı ciddi şekilde artırır. Ama development'ta kullanmayın — config:cache aktifken .env değişiklikleri görünmez.
Migration ve Seed
php artisan migrate --force
php artisan db:seed --force # Sadece ilk kurulumda
--force flag'i production'da confirmation prompt'unu atlar. CI/CD pipeline'larında gerekli.
Queue Worker (Systemd)
Arka plan işleri için queue worker'ı systemd servisi olarak çalıştırın:
sudo nano /etc/systemd/system/projeman-worker.service
[Unit]
Description=ProjeMan Queue Worker
After=redis.service mysql.service
[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/projeman
ExecStart=/usr/bin/php artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
sudo systemctl enable projeman-worker
sudo systemctl start projeman-worker
Scheduler (Cron)
sudo crontab -u www-data -e
* * * * * cd /var/www/projeman && php artisan schedule:run >> /dev/null 2>&1
Deploy Script
Her güncelleme için tekrar tekrar aynı komutları yazmamak için bir deploy script:
#!/bin/bash
# deploy.sh
set -e
echo "→ Deploying ProjeMan..."
cd /var/www/projeman
# Bakım modunu aç
php artisan down --retry=60
# Son kodu çek
git pull origin main
# Bağımlılıkları güncelle
composer install --no-dev --optimize-autoloader --no-interaction
# Frontend build
npm install && npm run build
# Migration
php artisan migrate --force
# Cache temizle ve yeniden oluştur
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
# Queue worker'ı yeniden başlat
php artisan queue:restart
# İzinleri düzelt
sudo chown -R www-data:www-data storage bootstrap/cache
# Bakım modunu kapat
php artisan up
echo "→ Deploy tamamlandı!"
chmod +x deploy.sh
./deploy.sh
php artisan down bakım sayfasını gösterir — deploy sırasında kullanıcılar hata görmez. --retry=60 browser'a 60 saniye sonra tekrar denemesini söyler.
set -e herhangi bir komut hata verirse script durur. Yarım kalmış deploy tehlikeli — set -e bunu önler.
Güvenlik Kontrol Listesi
-
APP_DEBUG=false -
.envdosyası web'den erişilemez - Storage dizinine PHP çalıştırma yetkisi yok
- SSH parola girişi kapalı, sadece key ile giriş
- Firewall aktif (ufw: sadece 22, 80, 443 açık)
- MySQL root şifresi güçlü
- Düzenli yedekleme (spatie/laravel-backup veya cron + mysqldump)
- SSL sertifikası aktif ve otomatik yenilenme kurulu
- fail2ban kurulu (brute force koruması)
Otomatik Deploy (GitHub Actions)
Manuel deploy yerine push'ta otomatik deploy:
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy to server
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_IP }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/projeman
./deploy.sh
GitHub repo settings'ten Secrets'a sunucu bilgilerini ekleyin. main branch'e push yapınca otomatik deploy olur.
İlk deploy her zaman en zor olanı. Ama bir kez deploy script'i ve CI/CD kurduğunuzda sonraki güncellemeler git push kadar kolay olur. Önemli olan güvenlik ayarlarını doğru yapmak ve düzenli yedekleme almak — geri kalanı rutin.