You deploy FuelPHP on hosting by pointing your document root at the project’s public/ folder, filling in fuel/app/config/db.php, setting FUEL_ENV to production, making fuel/app/logs and fuel/app/cache writable, and running php oil refine migrate. On shared hosting where you can’t move the docroot, an Apache rewrite into public/ is the workaround.
composer create-project fuel/fuel --prefer-dist . locally, commit the result, and deploy over Git or SFTP. Point the domain at /public, add SetEnv FUEL_ENV production to the .htaccess, chmod the logs and cache directories, then run migrations from the CLI. Budget time for the framework’s age, not the deployment.That said, plenty of working FuelPHP apps are still in production, and “rewrite it” is not a deployment plan you can execute this afternoon. So this guide does both jobs: a complete, correct deployment walkthrough, plus an honest read on the risk you’re carrying and what a migration would look like.
Where FuelPHP actually stands
| Question | Verified answer, July 2026 |
|---|---|
| Latest stable release | 1.9.0 on Packagist, published 28 December 2021 |
| What the official site advertises | 1.8.2, described as a bugfix release |
| FuelPHP 2.0 | Alpha only, never shipped; roadmap last touched September 2014 |
| PHP version in composer.json | >=5.4 |
| What the docs claim | “PHP 5.3.3 or greater. PHP 7 is fully supported.” No PHP 8 statement. |
| What the GitHub README claims | The 1.8/master branch is described as fully PHP 8.0 compatible |
| Realistic PHP target | PHP 8.0 or 8.1. Expect deprecation noise above that. |
Notice the contradiction: the documentation says PHP 7, the repository README says PHP 8.0, and composer says 5.4. That gap is itself the diagnosis. Nobody is curating this.
The security implications, stated plainly
An unmaintained framework means nobody is issuing patches. FuelPHP’s last public security fix, SEC-CORE-009, shipped in 1.8.2. If a vulnerability is found in the router, the ORM’s query building or the session handler tomorrow, there is no release to upgrade to. You would be patching vendor code yourself.
Two concrete problems you will hit:
- PHP end-of-life pressure. PHP 8.1 is out of active support and 8.2 is security-only through the end of 2026. FuelPHP has no verified support for 8.3, 8.4 or 8.5. So you either run the app on an aging PHP, which your host will eventually retire, or you run it on a modern PHP and fix the deprecations yourself.
- Stale dependencies. Older FuelPHP installs pull packages that no longer receive updates. The Crypt class historically wanted the mcrypt extension, which PHP removed in 7.2; FuelPHP falls back to PHPSecLib, and the version pinned in your
composer.lockmay be years old. Runcomposer auditand read the output honestly.
Practical mitigation for an app you can’t rewrite yet: put it behind a web application firewall, keep PHP as current as it will tolerate, turn off framework error output in production, restrict the database user to only the privileges the app uses, and treat every user-facing form as if the framework’s protections might not hold.
Server requirements that actually work
FuelPHP is undemanding, which is one reason old installs survive. You need Apache 2.4 with mod_rewrite, or Nginx with PHP-FPM. No PHP extensions are strictly mandatory, but in practice install mbstring, fileinfo, pdo_mysql and openssl. MySQL or MariaDB is the normal database.
The one thing you genuinely want is CLI access, because oil is how you run migrations and clear caches. Most shared hosts give you a non-root SSH shell, which is enough. If yours doesn’t, you’ll be running migrations by importing SQL by hand, which works but is miserable. A cheap VPS with root, set up the way our guide to launching CyberPanel on Hostinger describes, gives you a per-site PHP version selector and a real shell for about the same money as a mid-tier shared plan.
Step 1: Create the project locally
There are two supported ways to scaffold a FuelPHP app. Composer is the one to use.
# Recommended: Composer creates everything in the current directory
mkdir myapp && cd myapp
composer create-project fuel/fuel --prefer-dist .
# Alternative: the oil installer, *nix only
curl -L https://get.fuelphp.com/oil | sh
oil create myappThe oil route wraps Composer, sets directory permissions for you and only works on Linux, macOS and other Unix-likes. The Composer route is the one to prefer, because it is also what you’ll run in CI and because get.fuelphp.com is one more piece of aging infrastructure to depend on. Whichever you pick, do it on your machine, not on the production server. Committing a working composer.lock matters more than usual here, because you do not want Composer resolving fresh versions of a decade-old dependency tree during a deploy.
Step 2: Get the code onto the server
Git is the better option when your host supports it. Commit the whole project including composer.lock, exclude the contents of fuel/app/logs, fuel/app/cache and fuel/app/tmp, then on the server:
cd ~/apps
git clone git@github.com:you/myapp.git
cd myapp
composer install --no-dev --prefer-dist --optimize-autoloaderIf Composer isn’t available on the server, run composer install --no-dev locally and upload the vendor/ directory along with everything else. That is exactly the scenario FuelPHP’s docs call out as the reason to use create-project in the first place.
Over SFTP, upload the full tree in binary mode and preserve the directory structure. Do not upload public/ alone. The framework lives outside it and the bootstrap resolves relative paths from there.
Step 3: The document root question
This is where most FuelPHP deployments go wrong, and it is the single most important part of this guide.
FuelPHP splits the project into two halves. public/ holds index.php, assets and the .htaccess. fuel/ holds the framework, your application code, your config files including database credentials, and your logs. Only public/ should ever be reachable over HTTP.
On a VPS or anywhere you control the vhost
# Apache
<VirtualHost *:80>
ServerName example.com
DocumentRoot /home/deploy/apps/myapp/public
<Directory /home/deploy/apps/myapp/public>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
# Nginx
server {
server_name example.com;
root /home/deploy/apps/myapp/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
fastcgi_param FUEL_ENV production;
include fastcgi_params;
}
}That’s the correct setup. Nothing outside public/ is served, ever.
On shared hosting where the docroot is fixed at public_html
You have two options, and one of them is better than the other.
Option A, the rewrite. Put the project one level above public_html if your host allows writing there, and make public_html a symlink to myapp/public. Many cPanel hosts permit this and it is the cleanest shared-hosting answer. If symlinks are blocked, upload the project inside public_html/myapp/ and add an .htaccess at the public_html root that rewrites everything into the app’s public folder, plus rules that block direct access to the framework:
SetEnv FUEL_ENV production
RewriteEngine On
# Never serve the framework, app code, config or logs
RewriteRule ^myapp/fuel/ - [F,L]
RewriteRule ^myapp/(composer\.(json|lock)|oil)$ - [F,L]
# Everything else goes through the app's public folder
RewriteCond %{REQUEST_URI} !^/myapp/public/
RewriteRule ^(.*)$ myapp/public/$1 [L]Option B, moving public/ contents up. FuelPHP’s own installation docs describe this: move the contents of public/ into your host’s document root, then edit the path constants near the top of index.php so APPPATH, COREPATH and PKGPATH resolve to the new location of fuel/. It works, and it survives hosts that disable symlinks and mangle rewrites. The downside is that you now have a hand-edited file that a naive redeploy will overwrite. Document it in your README.
/fuel/app/config/db.php into your browser’s address bar. If you see anything other than a 403 or 404, your database credentials are on the public internet right now. Fix the rewrite before anything else.Step 4: Configure the database and the environment
FuelPHP merges two config files: the base fuel/app/config/db.php and an environment-specific override at fuel/app/config/production/db.php. Put real credentials only in the environment file.
<?php
// fuel/app/config/production/db.php
return array(
'default' => array(
'type' => 'mysqli',
'connection' => array(
'hostname' => 'localhost',
'port' => 3306,
'database' => 'user_myapp',
'username' => 'user_myapp',
'password' => 'put-it-in-an-env-var-if-you-can',
'persistent' => false,
),
'table_prefix' => '',
'charset' => 'utf8mb4',
'enable_cache' => true,
'profiling' => false,
),
);Then tell FuelPHP which environment it is in. On Apache this goes in the .htaccess that serves the app:
SetEnv FUEL_ENV productionOn Nginx it is a fastcgi_param FUEL_ENV production; inside the PHP location block, as in the vhost above. The variable name is uppercase and the value is lowercase. Valid values are development, test, staging and production, plus any custom name with a matching folder under fuel/app/config/.
Getting this wrong is why so many FuelPHP sites leak stack traces. In development, FuelPHP prints full error output including file paths and sometimes query fragments. Confirm the variable is landing by checking that a deliberate 404 renders a plain error page rather than a debug panel.
Step 5: File permissions
Three directories need to be writable by the user PHP runs as:
cd /home/deploy/apps/myapp
chmod -R 775 fuel/app/logs fuel/app/cache fuel/app/tmp
chown -R deploy:www-data fuel/app/logs fuel/app/cache fuel/app/tmp
# Verify PHP can actually write there
php -r "var_dump(is_writable('fuel/app/logs'));"On shared hosting where PHP runs as your own user, 755 is usually enough and 775 is unnecessary. Never use 777. FuelPHP writes daily log files into dated subdirectories under fuel/app/logs, so the parent must be writable, not just present. An unwritable logs directory is one of the most common causes of a blank white page, because the framework fails while trying to record the error that would have told you what happened.
Step 6: Run migrations
Migrations live in fuel/app/migrations/ with numeric prefixes, like 001_create_users.php. Run them from the project root, not from public/.
# Bring the database up to the latest migration
php oil refine migrate
# Step forward or back one migration
php oil refine migrate:up
php oil refine migrate:down
# Target a specific version
php oil refine migrate --version=10
# Include modules and packages
php oil refine migrate --all
php oil refine migrate --modules=admin,billing --default
# Ask oil what it supports on your version
php oil refine migrate:helpThe oil CLI reads the same environment variable. If your shell doesn’t have it, prefix the command: FUEL_ENV=production php oil refine migrate. Take a database dump first. FuelPHP migrations have no dry-run mode.
Should you migrate off FuelPHP?
Probably, on a timeline measured in quarters rather than weeks. Here’s how the realistic targets compare, with versions verified in July 2026.
| Framework | Current version | PHP requirement | Migration effort from FuelPHP | Pick it when |
|---|---|---|---|---|
| CodeIgniter 4 | 4.7.3, May 2026 | PHP 8.2+ | Lowest. Similar MVC shape, similar mental model, shared-hosting friendly. | You want out fast and the app is small to mid-sized |
| Laravel | 13.x, July 2026 | PHP 8.3+ | Moderate. Eloquent maps reasonably onto Fuel’s ORM; queues, jobs and auth are rewrites. | You want the largest ecosystem and easiest hiring |
| Symfony | 8.0.x, 2026 | PHP 8.4+ | Highest. Doctrine and the DI container are a genuinely different way to think. | Long-lived enterprise app, predictable LTS matters most |
| CakePHP | 5.x | PHP 8.1+ | Moderate. Convention-heavy like Fuel, so a lot of instinct transfers. | You liked Fuel’s conventions and want the same feel, maintained |
My recommendation for most inherited FuelPHP apps is CodeIgniter 4 if the goal is minimum time to a supported stack, and Laravel if you expect to keep investing in the product for years. CakePHP is the underrated middle option, and it deploys cleanly on managed platforms, as our walkthroughs of running CakePHP on cloud hosting and installing CakePHP on Cloudways cover.
Whatever you choose, migrate incrementally. Put the new app behind the same domain on a different path prefix, move one route group at a time, and share the database until the last controller is gone. A big-bang rewrite of a business-critical app is how these projects die twice.
Troubleshooting
A blank page or a 500 with no message
Check the web server error log first, then fuel/app/logs. If the logs directory is empty and its permissions are wrong, that is your answer. Temporarily set display_errors = On in a local php.ini, reproduce, then turn it straight back off. A 500 on a brand-new deploy is usually a missing vendor/ directory or a PHP version mismatch.
Every URL except the homepage 404s
mod_rewrite is off, or AllowOverride is set to None so your .htaccess is being ignored. On a VPS, run a2enmod rewrite, restart Apache, and set AllowOverride All on the directory. As a stopgap, FuelPHP will serve index.php/controller/action style URLs without rewriting, which is a useful way to confirm the app itself works before you go hunting through Apache config.
Fuel\Core\PhpErrorException
This is FuelPHP wrapping a native PHP error or warning into an exception, so the message after the class name is the real error. Undefined array keys, passing null where a string is expected, and implicit float-to-int conversion all surface this way on newer PHP versions. It is the most reliable signal that your PHP is newer than the framework expects. Read the file and line, fix the specific call, and if the trace lands inside fuel/core/ rather than your own code, drop back one PHP minor version while you plan a migration.
The /fuel/ directory is browsable
Your document root is one level too high. Fix the vhost or the rewrite as described in step 3. Until you can, add a defensive .htaccess inside fuel/ containing Require all denied for Apache 2.4, and rotate your database password, because you should assume it was read.
Cached config or routes won’t update
Delete the contents of fuel/app/cache, keeping the directory itself. Add that to your deploy script so it happens on every release.
Frequently asked questions
Is FuelPHP still maintained in 2026?
No, not in any practical sense. The last stable release on Packagist is 1.9.0 from December 2021, the official site still lists 1.8.2, and the 2.0 roadmap has not been updated since 2014. Existing apps still run, but nobody is shipping fixes, so treat it as legacy code you own outright.
What PHP version should I run a FuelPHP app on?
PHP 8.0 or 8.1 in practice. The framework’s composer.json only requires 5.4, the docs claim PHP 7 support, and the GitHub README claims PHP 8.0 compatibility. Nothing verifies 8.3 or later, and you should expect deprecation warnings escalating into fatal errors as you climb.
Should the document root point at /public or the project root?
Always at /public. Pointing it at the project root exposes fuel/app/config/db.php, your logs and your application source over HTTP. On shared hosting where you can’t change the docroot, symlink public_html to the public folder, or rewrite into it and explicitly deny /fuel/.
Can I deploy FuelPHP without SSH access?
Yes, but painfully. Upload the whole tree including vendor/ over SFTP, and run migrations by exporting the resulting schema locally and importing the SQL through phpMyAdmin. You lose oil, which also means losing easy cache clearing and task running.
What does composer create-project fuel/fuel actually install?
It downloads the FuelPHP application skeleton plus fuel/core and the default packages into the directory you name, and runs composer install for you. Add --prefer-dist to pull archives rather than Git history, which is faster and smaller.
Wrapping up
The deployment itself is not hard: create-project locally, ship the tree, point the docroot at /public, set FUEL_ENV, fill in the production db.php, make logs and cache writable, migrate. An hour, start to finish, once you’ve done it once. Verify the current install steps in the official FuelPHP installation docs and check the release history yourself on the fuel/fuel Packagist page.
The hard part is the decision you make afterward. Running an unmaintained framework on an aging PHP is a slow-moving problem, right up until your host retires that PHP version and gives you thirty days’ notice. Pick a migration target now, get one route group moved this quarter, and stop adding new features to the Fuel side. That’s a manageable plan. Waiting until something breaks is not.
About this article: GeekBlog covers U.S. technology news, AI, phones, smartwatches and gaming. Every story is written and checked under our Editorial Policy. Spotted a mistake or have a story tip? Contact our editors.

