Laravel is one of the most popular frameworks for building self-hosted PHP products — admin panels, SaaS platforms, CRMs, and more. Here's how to protect a Laravel application's source code before shipping it to customers.
What to Protect (and What Not To)
Not every file in a Laravel project needs protection. Here's a practical breakdown:
Protect these:
app/Services/— Your core business logicapp/Http/Controllers/— Request handling and orchestrationapp/Models/— Eloquent models with business rulesapp/Actions/orapp/Jobs/— Domain-specific operations
Skip these:
config/— Customers need to edit configurationresources/views/— Blade templates that customers might customizeroutes/— Route files that customers might extenddatabase/migrations/— Need to be readable for troubleshootingpublic/— Static assets, no PHP logic
Step 1: Create a CompileLock Project
Sign up at compilelock.com and create a project in the dashboard. Each project gets a unique encryption key — this means different products have different keys, and a license for Product A can't decrypt Product B.
Step 2: Install the CLI
curl -fsSL https://compilelock.com/install.sh | sh
compilelock auth --token="YOUR_API_KEY"
Step 3: Configure Protection
Create a compilelock.json in your Laravel project root:
{
"project_id": 1,
"include": [
"app/Services",
"app/Http/Controllers",
"app/Models",
"app/Actions"
],
"exclude": [
"app/Http/Controllers/Api/WebhookController.php"
],
"output": "./dist"
}
The exclude array lets you skip specific files — useful for webhook handlers that need to be inspected by payment providers, or controllers that customers should be able to modify.
Step 4: Build the Protected Version
compilelock protect --config=compilelock.json
This creates a dist/ directory with your protected files. Non-PHP files (Blade templates, config, etc.) are copied as-is. PHP files in the include paths are compiled to bytecode and encrypted.
Step 5: Prepare for Distribution
Your distribution package should include:
- The
dist/output (protected PHP + unmodified non-PHP files) - All files not in the include paths (config, views, routes, migrations, etc.)
composer.jsonandcomposer.lock— so the customer can install dependencies- Installation documentation
You do not ship the license file. Each customer gets their own license through your CompileLock dashboard.
Step 6: Customer Installation
On the customer's server:
# 1. Install the CompileLock extension
curl -fsSL https://compilelock.com/install-ext.sh | sh
# 2. Deploy your application normally
composer install --no-dev
php artisan migrate
php artisan config:cache
# 3. First request triggers the activation screen
# Customer enters their license key in the browser
When the customer visits the application for the first time, the CompileLock bootstrap detects that no license file exists and displays an activation screen. The customer enters their license key, the system validates it against your API, and if valid, creates a local license file and starts the application.
Handling Updates
When you release a new version, simply re-run the protection step and distribute the updated files. The customer's existing license continues to work — licenses are tied to the project, not to specific file versions.
CI/CD Integration
You can automate protection in your deployment pipeline:
# In your GitHub Actions / GitLab CI
- name: Protect source
run: |
curl -fsSL https://compilelock.com/install.sh | sh
compilelock auth --token="${{ secrets.COMPILELOCK_TOKEN }}"
compilelock protect --config=compilelock.json
- name: Package release
run: |
tar czf release-v${{ github.ref_name }}.tar.gz dist/