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.
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.
Initial Server Setup
Connect and Update
ssh root@your_server_ip
apt update && apt upgrade -yCreate a Deployment User
Running applications as root is a security risk:
# Create a new user
adduser deployer
# Add user to sudo group
usermod -aG sudo deployer
# Switch to the new user
su - deployerConfigure SSH Key Authentication
# 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_ipConfigure Firewall
# 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 statusInstalling Required Software
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 nginxInstall PHP 8.3 and Extensions
# 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 -vInstall 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 --versionInstall Node.js (Optional)
Required if your Laravel app uses Vite or npm packages:
# 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 -vInstall Redis (Optional)
Redis improves performance for caching, sessions, and queues:
# 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 pingDatabase Setup
Install MySQL 8.0
# 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_installationSecurity 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
# 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.
Deploying Your Laravel Application
Create Application 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-appClone Your 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 PHP dependencies (production mode)
composer install --optimize-autoloader --no-dev
# Install npm dependencies and build assets (if applicable)
npm ci
npm run buildConfigure Environment
# Copy example environment file
cp .env.example .env
# Generate application key
php artisan key:generate
# Edit environment file
nano .envUpdate your .env file with production settings:
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=6379Run Migrations & Set 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/cacheOptimize for Production
# 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:cacheConfiguring Nginx
Create Nginx Server Block
sudo nano /etc/nginx/sites-available/laravel-appAdd the following 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
# 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 nginxSSL Certificate with Let's Encrypt
Install Certbot
sudo apt install certbot python3-certbot-nginx -yObtain SSL Certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.comCertbot will automatically modify your Nginx configuration to enable HTTPS and redirect HTTP traffic.
Verify Auto-Renewal
# Test renewal process
sudo certbot renew --dry-run
# Check the timer status
sudo systemctl status certbot.timerPHP-FPM Optimization
Configure PHP-FPM Pool
sudo nano /etc/php/8.3/fpm/pool.d/www.confAdjust settings based on your VPS memory (for 4GB RAM):
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 = 10sPHP Configuration
sudo nano /etc/php/8.3/fpm/php.iniUpdate these values:
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=1sudo systemctl restart php8.3-fpmQueue Workers and Task Scheduler
Configure Supervisor for Queue Workers
sudo apt install supervisor -yCreate a Supervisor configuration for Laravel queues:
sudo nano /etc/supervisor/conf.d/laravel-worker.conf[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=3600Start Queue Workers
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-worker:*Configure Task Scheduler
# Edit crontab for deployer user
crontab -e
# Add this line
* * * * * cd /var/www/laravel-app && php artisan schedule:run >> /dev/null 2>&1Automated Deployment Script
Create a deployment script to streamline future updates:
#!/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
chmod +x deploy.shSecurity Best Practices
File 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/.envInstall Fail2Ban
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2banAdditional Security Headers
Add these to your Nginx server block:
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;Monitoring and Backups
Laravel Log Rotation
sudo nano /etc/logrotate.d/laravel/var/www/laravel-app/storage/logs/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 deployer www-data
sharedscripts
}Database Backup Script
#!/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 -deleteSchedule the backup:
# Add to crontab
0 2 * * * /home/deployer/backup-db.shRamNode Block Storage
Consider using RamNode Block Storage for storing backups. It provides reliable, high-performance storage that persists independently of your VPS.
Troubleshooting
Quick Reference Commands
| Task | Command |
|---|---|
| Restart Nginx | sudo systemctl restart nginx |
| Restart PHP-FPM | sudo systemctl restart php8.3-fpm |
| Restart Queue Workers | sudo supervisorctl restart laravel-worker:* |
| Clear All Caches | php artisan optimize:clear |
| Rebuild Caches | php artisan optimize |
| View Laravel Logs | tail -f storage/logs/laravel.log |
| Run Migrations | php artisan migrate --force |
| Enable Maintenance | php artisan down |
| Disable Maintenance | php 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.
