Installation
Install FTP Deployer into the Laravel application you want to deploy.
Requirements
Local machine or CI
- PHP
^8.1|^8.2|^8.3according to package metadata. - Composer available on
PATH. - Laravel application using
illuminate/support^10|^11|^12|^13. - PHP
ext-ftpenabled. - Network access to the target FTP/FTPS server.
- Network access to the deployed application URL over HTTP/HTTPS.
Remote host
- FTP or FTPS account.
- Public HTTP/HTTPS access to the configured
app_url. - PHP version compatible with your Laravel app.
- Required Laravel PHP extensions:
openssl,pdo,mbstring,tokenizer,xml,ctype,json. - Existing
.envfile on the host. - Non-empty
APP_KEYinside that.envfile. - Writable
storagepath. - Writable
bootstrap/cachepath.
[!WARNING] The runner refuses to deploy if
.envis missing orAPP_KEYis empty. This is intentional. Secrets should already exist on the server and should not be sent in HTTP deploy payloads.
Install package
Choose one of the methods below to install the package into your Laravel application.
Option A: From Packagist (Standard)
From your Laravel application root:
composer require inja-online/ftp-deployer
Option B: From a local directory (Local Install)
Use this if you want to download or clone the package code directly and put it in a local directory inside your Laravel application.
-
Download or clone this repository and place the files in a local folder within your Laravel project, e.g.,
packages/ftp-deployer. -
Add a
pathrepository pointing to your local folder in your Laravel application’scomposer.json:
{
"repositories": [
{
"type": "path",
"url": "packages/ftp-deployer",
"options": {
"symlink": true
}
}
]
}
[!NOTE] Set
"symlink": falseif you want Composer to mirror/copy the package files instead of creating a symlink. This is useful in environments like Docker or shared hosts where symlinks might not be supported or desired.
- Run the require command:
composer require inja-online/ftp-deployer:dev-main
Option C: From custom GitHub repository
Use this when installing from a fork, private repo, or before a Packagist release.
- Add the repository to your Laravel app’s
composer.json:
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/inja-online/ftp-deployer"
}
]
}
- Then require the package:
composer require inja-online/ftp-deployer:dev-main
The package auto-discovers:
- Service provider:
inja-online\FTPDeployer\FTPDeployerServiceProvider - Facade alias:
FTPDeployer - Artisan command:
ftp-deploy
Publish config
php artisan vendor:publish --provider="inja-online\FTPDeployer\FTPDeployerServiceProvider" --tag=config
This creates:
config/ftp-deployer.php
If your Laravel version or publishing setup does not use tags for this package, run:
php artisan vendor:publish --provider="inja-online\FTPDeployer\FTPDeployerServiceProvider"
Verify command registration
php artisan list | grep ftp-deploy
Expected command:
ftp-deploy
There are no separate ftp-deploy:init, ftp-deploy:build, ftp-deploy:push, ftp-deploy:run, or ftp-deploy:cleanup commands in the current implementation. The single ftp-deploy command performs the full flow.
Prepare remote .env
Upload or create the remote .env file before first deploy.
Simple mode default location:
{ftp_root}/app/.env
Versioned mode default location:
{ftp_root}/app/shared/.env
Make sure it contains:
APP_KEY=base64:your-existing-app-key
APP_ENV=production
APP_DEBUG=false
APP_URL=https://laravelapp.inja.online
Add your database, queue, mail, cache, session, and service credentials directly on the host.
[!IMPORTANT] Do not rely on
key:generateduring deploy unless you understand the consequences. RegeneratingAPP_KEYcan invalidate encrypted cookies, sessions, password reset tokens, and encrypted data.
Prepare writable paths
The runner checks write access before executing commands.
Simple mode:
{ftp_root}/app/storage/
{ftp_root}/app/bootstrap/cache/
Versioned mode:
{ftp_root}/app/shared/storage/
{ftp_root}/app/releases/{release_id}/bootstrap/cache/
On cPanel, create folders with File Manager or FTP if they do not exist. Permissions vary by host, but PHP must be able to write to them.
Prepare public document root
Choose one path model:
Option A: simple mode
Point your domain document root at:
{ftp_root}/app/public
Use default paths:
FTP_DEPLOYER_MODE=simple
FTP_DEPLOYER_FTP_ROOT=/
FTP_DEPLOYER_APP_ROOT=app
FTP_DEPLOYER_PUBLIC_ROOT=app/public
FTP_DEPLOYER_APP_URL=https://laravelapp.inja.online
Option B: versioned mode
Point your domain document root at:
{ftp_root}/public_html
The deployer manages:
{ftp_root}/public_html/index.php
Use paths like:
FTP_DEPLOYER_MODE=versioned
FTP_DEPLOYER_FTP_ROOT=/
FTP_DEPLOYER_APP_ROOT=app
FTP_DEPLOYER_PUBLIC_ROOT=public_html
FTP_DEPLOYER_RELEASE_ROOT=app/releases
FTP_DEPLOYER_SHARED_ROOT=app/shared
FTP_DEPLOYER_CURRENT_PATH=app/current
FTP_DEPLOYER_APP_URL=https://laravelapp.inja.online
First dry run checklist
Before running deploy, confirm:
php artisan ftp-deploy productioncan read your profile.- FTP credentials work.
FTP_DEPLOYER_APP_URLopens the site domain, likehttps://laravelapp.inja.online.- Remote
.envexists. APP_KEYexists and is not empty.- Local frontend build output exists if your app uses Vite or Mix.
composer installworks locally.
Then run:
php artisan ftp-deploy production
Continue with Configuration for every profile key, then use Cookbook & Examples for frontend builds, no-frontend apps, custom Artisan setup commands, and CI recipes.