Skip to content

Deploy a Laravel App ​

A walkthrough for getting a Laravel application running on AidiPanel, from a fresh site to a live app with SSL. This assumes your app already exists in a Git repository — either your own project or something you're deploying from a template.

Before you start:

  • AidiPanel is installed and you can log into the panel
  • Your Laravel app is in a Git repository you can clone from the server (public repo, or SSH/token access set up for a private one)
  • A domain pointed at your server

1. Create the site ​

bash
sudo aidipanel site:add --domain myapp.com --user myapp --type laravel

Using --type laravel (rather than plain php) matters here: it tells AidiPanel to point the Nginx vhost's document root at public/ instead of the site root, which is exactly where Laravel expects incoming requests to land.

This creates the dedicated Linux user myapp, an isolated PHP-FPM pool running as that user, and the web root at /home/myapp/htdocs/myapp.com.

2. Clone and install ​

bash
sudo -u myapp -H bash -lc '
  cd /home/myapp/htdocs/myapp.com
  git clone https://github.com/your/repo.git .
  composer install --no-dev --optimize-autoloader
'

The trailing . on git clone clones directly into the current (already-created) directory instead of making a new subfolder. --no-dev skips dev-only dependencies (test frameworks, debug tools) you don't want on production; --optimize-autoloader speeds up class loading for a real deployment.

No Composer on the server yet?

AidiPanel's default install doesn't assume every site needs Composer. If composer isn't found, install it directly: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer.

3. Configure the environment ​

bash
sudo -u myapp -H bash -lc '
  cd /home/myapp/htdocs/myapp.com
  cp .env.example .env
  php artisan key:generate
'

Now edit .env and fill in your database credentials (create the database first if you haven't — see Site Management → Installing WordPress, step 3 for the equivalent db:add pattern, it's identical for Laravel):

bash
sudo aidipanel db:add --name myapp_db --user myapp_db_user

This prints a generated password once — save it, then put it straight into .env:

dotenv
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=myapp_db
DB_USERNAME=myapp_db_user
DB_PASSWORD=<the generated password>

4. Run migrations ​

bash
sudo -u myapp -H bash -lc 'cd /home/myapp/htdocs/myapp.com && php artisan migrate --force'

Add --seed if your app ships seeders you want run on first deploy. If this fails with a connection error, double-check the four DB values above — same troubleshooting path as WordPress: Permissions & Database.

5. Fix ownership and storage permissions ​

bash
sudo chown -R myapp:myapp /home/myapp/htdocs/myapp.com
sudo -u myapp chmod -R u+rwX /home/myapp/htdocs/myapp.com/storage
sudo -u myapp chmod -R u+rwX /home/myapp/htdocs/myapp.com/bootstrap/cache

Laravel writes logs, compiled views, and cache files into storage/ and bootstrap/cache/ constantly — if PHP (running as myapp) can't write there, you'll get a 500 with a permissions error in storage/logs/laravel.log the moment the app tries to do anything.

Don't chmod 777

775 is enough since PHP-FPM already runs as the owning user (myapp) — there's no other process on the box that needs write access to these folders. 777 opens them to every user on the system for no benefit.

6. Set production mode ​

In .env:

dotenv
APP_ENV=production
APP_DEBUG=false

Never leave APP_DEBUG=true in production

With debug mode on, an unhandled exception dumps a full stack trace — including your .env values — straight to the browser. Turn it off before you point real traffic at the site.

Then cache the config and routes for a speed boost:

bash
sudo -u myapp -H bash -lc '
  cd /home/myapp/htdocs/myapp.com
  php artisan config:cache
  php artisan route:cache
  php artisan view:cache
'

Remember to clear these after every deploy

If you update .env or your routes later and the app doesn't seem to notice, you likely have a stale cache from this step. Re-run php artisan config:clear && php artisan route:clear (or re-run the :cache versions after your change) — this is one of the most common "why isn't my change showing up" moments in Laravel specifically.

7. Install SSL ​

bash
dig +short myapp.com   # confirm DNS has propagated first
sudo aidipanel ssl:install --domain myapp.com --email admin@myapp.com

8. The scheduler (if your app uses one) ​

If your app has scheduled tasks, Laravel needs one cron entry. Add it through AidiPanel so it is validated and installed in the site's own crontab:

bash
printf '%s\n' 'cd /home/myapp/htdocs/myapp.com && php artisan schedule:run >> /dev/null 2>&1' |
sudo aidipanel cron:add --domain myapp.com --schedule '* * * * *'

Running it as myapp (rather than root) keeps it consistent with the same isolation model as everything else — the scheduler can only touch what that site's user can touch.

Done ​

Your Laravel app is live, migrated, and served over HTTPS with an isolated PHP-FPM pool. A few things worth knowing as you keep working on it:

  • Redeploying: git pull, composer install --no-dev, re-run any new migrations, then php artisan config:cache route:cache view:cache again. Consider scripting this as a small deploy.sh in the repo.
  • Switching PHP version: see PHP Management if your app needs a specific version.
  • FastCGI Cache: Laravel apps are usually far more dynamic/session-heavy than a WordPress blog, so full-page caching is rarely a fit — the FastCGI Cache exclusion rules already skip logged-in and cookie-bearing requests, but you may want to leave page cache off entirely for an authenticated app and rely on Laravel's own caching (config:cache, query caching, Redis) instead.