Backend Framework Guide

    Deploying Laravel

    Deploy production-ready Laravel applications with Nginx, PHP-FPM, MySQL, Redis caching, SSL encryption, and automated deployment on RamNode's reliable VPS hosting.

    PHP 8.3
    Nginx
    MySQL
    SSL/TLS

    Laravel is a powerful PHP framework that provides an elegant syntax and robust toolset for building modern web applications. This guide walks you through deploying a Laravel application on a RamNode VPS, covering everything from initial server setup to production optimization and ongoing maintenance.

    1

    Prerequisites

    Before beginning the deployment, ensure you have:

    • A RamNode VPS with at least 2GB RAM (4GB recommended for production)
    • Ubuntu 22.04 LTS or Ubuntu 24.04 LTS installed
    • A registered domain name pointed to your VPS IP address
    • SSH access with root or sudo privileges
    • Your Laravel application code in a Git repository
    VPS Sizing

    For development/staging, 2GB RAM is sufficient. For production with moderate traffic, start with 4GB. You can easily scale your RamNode VPS as your application grows.

    2

    Initial Server Setup

    Connect and Update

    SSH & System Update
    ssh root@your_server_ip
    apt update && apt upgrade -y

    Create a Deployment User

    Running applications as root is a security risk:

    Create Deployer User
    # Create a new user
    adduser deployer
    
    # Add user to sudo group
    usermod -aG sudo deployer
    
    # Switch to the new user
    su - deployer

    Configure SSH Key Authentication

    SSH Key Setup
    # On your local machine, generate an SSH key (if you don't have one)
    ssh-keygen -t ed25519 -C "your_email@example.com"
    
    # Copy your public key to the server
    ssh-copy-id deployer@your_server_ip

    Configure Firewall

    UFW Configuration
    # Enable UFW
    sudo ufw enable
    
    # Allow SSH
    sudo ufw allow OpenSSH
    
    # Allow HTTP and HTTPS
    sudo ufw allow 'Nginx Full'
    
    # Check firewall status
    sudo ufw status
    3

    Installing Required Software

    Install Nginx

    Install Nginx
    sudo apt install nginx -y
    
    # Start and enable Nginx
    sudo systemctl start nginx
    sudo systemctl enable nginx
    
    # Verify Nginx is running
    sudo systemctl status nginx

    Install PHP 8.3 and Extensions

    Install PHP 8.3
    # Add PHP repository
    sudo add-apt-repository ppa:ondrej/php -y
    sudo apt update
    
    # Install PHP 8.3 and required extensions
    sudo apt install -y php8.3-fpm php8.3-cli php8.3-common \
      php8.3-mysql php8.3-pgsql php8.3-sqlite3 php8.3-redis \
      php8.3-mbstring php8.3-xml php8.3-curl php8.3-zip \
      php8.3-bcmath php8.3-intl php8.3-gd php8.3-imagick \
      php8.3-opcache php8.3-readline
    
    # Verify PHP installation
    php -v

    Install Composer

    Install Composer
    # Download and install Composer
    curl -sS https://getcomposer.org/installer | php
    
    # Move to global location
    sudo mv composer.phar /usr/local/bin/composer
    
    # Verify installation
    composer --version

    Install Node.js (Optional)

    Required if your Laravel app uses Vite or npm packages:

    Install Node.js
    # Install Node.js 20 LTS
    curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
    sudo apt install nodejs -y
    
    # Verify installation
    node -v
    npm -v

    Install Redis (Optional)

    Redis improves performance for caching, sessions, and queues:

    Install Redis
    # Install Redis
    sudo apt install redis-server -y
    
    # Configure Redis to run as a service
    sudo sed -i 's/supervised no/supervised systemd/' /etc/redis/redis.conf
    
    # Restart Redis
    sudo systemctl restart redis
    sudo systemctl enable redis
    
    # Test Redis
    redis-cli ping
    4

    Database Setup

    Install MySQL 8.0

    Install MySQL
    # Install MySQL
    sudo apt install mysql-server -y
    
    # Start and enable MySQL
    sudo systemctl start mysql
    sudo systemctl enable mysql
    
    # Run security script
    sudo mysql_secure_installation
    Security Script Prompts

    During mysql_secure_installation, set up password validation, set a root password, remove anonymous users, disallow remote root login, and remove the test database.

    Create Database and User

    MySQL Database Setup
    # Log into MySQL
    sudo mysql
    
    # Create database
    CREATE DATABASE laravel_app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    
    # Create user with strong password
    CREATE USER 'laravel_user'@'localhost' IDENTIFIED BY 'your_secure_password';
    
    # Grant privileges
    GRANT ALL PRIVILEGES ON laravel_app.* TO 'laravel_user'@'localhost';
    FLUSH PRIVILEGES;
    
    # Exit MySQL
    EXIT;
    PostgreSQL Alternative

    If you prefer PostgreSQL, install it with: sudo apt install postgresql postgresql-contrib -y. Laravel supports PostgreSQL natively.

    5

    Deploying Your Laravel Application

    Create Application Directory

    Setup Directory
    # Create web directory
    sudo mkdir -p /var/www/laravel-app
    
    # Set ownership to deployer user
    sudo chown -R deployer:deployer /var/www/laravel-app
    
    # Navigate to directory
    cd /var/www/laravel-app

    Clone Your Repository

    Clone Repository
    # Clone the repository
    git clone https://github.com/your-username/your-laravel-app.git .
    
    # Or for private repos, set up SSH key first
    git clone git@github.com:your-username/your-laravel-app.git .

    Install Dependencies

    Install Dependencies
    # Install PHP dependencies (production mode)
    composer install --optimize-autoloader --no-dev
    
    # Install npm dependencies and build assets (if applicable)
    npm ci
    npm run build

    Configure Environment

    Environment Setup
    # Copy example environment file
    cp .env.example .env
    
    # Generate application key
    php artisan key:generate
    
    # Edit environment file
    nano .env

    Update your .env file with production settings:

    .env Configuration
    APP_NAME="Your App Name"
    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=laravel_app
    DB_USERNAME=laravel_user
    DB_PASSWORD=your_secure_password
    
    CACHE_DRIVER=redis
    SESSION_DRIVER=redis
    QUEUE_CONNECTION=redis
    
    REDIS_HOST=127.0.0.1
    REDIS_PASSWORD=null
    REDIS_PORT=6379

    Run Migrations & Set Permissions

    Migrations & Permissions
    # Run migrations
    php artisan migrate --force
    
    # Optionally seed the database
    php artisan db:seed --force
    
    # Set storage and cache permissions
    sudo chown -R deployer:www-data /var/www/laravel-app
    sudo chmod -R 775 /var/www/laravel-app/storage
    sudo chmod -R 775 /var/www/laravel-app/bootstrap/cache

    Optimize for Production

    Laravel Optimization
    # Cache configuration
    php artisan config:cache
    
    # Cache routes
    php artisan route:cache
    
    # Cache views
    php artisan view:cache
    
    # Cache events (Laravel 11+)
    php artisan event:cache
    6

    Configuring Nginx

    Create Nginx Server Block

    Create Nginx Config
    sudo nano /etc/nginx/sites-available/laravel-app

    Add the following configuration:

    Nginx Configuration
    server {
        listen 80;
        listen [::]:80;
        server_name yourdomain.com www.yourdomain.com;
        root /var/www/laravel-app/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.3-fpm.sock;
            fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
            include fastcgi_params;
            fastcgi_hide_header X-Powered-By;
        }
    
        location ~ /\.(?!well-known).* {
            deny all;
        }
    
        # Gzip compression
        gzip on;
        gzip_vary on;
        gzip_min_length 1024;
        gzip_proxied expired no-cache no-store private auth;
        gzip_types text/plain text/css text/xml text/javascript
                   application/x-javascript application/xml
                   application/javascript application/json;
    }

    Enable the Site

    Enable Nginx Site
    # Create symbolic link
    sudo ln -s /etc/nginx/sites-available/laravel-app /etc/nginx/sites-enabled/
    
    # Remove default site (optional)
    sudo rm /etc/nginx/sites-enabled/default
    
    # Test Nginx configuration
    sudo nginx -t
    
    # Reload Nginx
    sudo systemctl reload nginx
    7

    SSL Certificate with Let's Encrypt

    Install Certbot

    Install Certbot
    sudo apt install certbot python3-certbot-nginx -y

    Obtain SSL Certificate

    Obtain Certificate
    sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

    Certbot will automatically modify your Nginx configuration to enable HTTPS and redirect HTTP traffic.

    Verify Auto-Renewal

    Verify Renewal
    # Test renewal process
    sudo certbot renew --dry-run
    
    # Check the timer status
    sudo systemctl status certbot.timer
    8

    PHP-FPM Optimization

    Configure PHP-FPM Pool

    Edit PHP-FPM Config
    sudo nano /etc/php/8.3/fpm/pool.d/www.conf

    Adjust settings based on your VPS memory (for 4GB RAM):

    PHP-FPM Pool Settings
    pm = dynamic
    pm.max_children = 50
    pm.start_servers = 10
    pm.min_spare_servers = 5
    pm.max_spare_servers = 20
    pm.max_requests = 500
    
    ; Process idle timeout
    pm.process_idle_timeout = 10s

    PHP Configuration

    Edit php.ini
    sudo nano /etc/php/8.3/fpm/php.ini

    Update these values:

    php.ini Settings
    upload_max_filesize = 64M
    post_max_size = 64M
    memory_limit = 256M
    max_execution_time = 60
    max_input_time = 60
    opcache.enable=1
    opcache.memory_consumption=256
    opcache.interned_strings_buffer=16
    opcache.max_accelerated_files=10000
    opcache.validate_timestamps=0
    opcache.save_comments=1
    Restart PHP-FPM
    sudo systemctl restart php8.3-fpm
    9

    Queue Workers and Task Scheduler

    Configure Supervisor for Queue Workers

    Install Supervisor
    sudo apt install supervisor -y

    Create a Supervisor configuration for Laravel queues:

    Create Supervisor Config
    sudo nano /etc/supervisor/conf.d/laravel-worker.conf
    Supervisor Configuration
    [program:laravel-worker]
    process_name=%(program_name)s_%(process_num)02d
    command=php /var/www/laravel-app/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
    autostart=true
    autorestart=true
    stopasgroup=true
    killasgroup=true
    user=deployer
    numprocs=2
    redirect_stderr=true
    stdout_logfile=/var/www/laravel-app/storage/logs/worker.log
    stopwaitsecs=3600

    Start Queue Workers

    Start Workers
    sudo supervisorctl reread
    sudo supervisorctl update
    sudo supervisorctl start laravel-worker:*

    Configure Task Scheduler

    Setup Cron
    # Edit crontab for deployer user
    crontab -e
    
    # Add this line
    * * * * * cd /var/www/laravel-app && php artisan schedule:run >> /dev/null 2>&1
    10

    Automated Deployment Script

    Create a deployment script to streamline future updates:

    deploy.sh
    #!/bin/bash
    set -e
    
    echo "Starting deployment..."
    
    # Navigate to application directory
    cd /var/www/laravel-app
    
    # Enable maintenance mode
    php artisan down --retry=60
    
    # Pull latest changes
    git pull origin main
    
    # Install PHP dependencies
    composer install --optimize-autoloader --no-dev
    
    # Install and build frontend assets
    npm ci
    npm run build
    
    # Run database migrations
    php artisan migrate --force
    
    # Clear and rebuild caches
    php artisan config:cache
    php artisan route:cache
    php artisan view:cache
    php artisan event:cache
    
    # Restart queue workers
    sudo supervisorctl restart laravel-worker:*
    
    # Disable maintenance mode
    php artisan up
    
    echo "Deployment completed successfully!"

    Make Executable

    Set Permissions
    chmod +x deploy.sh
    11

    Security Best Practices

    File Permissions

    Set Permissions
    # Set ownership
    sudo chown -R deployer:www-data /var/www/laravel-app
    
    # Set directory permissions
    find /var/www/laravel-app -type d -exec chmod 755 {} \;
    
    # Set file permissions
    find /var/www/laravel-app -type f -exec chmod 644 {} \;
    
    # Writable directories
    chmod -R 775 /var/www/laravel-app/storage
    chmod -R 775 /var/www/laravel-app/bootstrap/cache
    
    # Secure environment file
    chmod 600 /var/www/laravel-app/.env

    Install Fail2Ban

    Install Fail2Ban
    sudo apt install fail2ban -y
    sudo systemctl enable fail2ban
    sudo systemctl start fail2ban

    Additional Security Headers

    Add these to your Nginx server block:

    Security Headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header Content-Security-Policy "default-src 'self';" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
    12

    Monitoring and Backups

    Laravel Log Rotation

    Create Logrotate Config
    sudo nano /etc/logrotate.d/laravel
    Logrotate Configuration
    /var/www/laravel-app/storage/logs/*.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 0640 deployer www-data
        sharedscripts
    }

    Database Backup Script

    backup-db.sh
    #!/bin/bash
    # /home/deployer/backup-db.sh
    
    BACKUP_DIR="/home/deployer/backups"
    DATE=$(date +%Y%m%d_%H%M%S)
    DB_NAME="laravel_app"
    DB_USER="laravel_user"
    DB_PASS="your_secure_password"
    
    mkdir -p $BACKUP_DIR
    
    mysqldump -u$DB_USER -p$DB_PASS $DB_NAME | gzip > $BACKUP_DIR/db_$DATE.sql.gz
    
    # Keep only last 7 days of backups
    find $BACKUP_DIR -name "db_*.sql.gz" -mtime +7 -delete

    Schedule the backup:

    Schedule Backup
    # Add to crontab
    0 2 * * * /home/deployer/backup-db.sh
    RamNode Block Storage

    Consider using RamNode Block Storage for storing backups. It provides reliable, high-performance storage that persists independently of your VPS.

    13

    Troubleshooting

    Quick Reference Commands

    TaskCommand
    Restart Nginxsudo systemctl restart nginx
    Restart PHP-FPMsudo systemctl restart php8.3-fpm
    Restart Queue Workerssudo supervisorctl restart laravel-worker:*
    Clear All Cachesphp artisan optimize:clear
    Rebuild Cachesphp artisan optimize
    View Laravel Logstail -f storage/logs/laravel.log
    Run Migrationsphp artisan migrate --force
    Enable Maintenancephp artisan down
    Disable Maintenancephp artisan up

    Conclusion

    Congratulations! You have successfully deployed a Laravel application on your RamNode VPS with a production-ready configuration including Nginx web server, PHP-FPM, MySQL database, Redis caching, SSL encryption, queue workers, and automated deployment capabilities. Remember to regularly update system packages, monitor logs, keep dependencies updated, and test your backup strategy.