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_KEY generated
  • 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

  • .env not 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

  1. Check storage permissions
  2. Check .env configuration
  3. View logs: tail -f storage/logs/laravel.log
  4. Enable debug temporarily: APP_DEBUG=true

502 Bad Gateway

  1. Check PHP-FPM is running: systemctl status php8.3-fpm
  2. Check PHP-FPM socket path in Nginx config
  3. Check PHP-FPM logs

Assets Not Loading

  1. Run npm run build
  2. Check APP_URL matches domain
  3. Clear browser cache
  4. Check Vite manifest exists

Next Steps

/