./Deploy Laravel on VPS with Caddy.md
Getting your Laravel app live on a VPS doesn't have to be complicated. This guide walks you through deploying Laravel using Caddy web server, which handles SSL certificates automatically and has a much simpler configuration than Nginx or Apache.
What You Need
Ubuntu VPS (22.04 or 24.04)
A domain name
SSH access to your server
Your Laravel project
Step 1: Update Your System
Always start with a fresh package list:
sudo apt updateStep 2: Install PHP and Required Extensions
Laravel needs PHP along with several extensions to function properly. Install them all at once:
sudo apt install php php-cli php-common php-mysql php-zip php-gd php-mbstring php-curl php-xmlHere's what each extension does:
php-cli - Run artisan commands from terminal
php-mysql - Database connectivity
php-zip - Composer dependency management
php-gd - Image processing
php-mbstring - String handling for internationalization
php-curl - HTTP requests
php-xml - XML parsing (many packages require this)
Verify the installation:
php -vYou should see PHP 8.3.x (or your installed version).
Step 3: Install PHP-FPM
PHP-FPM (FastCGI Process Manager) is the recommended way to run PHP with modern web servers. It's more efficient and handles concurrent requests better:
sudo apt install php8.3-fpm php8.3-mysql php8.3-xml php8.3-curl php8.3-mbstring php8.3-zip php8.3-gd unzipEnable and start the service:
sudo systemctl enable --now php8.3-fpmStep 4: Install Composer
Composer manages PHP dependencies. Install it globally:
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composerConfirm it's working:
composer --versionStep 5: Upload Your Laravel Application
Navigate to the web directory:
cd /var/wwwClone your repository or upload your files:
git clone https://github.com/yourusername/your-repo.git laravel-app
cd laravel-appIf you're not using Git, you can upload files via SFTP to /var/www/laravel-app.
Step 6: Install Dependencies
Install PHP packages without development dependencies:
composer install --no-dev --optimize-autoloaderThe --no-dev flag skips testing and development packages, while --optimize-autoloader improves performance.
If your app uses Vite or another frontend build tool:
npm install
npm run buildStep 7: Configure Environment
Create your environment file:
cp .env.example .envEdit the file with your production settings:
nano .envImportant settings to update:
APP_ENV=productionAPP_DEBUG=false(critical for security)Database credentials (DB_HOST, DB_DATABASE, DB_USERNAME, DB_PASSWORD)
APP_URLwith your actual domainAny third-party API keys
Generate the application encryption key:
php artisan key:generateCreate the symbolic link for file storage:
php artisan storage:linkStep 8: Optimize Laravel
Cache your configuration files for better performance:
php artisan config:cache
php artisan route:cache
php artisan view:cacheThis compiles your config, routes, and Blade templates into cached files.
Step 9: Database Setup
Run your migrations:
php artisan migrate --forceThe --force flag is required in production environments.
If you need to seed initial data:
php artisan db:seed --forceStep 10: Set Correct Permissions
Laravel needs write access to specific directories. Set the correct ownership:
sudo chown -R www-data:www-data /var/www/laravel-app/storage
sudo chown -R www-data:www-data /var/www/laravel-app/bootstrap/cacheSet appropriate permissions:
sudo chmod -R 775 /var/www/laravel-app/storage
sudo chmod -R 775 /var/www/laravel-app/bootstrap/cacheThese permissions allow the web server to write logs, cache files, and uploaded content.
Step 11: Install Caddy
Add Caddy's repository and install:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddyStep 12: Configure DNS
Before configuring Caddy, point your domain to your VPS. Add an A record in your DNS settings:
Type: A
Name: blog (or @ for root domain)
Value: Your VPS IP address
TTL: 3600Step 13: Configure Caddy
Edit the Caddyfile:
sudo nano /etc/caddy/CaddyfileReplace the contents with your Laravel configuration:
blog.yourdomain.com {
root * /var/www/laravel-app/public
php_fastcgi unix//run/php/php8.3-fpm.sock
file_server
encode gzip
request_body {
max_size 10MB
}
header {
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
Referrer-Policy "no-referrer-when-downgrade"
-Server
}
log {
output file /var/log/caddy/blog.log
level INFO
}
}Key configuration elements:
root - Points to Laravel's public directory
php_fastcgi - Connects to PHP-FPM via Unix socket
file_server - Serves static assets (CSS, JS, images)
encode gzip - Compresses responses
request_body - Sets maximum upload size
header - Adds security headers
log - Enables access logging
Adjust max_size if you need to handle larger file uploads.
Step 14: Start Caddy
Reload Caddy with your new configuration:
sudo systemctl reload caddyCheck that it's running properly:
sudo systemctl status caddyYou should see "active (running)" status.
The best part? Caddy automatically obtains and renews SSL certificates from Let's Encrypt. No manual certificate management needed.
Step 15: Access Your Application
Open your browser and visit:
https://blog.yourdomain.comYou should see your Laravel application running with HTTPS enabled (green padlock in the address bar).
Troubleshooting Common Issues
502 Bad Gateway Error
This indicates PHP-FPM isn't running properly. Check its status:
sudo systemctl status php8.3-fpmIf it's not running, start it:
sudo systemctl start php8.3-fpm500 Internal Server Error
Check Laravel's logs for detailed error information:
tail -f /var/www/laravel-app/storage/logs/laravel.logCommon causes:
Incorrect file permissions
Database connection issues
Missing or misconfigured
.envfileCache issues (try clearing with
php artisan cache:clear)
Missing Images or Uploaded Files
The storage link might be broken. Recreate it:
cd /var/www/laravel-app
php artisan storage:linkCaddy Won't Start
Check Caddy's logs for configuration errors:
sudo journalctl -u caddy --no-pager | tail -50Common issues:
Domain not pointing to server yet
Port 80/443 already in use by another service
Syntax error in Caddyfile
Deploying Updates
When you need to deploy changes, follow this workflow:
cd /var/www/laravel-app
# Enable maintenance mode
php artisan down
# Pull latest changes
git pull origin main
# Update dependencies
composer install --no-dev --optimize-autoloader
npm install
npm run build
# Clear old caches
php artisan config:clear
php artisan cache:clear
php artisan view:clear
# Rebuild caches
php artisan config:cache
php artisan route:cache
php artisan view:cache
# Run new migrations
php artisan migrate --force
# Disable maintenance mode
php artisan up
# Restart PHP-FPM
sudo systemctl reload php8.3-fpmYou can save this as a shell script for faster deployments.
Wrapping Up
Your Laravel application is now live on your VPS with automatic HTTPS courtesy of Caddy. The setup provides a solid foundation for production hosting with minimal configuration overhead.
# Get new posts via email. No spam.
$ comments.log // 0 Comments
➜ ./add_comment.sh