Tech Verse Logo
Enable dark mode
Next-Gen Laravel Deployment: FrankenPHP + Octane on Ubuntu VPS

Next-Gen Laravel Deployment: FrankenPHP + Octane on Ubuntu VPS

Tech Verse Daily

Tech Verse Daily

4 min read

For years, the gold standard for Laravel deployment has been the Nginx + PHP-FPM stack. While reliable, it involves multiple moving parts and communication overhead.

Enter FrankenPHP. Built on top of the Caddy web server, FrankenPHP is a modern PHP application server that supports HTTP/2, HTTP/3, and "Worker Mode" natively. When paired with Laravel Octane, it keeps your application in memory, eliminating the need to boot the framework on every request and resulting in staggering performance gains.

This guide will walk you through deploying a production-ready Laravel environment on an Ubuntu 24.04 VPS.

Why Choose FrankenPHP over Nginx?

  • Single Binary: No need to manage separate Nginx and PHP-FPM services.

  • Worker Mode: Keeps Laravel "booted" in RAM for millisecond response times.

  • Automatic SSL: Built-in Caddy integration handles Let's Encrypt certificates automatically.

  • Modern Protocols: Native support for 103 Early Hints and HTTP/3.

Step 1: Server Preparation

SSH into your VPS and ensure your system is up to date.

sudo apt update && sudo apt upgrade -y
sudo apt install -y git curl unzip software-properties-common

Step 2: Install FrankenPHP Binary

We will download the static FrankenPHP binary, which contains its own optimized PHP environment.

cd ~
curl -L https://github.com/dunglas/frankenphp/releases/latest/download/frankenphp-linux-x86_64 -o frankenphp
chmod +x frankenphp
sudo mv frankenphp /usr/local/bin/frankenphp

Step 3: Install PHP CLI and Composer

Even though FrankenPHP handles the web requests, you still need the PHP CLI on your server to run migrations, artisan commands, and Composer.

sudo apt install -y php8.3-cli php8.3-curl php8.3-mbstring php8.3-xml php8.3-zip php8.3-sqlite3 php8.3-bcmath php8.3-intl

# Install Composer
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer

Step 4: Deploy Your Application

Navigate to your web directory and set up your project.

sudo mkdir -p /var/www
sudo chown $USER:www-data /var/www
cd /var/www
git clone https://github.com/your-repo/laravel-app.git .
composer install --no-dev --optimize-autoloader

Essential Permissions

For FrankenPHP to serve your files safely, the www-data user must own the project.

sudo chown -R www-data:www-data /var/www
sudo chmod -R 775 storage bootstrap/cache

Step 5: Configure Laravel Octane

Octane is the bridge that allows Laravel to run inside the FrankenPHP worker.

  1. Install Octane: composer require laravel/octane

  2. Install the Driver: php artisan octane:install --server=frankenphp

  3. Optimize: php artisan optimize

Step 6: Create the Systemd Service

To ensure your API stays online 24/7 and restarts after a server reboot, create a systemd service.

sudo nano /etc/systemd/system/frankenphp.service

Paste the following configuration:

[Unit]
Description=FrankenPHP Laravel Octane Server
After=network.target

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www
# We use port 8000 here; use 80/443 if you have no other web server
ExecStart=/usr/local/bin/frankenphp php-server --port=8000 --root-dir=/var/www/public
# Alternatively, if using Octane's worker mode:
# ExecStart=/usr/bin/php /var/www/artisan octane:start --server=frankenphp --host=0.0.0.0 --port=8000
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

Activate the service:

sudo systemctl daemon-reload
sudo systemctl enable frankenphp
sudo systemctl start frankenphp

Step 7: Finalizing the Network

If you are using AWS, DigitalOcean, or Azure, ensure your Security Groups or Firewall allow traffic on port 8000.

Production Maintenance Checklist

When you push new code to your server, follow this sequence to avoid downtime or stale caches:

  1. Pull latest code: git pull

  2. Update dependencies: composer install --no-dev

  3. Run migrations: php artisan migrate --force

  4. Clear/Rebuild cache: php artisan optimize

  5. Restart Octane: sudo systemctl restart frankenphp

Troubleshooting FAQ

Q: I get "Permission Denied" on the logs. A: Ensure the www-data user has write access to your storage folder and your database file (if using SQLite).

Q: My changes aren't appearing on the site. A: Because Octane keeps the app in memory, it doesn't "see" code changes automatically. You must restart the service (systemctl restart frankenphp) for code changes to take effect.

Q: How do I enable HTTPS? A: If you point your domain directly to the VPS and run FrankenPHP on port 80/443, it will automatically provision a Let's Encrypt SSL certificate for you.

    Latest Posts

    View All

    Handling Large File Uploads in Laravel: A Guide to Chunking & Resuming

    Handling Large File Uploads in Laravel: A Guide to Chunking & Resuming

    Next-Gen Laravel Deployment: FrankenPHP + Octane on Ubuntu VPS

    Next-Gen Laravel Deployment: FrankenPHP + Octane on Ubuntu VPS

    Speed Up Your Laravel App: Mastering Concurrent API Requests with Http::pool and Batch

    Speed Up Your Laravel App: Mastering Concurrent API Requests with Http::pool and Batch

    Beyond the Basics: Building Production-Ready APIs with Laravel

    Beyond the Basics: Building Production-Ready APIs with Laravel

    PHP 8.6: Expected Release Window and RFCs to Watch

    PHP 8.6: Expected Release Window and RFCs to Watch

    Downloading Files from External URLs in Laravel

    Downloading Files from External URLs in Laravel

    Pause and Resume Laravel Queue Workers on Demand

    Pause and Resume Laravel Queue Workers on Demand

    Resume Canvas - Open Source Resume Builder

    Resume Canvas - Open Source Resume Builder

    Laravel Tyro: Complete guide to Authentication, Authorization, and Role & Privilege Management for Laravel 12

    Laravel Tyro: Complete guide to Authentication, Authorization, and Role & Privilege Management for Laravel 12

    CRITICAL: The "React2Shell" Vulnerability (CVE-2025-55182)

    CRITICAL: The "React2Shell" Vulnerability (CVE-2025-55182)