Deployment Guide
Complete guide to deploying LaraDashboard to production servers including server requirements, configuration, optimization, and security.
Deployment Guide
This guide covers deploying LaraDashboard to production environments, including server setup, web server configuration, and optimization.
Server Requirements
Minimum Requirements
| Component | Requirement |
|---|---|
| PHP | 8.3 or 8.4 |
| MySQL | 8.0+ |
| RAM | 1 GB |
| Storage | 10 GB |
| CPU | 1 core |
Recommended Requirements
| Component | Requirement |
|---|---|
| PHP | 8.4 |
| MySQL | 8.0+ |
| RAM | 4 GB |
| Storage | 50 GB SSD |
| CPU | 2+ cores |
| Redis | 7.0+ |
Required PHP Extensions
bcmath, ctype, curl, dom, fileinfo, gd/imagick,
json, mbstring, openssl, pdo, pdo_mysql,
tokenizer, xml, zip
Server Setup
Ubuntu/Debian
# Update system
sudo apt update && sudo apt upgrade -y
# Install PHP 8.3
sudo apt install php8.3-fpm php8.3-cli php8.3-mysql \
php8.3-mbstring php8.3-xml php8.3-curl php8.3-zip \
php8.3-gd php8.3-bcmath php8.3-redis -y
# Install MySQL
sudo apt install mysql-server -y
# Install Nginx
sudo apt install nginx -y
# Install Composer
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
# Install Node.js
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install nodejs -y
# Install Redis (recommended)
sudo apt install redis-server -y
Create Database
sudo mysql
CREATE DATABASE laradashboard CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'laradashboard'@'localhost' IDENTIFIED BY 'secure_password';
GRANT ALL PRIVILEGES ON laradashboard.* TO 'laradashboard'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Deploying the Application
Upload Files
Using Git (recommended):
cd /var/www
git clone https://github.com/your-repo/laradashboard.git
cd laradashboard
Or using SCP/SFTP:
scp -r laradashboard/ user@server:/var/www/
Install Dependencies
# PHP dependencies (production mode)
composer install --no-dev --optimize-autoloader
# Node dependencies and build
npm ci
npm run build
Configure Environment
# Copy environment file
cp .env.example .env
# Generate application key
php artisan key:generate
# Edit environment file
nano .env
Essential .env settings:
APP_NAME="LaraDashboard"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://yourdomain.com
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laradashboard
DB_USERNAME=laradashboard
DB_PASSWORD=secure_password
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
Set Permissions
# Set ownership
sudo chown -R www-data:www-data /var/www/laradashboard
# Set directory permissions
sudo chmod -R 755 /var/www/laradashboard
sudo chmod -R 775 /var/www/laradashboard/storage
sudo chmod -R 775 /var/www/laradashboard/bootstrap/cache
# Create storage link
php artisan storage:link
Run Migrations
php artisan migrate --force
php artisan db:seed --force
Web Server Configuration
Nginx Configuration
# /etc/nginx/sites-available/laradashboard
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/laradashboard/public;
index index.php;
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
# 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;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Gzip Compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
# Client body size (file uploads)
client_max_body_size 100M;
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.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_read_timeout 300;
}
# Deny access to sensitive files
location ~ /\.(?!well-known).* {
deny all;
}
location ~ /\.env {
deny all;
}
# Static file caching
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}
Enable the site:
sudo ln -s /etc/nginx/sites-available/laradashboard /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Apache Configuration
# /etc/apache2/sites-available/laradashboard.conf
<VirtualHost *:80>
ServerName yourdomain.com
Redirect permanent / https://yourdomain.com/
</VirtualHost>
<VirtualHost *:443>
ServerName yourdomain.com
DocumentRoot /var/www/laradashboard/public
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/yourdomain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem
<Directory /var/www/laradashboard/public>
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/laradashboard-error.log
CustomLog ${APACHE_LOG_DIR}/laradashboard-access.log combined
</VirtualHost>
Enable the site:
sudo a2enmod rewrite ssl
sudo a2ensite laradashboard
sudo systemctl reload apache2
SSL Certificate
Using Let's Encrypt
# Install Certbot
sudo apt install certbot python3-certbot-nginx -y
# Obtain certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Auto-renewal is configured automatically
# Test renewal
sudo certbot renew --dry-run
Optimization
Cache Configuration
# Cache all the things
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
# Or use optimize
php artisan optimize
PHP-FPM Tuning
Edit /etc/php/8.3/fpm/pool.d/www.conf:
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
MySQL Tuning
Edit /etc/mysql/mysql.conf.d/mysqld.cnf:
[mysqld]
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
query_cache_type = 1
query_cache_size = 128M
max_connections = 200
Redis Configuration
Edit /etc/redis/redis.conf:
maxmemory 256mb
maxmemory-policy allkeys-lru
Queue Workers
Supervisor Setup
Install Supervisor:
sudo apt install supervisor -y
Create worker configuration:
# /etc/supervisor/conf.d/laradashboard-worker.conf
[program:laradashboard-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/laradashboard/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
numprocs=4
redirect_stderr=true
stdout_logfile=/var/www/laradashboard/storage/logs/worker.log
stopwaitsecs=3600
Start workers:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laradashboard-worker:*
Scheduled Tasks
Add to crontab:
sudo crontab -e
Add the line:
* * * * * cd /var/www/laradashboard && php artisan schedule:run >> /dev/null 2>&1
Security Checklist
Application Security
-
APP_DEBUG=false -
APP_ENV=production - Strong
APP_KEYgenerated - HTTPS enabled
- Secure session cookies
Server Security
- Firewall configured (UFW)
- SSH key authentication only
- Fail2ban installed
- Regular security updates
- Non-root user for application
File Security
-
.envnot accessible via web - Storage directory not directly accessible
- Proper file permissions
- No sensitive files in public
Firewall Setup
# Install UFW
sudo apt install ufw -y
# Configure rules
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 'Nginx Full'
sudo ufw enable
Monitoring
Log Files
# Application logs
tail -f /var/www/laradashboard/storage/logs/laravel.log
# Nginx logs
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log
# PHP-FPM logs
tail -f /var/log/php8.3-fpm.log
Laravel Telescope
For development/staging, enable Telescope:
// app/Providers/TelescopeServiceProvider.php
public function gate(): void
{
Gate::define('viewTelescope', function ($user) {
return in_array($user->email, [
'admin@example.com',
]);
});
}
Health Checks
Create a health check endpoint:
// routes/web.php
Route::get('/health', function () {
return response()->json([
'status' => 'healthy',
'timestamp' => now(),
'database' => DB::connection()->getPdo() ? 'connected' : 'disconnected',
'cache' => Cache::has('health') ? 'working' : 'working',
'queue' => Queue::size() ?? 0,
]);
});
Deployment Automation
Using Laravel Envoy
// Envoy.blade.php
@servers(['web' => 'user@yourdomain.com'])
@task('deploy', ['on' => 'web'])
cd /var/www/laradashboard
git pull origin main
composer install --no-dev --optimize-autoloader
npm ci && npm run build
php artisan migrate --force
php artisan optimize
sudo supervisorctl restart laradashboard-worker:*
@endtask
Run deployment:
envoy run deploy
Zero-Downtime Deployment
Use symbolic links for zero-downtime:
# Structure
/var/www/
├── laradashboard/ # Symlink to current release
├── releases/
│ ├── 20240115_103000/
│ └── 20240116_140000/
└── shared/
├── storage/
└── .env
Troubleshooting
500 Error
- Check storage permissions
- Check
.envconfiguration - View logs:
tail -f storage/logs/laravel.log - Enable debug temporarily:
APP_DEBUG=true
502 Bad Gateway
- Check PHP-FPM is running:
systemctl status php8.3-fpm - Check PHP-FPM socket path in Nginx config
- Check PHP-FPM logs
Assets Not Loading
- Run
npm run build - Check
APP_URLmatches domain - Clear browser cache
- Check Vite manifest exists
Next Steps
- Backup & Restore - Data protection
- Upgrade Guide - Version upgrades
- Troubleshooting - Common issues