Server Deployment: From Development to Production
Complete guide to deploying Laravel applications to production servers with zero-downtime deployment, SSL configuration, and performance optimization.
StalkTechie
Author
Server Deployment: From Development to Production
Deploying a Laravel app isn't just FTP-ing files anymore-it's about reliability, security, and scalability. Imagine pushing code without users noticing downtime, auto-scaling during traffic spikes, and sleeping easy knowing SSL and backups are handled. This guide covers the full journey: prep, CI/CD, zero-downtime strategies, SSL, optimization, and monitoring. Tailored for Laravel 11.x in 2025, whether on VPS (DigitalOcean), cloud (AWS), or PaaS (Vercel for APIs). Let's turn your local dev into a battle-hardened production beast.
Preparing Your App for Production
Before deploy, harden and optimize.
- Env Config: Use
.env.production-set APP_ENV=production, APP_DEBUG=false, LOG_CHANNEL=stderr. - Composer Optimize:
composer install --optimize-autoloader --no-dev-removes dev deps. - Cache Everything:
php artisan config:cache,route:cache,view:cache,event:cache. Clear withoptimize:clearin dev. - Storage Permissions:
chmod -R 775 storage bootstrap/cache, chown to www-data. - Queue/Supervisor: For Horizon or jobs-configure supervisord later.
Security: Enable CSRF, use Sanctum/Fortify. Scan with php artisan security:check (or laravel-security package). Human tip: Version your .env-never commit secrets; use Vault or Forge secrets.
Choosing a Server Environment
- VPS (e.g., DigitalOcean Droplet): Full control, Ubuntu 22.04+, install LEMP (Nginx, PHP 8.3, MySQL).
- Cloud (AWS EC2/Lightsail): Scalable, use EB for auto-deploys.
- PaaS (Laravel Vapor, Forge, Heroku): Serverless-Vapor handles Lambda scaling.
- Docker/K8s: Containerize for consistency (more below).
Setup basics: SSH key access, firewall (ufw allow 80,443,22), swap file for RAM.
Zero-Downtime Deployment Strategies
Avoid user frustration-use symlinks and atomic swaps.
Manual Script Approach
# On server: deploy.sh
git pull origin main
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan optimize
npm ci && npm run build # For assets
ln -sfn /path/to/new/release /path/to/current # Atomic switch
sudo systemctl reload php-fpm
Directories: /var/www/releases/{timestamp}, /var/www/current symlink. Rollback: Point symlink back.
Tools: Envoy, Deployer
Install Deployer: composer require deployer/deployer.
// deploy.php
host('prod')
->set('deploy_path', '/var/www/myapp')
->set('branch', 'main');
task('deploy', [
'deploy:prepare',
'deploy:lock',
'deploy:release',
'deploy:update_code',
'deploy:shared',
'deploy:vendors',
'artisan:migrate',
'deploy:symlink',
'deploy:unlock',
'cleanup',
]);
after('deploy:failed', 'deploy:unlock');
Run dep deploy prod-handles zero-downtime via symlinks. Envoy for Laravel-native tasks.
Docker and Containerized Deployment
For portability: Multi-stage Dockerfile.
FROM php:8.3-fpm as builder
WORKDIR /app
COPY . .
RUN composer install --no-dev
FROM php:8.3-fpm
COPY --from=builder /app /var/www
CMD ["php-fpm"]
Compose with nginx, mysql. Deploy to ECS or Kubernetes: Use rolling updates for zero-downtime.
CI/CD Pipelines
Automate with GitHub Actions:
name: Deploy
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with: {php-version: '8.3'}
- run: composer install --no-dev
- run: php artisan test
- name: Deploy to Server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USER }}
key: ${{ secrets.SSH_KEY }}
script: cd /var/www/myapp && git pull && php artisan migrate --force
Test first, then deploy. For Vapor: Serverless, auto-handles.
SSL Configuration and HTTPS
Free certs with Let's Encrypt.
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d example.com
In Nginx: Redirect HTTP to HTTPS, HSTS header. Laravel: URL::forceScheme('https'); in AppServiceProvider.
Performance Optimization Post-Deploy
- Opcache: Enable in php.ini: opcache.enable=1, opcache.memory_consumption=128.
- Queue Workers: Supervisor config:
program:x-laravel-queue{numprocs 8}. - CDN: Cloudflare for assets, caching.
- Database: Indexes, read replicas.
- Monitoring: Laravel Telescope (dev), Horizon for queues, New Relic/Prometheus.
Tune: php artisan queue:work --daemon, Redis for cache/sessions.
Security and Maintenance
- Firewall, fail2ban for brute-force.
- Backups: mysqldump cron, S3 storage.
- Logs: Rotate with logrotate, monitor with Papertrail.
- Updates: Regular OS patches, Laravel updates.
Disaster recovery: Test restores quarterly.
Common Pitfalls and Tips
Storage links: php artisan storage:link. Env sync issues-use Forge/Envoyer for managed deploys. Real talk: First deploy nerves? Use staging mirror. Scale: Add load balancer (NGINX) for multi-server.
Deployment done right means focus on building, not fixing. Start with Forge for ease, graduate to custom. Communities like Laracasts have gold-happy deploying!