Deploying Laravel to production is more than git push. AWS provides enterprise-grade infrastructure, but requires proper configuration for security, performance, and scalability. At ZIRA Software, we deploy dozens of Laravel applications on AWS, and this guide captures our battle-tested approach.
Why AWS for Laravel?
AWS advantages:
- Scalability on demand
- 99.99% uptime SLA
- Global infrastructure
- Managed services (RDS, ElastiCache, S3)
- Pay-as-you-go pricing
- Enterprise security
AWS Services we'll use:
- EC2: Virtual servers
- RDS: Managed MySQL/PostgreSQL
- S3: File storage
- ElastiCache: Redis/Memcached
- Route 53: DNS
- CloudFront: CDN
Prerequisites
- AWS account
- Domain name
- SSH key pair
- Basic Linux knowledge
Architecture Overview
┌─────────────┐
│ Route 53 │ (DNS)
└──────┬──────┘
│
┌──────▼──────┐
│ CloudFront │ (CDN)
└──────┬──────┘
│
┌──────────▼──────────┐
│ Elastic Load │
│ Balancer │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ EC2 Instances │
│ (Laravel App) │
└───┬──────────────┬──┘
│ │
┌─────▼─────┐ ┌────▼────┐
│ RDS │ │ S3 │
│ (MySQL) │ │ (Files) │
└───────────┘ └─────────┘
Step 1: Launch EC2 Instance
Create Instance
- Go to EC2 Dashboard → Launch Instance
- Choose AMI: Ubuntu Server 20.04 LTS
- Instance type: t2.micro (free tier) or t2.small
- Configure security group:
- SSH (22) - Your IP
- HTTP (80) - Anywhere
- HTTPS (443) - Anywhere
- Create/select key pair
- Launch instance
Connect to Instance
chmod 400 your-key.pem
ssh -i your-key.pem ubuntu@your-ec2-ip
Step 2: Configure Server
Update System
sudo apt update
sudo apt upgrade -y
Install PHP 7.0
sudo apt install -y software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt update
sudo apt install -y php7.0-fpm php7.0-cli php7.0-mcrypt php7.0-mysql \
php7.0-curl php7.0-gd php7.0-mbstring php7.0-xml php7.0-zip
Install Nginx
sudo apt install -y nginx
# Start and enable
sudo systemctl start nginx
sudo systemctl enable nginx
Install Composer
curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer
Install Git
sudo apt install -y git
Install Node.js (for asset compilation)
curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
sudo apt install -y nodejs
Step 3: Setup RDS Database
Create RDS Instance
- Go to RDS Dashboard → Create Database
- Choose: MySQL 5.7
- Template: Free tier or Production
- DB Instance identifier: laravel-db
- Master username: admin
- Master password: (secure password)
- Instance class: db.t2.micro
- Storage: 20 GB
- VPC security group: Allow access from EC2 security group
- Create database
Get Connection Details
- Endpoint:
laravel-db.xxxxx.us-east-1.rds.amazonaws.com - Port:
3306 - Database name:
laravel
Step 4: Setup S3 Bucket
Create Bucket
aws s3 mb s3://your-app-storage
Or via Console:
- Go to S3 → Create Bucket
- Bucket name: your-app-storage
- Region: Same as EC2
- Create
Configure CORS
[
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET", "PUT", "POST", "DELETE"],
"AllowedOrigins": ["*"],
"ExposeHeaders": []
}
]
Create IAM User
- IAM → Users → Add User
- Username: laravel-s3-user
- Access type: Programmatic access
- Attach policy: AmazonS3FullAccess
- Note Access Key ID and Secret
Step 5: Deploy Laravel Application
Create Directory
sudo mkdir -p /var/www/laravel
sudo chown -R $USER:$USER /var/www/laravel
cd /var/www/laravel
Clone Repository
git clone https://github.com/youruser/yourapp.git .
# Or upload files via SCP
scp -i your-key.pem -r /local/path ubuntu@ec2-ip:/var/www/laravel
Install Dependencies
composer install --no-dev --optimize-autoloader
npm install
npm run production
Configure Environment
cp .env.example .env
nano .env
Production .env:
APP_NAME="Your App"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://yourdomain.com
DB_CONNECTION=mysql
DB_HOST=laravel-db.xxxxx.us-east-1.rds.amazonaws.com
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=admin
DB_PASSWORD=your-rds-password
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
REDIS_HOST=your-elasticache-endpoint
REDIS_PASSWORD=null
REDIS_PORT=6379
AWS_ACCESS_KEY_ID=your-key
AWS_SECRET_ACCESS_KEY=your-secret
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=your-app-storage
MAIL_DRIVER=ses
MAIL_FROM_ADDRESS=noreply@yourdomain.com
MAIL_FROM_NAME="${APP_NAME}"
Generate Key & Migrate
php artisan key:generate
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cache
Set Permissions
sudo chown -R www-data:www-data /var/www/laravel
sudo chmod -R 755 /var/www/laravel
sudo chmod -R 775 /var/www/laravel/storage
sudo chmod -R 775 /var/www/laravel/bootstrap/cache
Step 6: Configure Nginx
sudo nano /etc/nginx/sites-available/laravel
Nginx configuration:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
root /var/www/laravel/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.php index.html;
charset utf-8;
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 ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
Enable site:
sudo ln -s /etc/nginx/sites-available/laravel /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Step 7: Install SSL Certificate
Using Let's Encrypt (Free)
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Follow prompts and choose redirect option.
Auto-renewal:
sudo certbot renew --dry-run
Step 8: Setup Queue Worker
Create Supervisor Configuration
sudo apt install -y supervisor
sudo nano /etc/supervisor/conf.d/laravel-worker.conf
Configuration:
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/laravel/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
numprocs=2
redirect_stderr=true
stdout_logfile=/var/www/laravel/storage/logs/worker.log
stopwaitsecs=3600
Start worker:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-worker:*
Step 9: Setup Cron Jobs
sudo crontab -e -u www-data
Add:
* * * * * cd /var/www/laravel && php artisan schedule:run >> /dev/null 2>&1
Step 10: Setup ElastiCache (Redis)
- ElastiCache → Redis → Create
- Name: laravel-cache
- Node type: cache.t2.micro
- Number of replicas: 0 (or 1 for HA)
- Security group: Allow EC2 security group
- Create
Update .env with ElastiCache endpoint.
Deployment Script
Create deployment script for updates:
#!/bin/bash
cd /var/www/laravel
# Maintenance mode
php artisan down
# Pull latest code
git pull origin main
# Install dependencies
composer install --no-dev --optimize-autoloader
# Migrate database
php artisan migrate --force
# Clear and cache
php artisan config:cache
php artisan route:cache
php artisan view:cache
# Restart queue workers
sudo supervisorctl restart laravel-worker:*
# Exit maintenance mode
php artisan up
echo "Deployment complete!"
Make executable:
chmod +x deploy.sh
Monitoring & Logging
CloudWatch Logs
Install agent:
wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
sudo dpkg -i amazon-cloudwatch-agent.deb
Application Logging
# View Laravel logs
tail -f /var/www/laravel/storage/logs/laravel.log
# View Nginx logs
tail -f /var/log/nginx/error.log
tail -f /var/log/nginx/access.log
# View queue logs
tail -f /var/www/laravel/storage/logs/worker.log
Scaling
Horizontal Scaling
- Create AMI from EC2 instance
- Launch Auto Scaling Group
- Add Load Balancer
- Configure health checks
Vertical Scaling
Change instance type:
- Stop instance
- Change instance type
- Start instance
Security Best Practices
-
Use Security Groups properly
- Restrict SSH to your IP
- Use VPC for RDS
-
Keep software updated
sudo apt update && sudo apt upgrade -y -
Disable debug mode
APP_DEBUG=false -
Rotate secrets
- Change
APP_KEYcarefully - Rotate AWS keys regularly
- Change
-
Enable CloudTrail
- Audit all AWS API calls
-
Use IAM roles
- Attach IAM role to EC2 instead of hardcoding keys
Cost Optimization
Free tier eligible:
- EC2 t2.micro: 750 hours/month
- RDS db.t2.micro: 750 hours/month
- S3: 5GB storage
- CloudFront: 50GB transfer
Cost-saving tips:
- Use Reserved Instances (40-60% savings)
- Enable auto-scaling
- Use S3 lifecycle policies
- Monitor with Cost Explorer
Troubleshooting
500 Error:
# Check Laravel logs
tail -f storage/logs/laravel.log
# Check Nginx logs
sudo tail -f /var/log/nginx/error.log
# Check PHP-FPM
sudo systemctl status php7.0-fpm
Permission Issues:
sudo chown -R www-data:www-data /var/www/laravel
sudo chmod -R 755 /var/www/laravel
sudo chmod -R 775 storage bootstrap/cache
Database Connection Failed:
- Check RDS security group
- Verify credentials
- Test connection:
mysql -h endpoint -u user -p
Conclusion
AWS provides robust infrastructure for Laravel applications. While the initial setup requires effort, the result is a scalable, secure production environment. At ZIRA Software, this architecture supports applications serving millions of requests monthly.
Follow this guide, adapt to your needs, and you'll have a production-ready Laravel deployment on AWS.
Need help deploying to AWS? Contact ZIRA Software to discuss infrastructure setup, DevOps automation, and cloud architecture for your Laravel application.