This guide covers deploying the Laravel Blog API to a production environment with best practices for security, performance, and reliability.
Server requirements
Ensure your production server meets the following requirements:
PHP requirements
PHP ^7.1.3 or higher
Extensions :
OpenSSL PHP Extension
PDO PHP Extension
Mbstring PHP Extension
Tokenizer PHP Extension
XML PHP Extension
Ctype PHP Extension
JSON PHP Extension
BCMath PHP Extension
Verify installed PHP extensions with php -m
Web server
Choose one of the following:
Nginx 1.18+ (recommended)
Apache 2.4+ with mod_rewrite enabled
Database
MySQL 5.7+ or MariaDB 10.2+
PostgreSQL 9.6+ (alternative)
Additional requirements
Composer (for dependency management)
Git (for deployment)
SSL certificate (for HTTPS)
Pre-deployment checklist
Before deploying, ensure you have:
Test locally
Verify the application works correctly in your local environment
Update dependencies
Ensure all Composer dependencies are up to date:
Run tests
Execute your test suite to catch any issues:
Optimize code
Clear and cache configuration files: php artisan config:cache
php artisan route:cache
Environment configuration
Production environment settings differ significantly from development.
Production .env file
Create a production .env file with the following critical settings:
# Application
APP_NAME = "Laravel Blog API"
APP_ENV = production
APP_KEY = base64:YOUR_GENERATED_KEY_HERE
APP_DEBUG = false
APP_URL = https://yourdomain.com
# Logging
LOG_CHANNEL = stack
# Database
DB_CONNECTION = mysql
DB_HOST = 127.0.0.1
DB_PORT = 3306
DB_DATABASE = production_database
DB_USERNAME = production_user
DB_PASSWORD = strong_random_password
# Cache and Session
CACHE_DRIVER = redis
SESSION_DRIVER = redis
SESSION_LIFETIME = 120
QUEUE_CONNECTION = redis
# Redis
REDIS_HOST = 127.0.0.1
REDIS_PASSWORD = your_redis_password
REDIS_PORT = 6379
# Mail
MAIL_DRIVER = smtp
MAIL_HOST = smtp.yourprovider.com
MAIL_PORT = 587
MAIL_USERNAME = your_smtp_username
MAIL_PASSWORD = your_smtp_password
MAIL_ENCRYPTION = tls
Critical security settings:
Set APP_DEBUG=false to hide error details from users
Use a strong, unique APP_KEY (generate with php artisan key:generate)
Set APP_ENV=production
Use strong, random passwords for database and Redis
Environment variables explained
Application settings
APP_DEBUG=false : Prevents sensitive error information from being displayed to users
APP_ENV=production : Optimizes Laravel for production performance
APP_URL : Your application’s public URL (important for generating correct links)
CACHE_DRIVER = redis
SESSION_DRIVER = redis
QUEUE_CONNECTION = redis
Using Redis for caching, sessions, and queues significantly improves performance compared to file-based drivers.
Database setup
Create production database
On your production server, create the database:
CREATE DATABASE production_database CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER ' production_user '@ 'localhost' IDENTIFIED BY 'strong_random_password' ;
GRANT ALL PRIVILEGES ON production_database. * TO 'production_user' @ 'localhost' ;
FLUSH PRIVILEGES;
EXIT;
Replace production_database, production_user, and strong_random_password with your actual values.
Run migrations
Execute migrations on the production database:
php artisan migrate --force
The --force flag bypasses the production environment confirmation.
Always backup your database before running migrations in production: mysqldump -u production_user -p production_database > backup_ $( date +%Y%m%d_%H%M%S ) .sql
File storage configuration
Set up storage directories
Ensure storage directories exist and have proper permissions:
# Create necessary directories
mkdir -p storage/framework/cache
mkdir -p storage/framework/sessions
mkdir -p storage/framework/views
mkdir -p storage/logs
# Set permissions
chmod -R 775 storage bootstrap/cache
# Set ownership (adjust www-data to your web server user)
chown -R www-data:www-data storage bootstrap/cache
The web server user varies by system:
Ubuntu/Debian: www-data
CentOS/RHEL: apache or nginx
macOS: _www
Create storage symlink
If your application uses public file storage:
This creates a symbolic link from public/storage to storage/app/public.
Web server configuration
Nginx configuration
Create an Nginx server block for your application:
server {
listen 80 ;
listen [::]:80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$ server_name $ request_uri ;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
root /var/www/laravel-blog-api/public;
index index.php;
# SSL Configuration
ssl_certificate /path/to/ssl/certificate.crt;
ssl_certificate_key /path/to/ssl/private.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Logging
access_log /var/log/nginx/laravel-access.log;
error_log /var/log/nginx/laravel-error.log;
# File size limits
client_max_body_size 20M ;
location / {
try_files $ uri $ uri / /index.php?$ query_string ;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $ realpath_root $ fastcgi_script_name ;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all ;
}
}
Replace /var/run/php/php7.4-fpm.sock with your PHP-FPM socket path. Check with ls /var/run/php/
Apache configuration
If using Apache, create a virtual host:
< VirtualHost *:80 >
ServerName yourdomain.com
ServerAlias www.yourdomain.com
Redirect permanent / https://yourdomain.com/
</ VirtualHost >
< VirtualHost *:443 >
ServerName yourdomain.com
ServerAlias www.yourdomain.com
DocumentRoot /var/www/laravel-blog-api/public
< Directory /var/www/laravel-blog-api/public >
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</ Directory >
# SSL Configuration
SSLEngine on
SSLCertificateFile /path/to/ssl/certificate.crt
SSLCertificateKeyFile /path/to/ssl/private.key
# Logging
ErrorLog ${APACHE_LOG_DIR}/laravel-error.log
CustomLog ${APACHE_LOG_DIR}/laravel-access.log combined
</ VirtualHost >
Enable required Apache modules:
sudo a2enmod rewrite
sudo a2enmod ssl
sudo systemctl restart apache2
Deployment process
Upload code to server
Use Git to deploy your code: cd /var/www
git clone https://github.com/yourusername/laravel-blog-api.git
cd laravel-blog-api
Install dependencies
Install PHP dependencies without dev packages: composer install --optimize-autoloader --no-dev
The --no-dev flag excludes development dependencies, reducing the application size.
Configure environment
Copy and edit the environment file: cp .env.example .env
nano .env
Update all production values as detailed in Environment configuration .
Set permissions
chmod -R 775 storage bootstrap/cache
chown -R www-data:www-data storage bootstrap/cache
Run migrations
php artisan migrate --force
Optimize application
Cache configuration and routes for better performance: php artisan config:cache
php artisan route:cache
php artisan view:cache
Clear these caches when deploying updates using php artisan cache:clear
Restart web server
sudo systemctl restart nginx
Security best practices
Essential security measures
Implement these security measures before going live:
Disable debug mode
Use HTTPS only
Install SSL certificate (use Let’s Encrypt for free certificates)
Force HTTPS redirects
Set APP_URL to use https://
Secure your APP_KEY
Never commit .env to version control
Use a strong, random application key
Rotate keys periodically
Database security
Use strong passwords
Create dedicated database users with minimal privileges
Never use root database credentials
File permissions
# Application files: readable by web server
chmod -R 755 /var/www/laravel-blog-api
# Storage and cache: writable by web server
chmod -R 775 storage bootstrap/cache
# .env file: readable only by owner
chmod 600 .env
Hide sensitive files
Ensure .env, .git, and storage are not publicly accessible
Configure your web server to deny access to these directories
Additional hardening
Enable rate limiting for API endpoints
Implement CORS policies appropriately
Use prepared statements (Laravel does this by default)
Keep dependencies updated regularly
Monitor application logs for suspicious activity
Caching strategies
# Cache configuration
php artisan config:cache
# Cache routes
php artisan route:cache
# Cache views
php artisan view:cache
After making configuration changes, clear the cache with php artisan cache:clear and rebuild it.
Use Redis for caching
Install Redis:
sudo apt install redis-server
sudo systemctl enable redis-server
sudo systemctl start redis-server
Update .env:
CACHE_DRIVER = redis
SESSION_DRIVER = redis
QUEUE_CONNECTION = redis
Enable OPcache
Edit php.ini to enable OPcache:
opcache.enable =1
opcache.memory_consumption =128
opcache.interned_strings_buffer =8
opcache.max_accelerated_files =4000
opcache.revalidate_freq =60
opcache.fast_shutdown =1
Monitoring and maintenance
Log monitoring
Laravel logs are stored in storage/logs/laravel.log:
# View recent logs
tail -f storage/logs/laravel.log
# Search for errors
grep "ERROR" storage/logs/laravel.log
Consider using a log management service like Papertrail, Loggly, or CloudWatch for centralized logging.
Database backups
Automate daily backups with a cron job:
# Add to crontab
0 2 * * * mysqldump -u production_user -p 'password' production_database > /backups/db_ $( date + \% Y \% m \% d ) .sql
Scheduled tasks
If using Laravel’s task scheduler, add to crontab:
* * * * * cd /var/www/laravel-blog-api && php artisan schedule:run >> /dev/null 2>&1
Continuous deployment
For automated deployments, create a deployment script:
#!/bin/bash
# deploy.sh
set -e
echo "Starting deployment..."
# Pull latest code
git pull origin main
# Install/update dependencies
composer install --optimize-autoloader --no-dev
# Run migrations
php artisan migrate --force
# Clear and rebuild cache
php artisan cache:clear
php artisan config:cache
php artisan route:cache
php artisan view:cache
# Restart services
sudo systemctl restart php7.4-fpm
sudo systemctl reload nginx
echo "Deployment completed successfully!"
Make it executable:
Troubleshooting
500 Internal Server Error
Check Laravel logs:
tail -f storage/logs/laravel.log
Common causes:
Incorrect file permissions
Missing .env file
Database connection issues
403 Forbidden
Ensure web server has read access:
chown -R www-data:www-data /var/www/laravel-blog-api
White screen / blank page
Enable error reporting temporarily to diagnose:
Disable debug mode immediately after diagnosing the issue.
Database connection errors
Verify:
Database credentials in .env
Database server is running
Firewall allows database connections
# Test MySQL connection
mysql -u production_user -p production_database
Next steps
API reference Explore the API endpoints
Setup guide Return to local development setup