Laravel API Resources: Transforming Your Eloquent Models for JSON Responses
Create consistent API responses with API resources.
Deploying a Laravel application can be intimidating, but with the right approach, it becomes a straightforward process. Whether you're using budget-friendly shared hosting or a powerful VPS, this guide will walk you through every step.
# .env.production
APP_NAME="Your App Name"
APP_ENV=production
APP_KEY=base64:your-generated-key-here
APP_DEBUG=false
APP_URL=https://yourdomain.com
APP_TIMEZONE=UTC
LOG_CHANNEL=stack
LOG_LEVEL=error
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_database
DB_USERNAME=your_username
DB_PASSWORD=your_secure_password
CACHE_DRIVER=redis
FILESYSTEM_DISK=public
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=your_smtp_username
MAIL_PASSWORD=your_smtp_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="noreply@yourdomain.com"
MAIL_FROM_NAME="${APP_NAME}"
Requirements for Laravel:
# Local preparation
cd /path/to/your/laravel-app
# Install dependencies (excluding dev dependencies)
composer install --optimize-autoloader --no-dev
# Build assets
npm run build
# Create zip for upload (excluding unnecessary files)
zip -r deployment.zip . \
-x "*.git*" \
-x "*.env*" \
-x "node_modules/*" \
-x "storage/*" \
-x "tests/*" \
-x "*.md" \
-x "*.txt" \
-x "phpunit.xml" \
-x "*.zip" \
-x "*.tar.gz"
cPanel Setup:
# Via cPanel File Manager or SSH
chmod -R 755 storage
chmod -R 755 bootstrap/cache
chmod 644 .env
# Create .env file via cPanel or upload
APP_NAME="Your App"
APP_ENV=production
APP_KEY=base64:...
APP_DEBUG=false
APP_URL=https://yourdomain.com
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=cpanelusername_dbname
DB_USERNAME=cpanelusername_dbuser
DB_PASSWORD=your_secure_password
# For shared hosting, use file cache
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_CONNECTION=sync
In cPanel โ Cron Jobs:
# Run every minute
* * * * * cd /home/username/public_html && php artisan schedule:run >> /dev/null 2>&1
# Daily backup (if using spatie/laravel-backup)
0 2 * * * cd /home/username/public_html && php artisan backup:run --quiet
Popular VPS Providers:
Recommended Specifications:
# Connect via SSH
ssh root@your_server_ip
# Update system
apt update && apt upgrade -y
# Create new user (optional but recommended)
adduser deploy
usermod -aG sudo deploy
# Copy SSH key for new user
rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy
# Setup firewall
sudo apt install ufw -y
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh # or your custom port: sudo ufw allow 2222/tcp
sudo ufw allow http
sudo ufw allow https
sudo ufw enable
# Install fail2ban for brute force protection
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
# Install PHP 8.2 with extensions
sudo apt install software-properties-common -y
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update
sudo apt install php8.2-fpm php8.2-common php8.2-mysql php8.2-xml \
php8.2-xmlrpc php8.2-curl php8.2-gd php8.2-imagick php8.2-cli \
php8.2-dev php8.2-imap php8.2-mbstring php8.2-opcache \
php8.2-soap php8.2-zip php8.2-bcmath php8.2-intl -y
# Install Composer
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
sudo chmod +x /usr/local/bin/composer
# Install MySQL
sudo apt install mysql-server -y
sudo mysql_secure_installation
# Install Redis
sudo apt install redis-server -y
sudo systemctl enable redis-server
sudo systemctl start redis-server
# Install Nginx
sudo apt install nginx -y
# Install Node.js and npm
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install nodejs -y
sudo mkdir -p /var/www/yourdomain.com
sudo chown -R deploy:www-data /var/www/yourdomain.com
sudo chmod -R 755 /var/www/yourdomain.com
# As deploy user
su - deploy
cd /var/www/yourdomain.com
# Clone your repository
git clone https://github.com/yourusername/yourproject.git .
# Or upload via SCP
# From local machine:
scp -r /path/to/local/laravel deploy@your_server_ip:/var/www/yourdomain.com
cd /var/www/yourdomain.com
# Install PHP dependencies
composer install --optimize-autoloader --no-dev
# Install npm dependencies and build
npm ci --only=production
npm run build
# Set permissions
sudo chown -R deploy:www-data /var/www/yourdomain.com
sudo chmod -R 775 storage bootstrap/cache
cd /var/www/yourdomain.com
cp .env.example .env
# Generate application key
php artisan key:generate
# Edit .env file
nano .env
# /var/www/yourdomain.com/.env
APP_NAME="Your App"
APP_ENV=production
APP_KEY=base64:...
APP_DEBUG=false
APP_URL=https://yourdomain.com
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_db
DB_USERNAME=laravel_user
DB_PASSWORD=your_secure_password
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
server {
listen 80;
listen [::]:80;
server_name yourdomain.com www.yourdomain.com;
root /var/www/yourdomain.com/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header X-XSS-Protection "1; mode=block";
index index.php;
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/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
# Cache static files
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Deny access to sensitive files
location ~ /\.ht {
deny all;
}
location ~ /\.env {
deny all;
}
location ~ /storage/.*\.php$ {
deny all;
}
}
Enable the site:
sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo nano /etc/php/8.2/fpm/php.ini
; Performance optimization
max_execution_time = 300
max_input_time = 300
memory_limit = 256M
post_max_size = 100M
upload_max_filesize = 100M
; Opcache for better performance
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2
opcache.fast_shutdown=1
; Security
expose_php = Off
display_errors = Off
log_errors = On
sudo nano /etc/php/8.2/fpm/pool.d/www.conf
; Performance tuning
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500
; User and group
user = deploy
group = www-data
; Listen socket
listen = /var/run/php/php8.2-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
Restart PHP-FPM:
sudo systemctl restart php8.2-fpm
# Install Certbot
sudo apt install certbot python3-certbot-nginx -y
# Get SSL certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Auto-renewal test
sudo certbot renew --dry-run
sudo apt install supervisor -y
sudo nano /etc/supervisor/conf.d/laravel-worker.conf
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/yourdomain.com/artisan queue:work --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=deploy
numprocs=4
redirect_stderr=true
stdout_logfile=/var/www/yourdomain.com/storage/logs/worker.log
stopwaitsecs=3600
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start all
#!/bin/bash
set -e
echo "๐ Starting deployment..."
# Variables
PROJECT_PATH="/var/www/yourdomain.com"
BACKUP_PATH="/var/backups/yourdomain.com"
BRANCH="main"
# Backup current version
echo "๐ฆ Creating backup..."
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
sudo -u deploy cp -r "$PROJECT_PATH" "$BACKUP_PATH/$TIMESTAMP"
# Go to project directory
cd "$PROJECT_PATH"
# Pull latest changes
echo "โฌ๏ธ Pulling latest changes..."
sudo -u deploy git fetch origin
sudo -u deploy git checkout "$BRANCH"
sudo -u deploy git reset --hard origin/"$BRANCH"
sudo -u deploy git pull origin "$BRANCH"
# Install PHP dependencies
echo "๐ฆ Installing PHP dependencies..."
sudo -u deploy composer install --no-dev --optimize-autoloader
# Install npm dependencies and build
echo "๐ฆ Installing npm dependencies..."
sudo -u deploy npm ci --only=production
sudo -u deploy npm run build
# Run database migrations
echo "๐๏ธ Running migrations..."
sudo -u deploy php artisan migrate --force
# Clear caches
echo "๐งน Clearing caches..."
sudo -u deploy php artisan config:cache
sudo -u deploy php artisan route:cache
sudo -u deploy php artisan view:cache
sudo -u deploy php artisan event:cache
# Set permissions
echo "๐ Setting permissions..."
sudo chown -R deploy:www-data "$PROJECT_PATH"
sudo chmod -R 775 storage bootstrap/cache
# Restart services
echo "๐ Restarting services..."
sudo supervisorctl restart all
sudo systemctl reload php8.2-fpm
sudo systemctl reload nginx
echo "โ
Deployment completed successfully!"
echo "๐ Your site is now live at: https://yourdomain.com"
Make it executable:
sudo chmod +x /var/www/yourdomain.com/deploy.sh
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: mbstring, xml, ctype, iconv, intl, pdo_mysql, bcmath, redis
- name: Install Dependencies
run: composer install --prefer-dist --no-progress --no-interaction
- name: Run Tests
run: vendor/bin/phpunit
deploy:
needs: tests
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup SSH
uses: webfactory/ssh-agent@v0.5.3
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Deploy to Production
run: |
ssh -o StrictHostKeyChecking=no deploy@${{ secrets.SERVER_IP }} << 'EOF'
cd /var/www/yourdomain.com
git pull origin main
composer install --no-dev --optimize-autoloader
npm ci --only=production
npm run build
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cache
sudo supervisorctl restart all
sudo systemctl reload php8.2-fpm
EOF
# Install monitoring tools
sudo apt install htop nload net-tools -y
# Install logrotate for Laravel logs
sudo nano /etc/logrotate.d/laravel
# /etc/logrotate.d/laravel
/var/www/yourdomain.com/storage/logs/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 640 deploy www-data
sharedscripts
postrotate
sudo systemctl reload php8.2-fpm >/dev/null 2>&1 || true
endscript
}
#!/bin/bash
# security-hardening.sh
echo "๐ Starting server security hardening..."
# Update system
echo "๐ Updating system packages..."
apt update && apt upgrade -y
# Install security tools
echo "๐ฆ Installing security tools..."
apt install -y fail2ban ufw unattended-upgrades logwatch
# Setup firewall
echo "๐ฅ Configuring firewall..."
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw allow http
ufw allow https
echo "y" | ufw enable
# Secure SSH
echo "๐ Securing SSH..."
sed -i 's/#Port 22/Port 2222/' /etc/ssh/sshd_config
sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
systemctl restart sshd
# Setup fail2ban
echo "๐จ Configuring fail2ban..."
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
cat >> /etc/fail2ban/jail.local << EOF
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 3600
EOF
systemctl restart fail2ban
# Set file permissions
echo "๐ Setting secure permissions..."
find /var/www -type d -exec chmod 755 {} \;
find /var/www -type f -exec chmod 644 {} \;
chmod -R 750 /var/www/yourdomain.com/storage
chmod -R 750 /var/www/yourdomain.com/bootstrap/cache
chown -R deploy:www-data /var/www/yourdomain.com
echo "โ
Security hardening completed!"
#!/bin/bash
# quick-fixes.sh
echo "๐ง Applying quick fixes..."
# Fix permissions
echo "Setting permissions..."
sudo chown -R deploy:www-data /var/www/yourdomain.com
sudo chmod -R 775 storage bootstrap/cache
sudo chmod 644 .env
# Clear caches
echo "Clearing caches..."
php artisan cache:clear
php artisan config:clear
php artisan route:clear
php artisan view:clear
# Re-cache for production
echo "Re-caching for production..."
php artisan config:cache
php artisan route:cache
php artisan view:cache
# Restart services
echo "Restarting services..."
sudo supervisorctl restart all
sudo systemctl reload php8.2-fpm
sudo systemctl reload nginx
echo "โ
Quick fixes applied!"
Quick Performance Wins:
Deploying Laravel applications doesn't have to be complicated. Whether you choose shared hosting for simplicity or a VPS for control and performance, following these step-by-step guides will ensure a smooth deployment process.
Remember: Every deployment is a learning opportunity. Start with a simple setup, monitor performance, and gradually implement more advanced optimizations as your application grows.