Kanboard is one of the leaner PHP applications you can host. A default install with SQLite or a small MySQL database ships as a few megabytes of code, has no bloated framework layer, and serves a project board with a handful of queries. So when a Kanboard site starts throwing 503 errors, stalling on login, or triggering resource-usage warnings in cPanel, the instinct to upgrade the plan is almost always premature. The application rarely needs more raw capacity. What it usually needs is a correctly sized PHP process pool, a database backend that matches the team's concurrency, and file storage that has not quietly filled the inode allocation.

The value of working through the actual bottleneck first is practical: a Cloud VPS costs more and shifts maintenance onto you, and if the underlying misconfiguration travels with the migration, the same symptoms reappear on hardware you are now paying more for. Everything below is done from an unprivileged hosting account using cPanel Jupiter or DirectAdmin Evolution, the PHP Selector, .user.ini, .htaccess, phpMyAdmin, and the Kanboard admin dashboard.

Reading the signals: which resource is actually saturated

Before changing anything, identify the constraint from data rather than guessing. cPanel exposes this directly. Open cPanel > Metrics > Resource Usage (on CloudLinux this is the LVE stats view). It reports whether you are hitting CPU (faults on the CPU line), physical memory (PMEM), entry processes (EP, concurrent PHP requests), or I/O and IOPS limits. DirectAdmin users find similar data under Statistics / Info and the account resource graphs. A single number matters most here: which limit shows a non-zero faults or throttled count. That is your bottleneck. Everything else is noise.

Map the fault type to a Kanboard behavior. Entry-process (EP) faults mean too many PHP requests ran at once and later requests were queued or refused, which surfaces as intermittent 508 or 503 pages when several team members load boards simultaneously. PMEM faults mean a single request tried to allocate more RAM than the account allows, common during CSV exports, large board rendering, or plugin-heavy installs. I/O and IOPS throttling points at disk activity, which for Kanboard almost always means a SQLite database on a busy board or verbose logging. CPU faults are the rarest for Kanboard and usually indicate a runaway cron job or an external bot hammering the login endpoint.

Correlate the timing with Kanboard's own logs. In File Manager, look at data/error.log inside the Kanboard document root and the per-directory error_log that PHP writes next to the executing script. PHP fatal errors such as Allowed memory size of ... exhausted confirm a PMEM/memory_limit problem; Maximum execution time exceeded points at slow queries or a locked SQLite file. Pair those timestamps with the Resource Usage graph spikes and the picture becomes concrete instead of speculative.

Tuning PHP limits and worker behavior without root

Kanboard's PHP needs are modest, but two defaults commonly cause trouble: a memory_limit that is too low for exports or too high for the account's concurrency, and an max_execution_time that lets a stuck request occupy an entry process far too long. On this platform you control these per-account through the PHP Selector (cPanel > Select PHP Version > Options) or by placing a .user.ini in the Kanboard root. Use a modern interpreter — set Kanboard to PHP 8.1 or 8.2 in cPanel > MultiPHP Manager, since older PHP releases use more memory per request and lack current OPcache improvements.

A sensible .user.ini for a Kanboard board serving a small-to-medium team:

; place in the Kanboard document root, e.g. /home/user/public_html/kanboard/.user.ini
memory_limit = 256M
max_execution_time = 60
max_input_time = 60
upload_max_filesize = 32M
post_max_size = 34M
opcache.enable = 1
opcache.memory_consumption = 64
opcache.max_accelerated_files = 10000
opcache.validate_timestamps = 1
opcache.revalidate_freq = 60

The counterintuitive lever for EP faults is not raising limits but lowering per-request weight so more requests fit inside the account's entry-process ceiling. A 256M memory_limit is generous for Kanboard; setting it to 512M or 1G simply lets one heavy request starve the pool. Enabling OPcache is the single most effective change because it removes repeated PHP compilation from every board load, cutting both CPU and memory per request. After editing, wait a minute for LiteSpeed to pick up the new .user.ini, then reload a board and confirm in a phpinfo() file that the values took effect.

Also protect the login endpoint. Automated login attempts against /index.php can generate a flood of PHP requests that eat your entry-process budget. A short .htaccess block in the Kanboard root reduces that pressure:

# Kanboard root .htaccess
<IfModule mod_headers.c>
  Header set X-Frame-Options "SAMEORIGIN"
</IfModule>

# block direct access to the data directory
RedirectMatch 404 /data/

# deny the SQLite file and config from the web
<FilesMatch "^(db\.sqlite|config\.php)$">
  Require all denied
</FilesMatch>

Database and I/O: the fix that eliminates most scaling requests

The most impactful change for a growing Kanboard install is moving off SQLite. Kanboard defaults to a single data/db.sqlite file, and SQLite serializes writes with a file-level lock. With one or two users this is fine; with a team dragging cards, adding comments, and refreshing boards concurrently, every write blocks every other write. That lock contention shows up as I/O throttling and database is locked errors in data/error.log, and it is frequently misread as a plan being too small when the real issue is the storage engine.

Migrate to MySQL/MariaDB using only account tools. In cPanel > MySQL Databases (or DirectAdmin > MySQL Management) create a database and user, then grant all privileges. Export the current SQLite data with Kanboard's built-in tooling, then edit config.php in the Kanboard root through File Manager:

<?php
// config.php
define('DB_DRIVER', 'mysql');
define('DB_USERNAME', 'user_kanboard');
define('DB_PASSWORD', 'your_password_here');
define('DB_HOSTNAME', 'localhost');
define('DB_NAME', 'user_kanboard');
define('DB_PORT', null);

Run the schema setup by loading the site once so Kanboard creates its tables, or import a prepared dump through phpMyAdmin > Import. MySQL uses row-level rather than file-level locking, so concurrent writes stop blocking one another and the I/O throttling that came from SQLite lock churn disappears. Inside phpMyAdmin you can also confirm the database is healthy: check the Status tab for slow queries and use the SQL tab to inspect table sizes if a board with thousands of tasks feels sluggish. Kanboard's schema is small and well indexed, so a genuinely slow query almost always means an oversized activity or comment table that can be trimmed through the admin dashboard.

Two more storage issues masquerade as needing a bigger plan. First, inodes: shared plans cap the number of files, and Kanboard's file attachments plus session files under data/ and tmp/ accumulate. Check cPanel > Statistics > File Usage (inodes). If you are near the ceiling, prune old attachments from within Kanboard and clear stale session and cache files rather than upgrading for storage you are not really out of. Second, logging: verbose debug logging writes to disk on every request. In Kanboard's config.php, keep DEBUG set to false in production so data/debug.log does not grow without bound and consume both inodes and I/O.

Confirming the fix and when a VPS is genuinely warranted

After applying OPcache, right-sized PHP limits, and the MySQL migration, return to Resource Usage and watch for 48 hours of normal use. In the large majority of Kanboard cases the fault counts drop to zero, because the application was never CPU- or RAM-bound in the first place — it was queue-bound on entry processes or lock-bound on SQLite. If the graphs stay clean during peak collaboration, you have solved the problem for the cost of a few config edits.

There are honest limits to what an unprivileged account can absorb. If your team routinely runs dozens of simultaneous active sessions, if you rely on many heavy plugins, or if you host Kanboard alongside other busy applications on the same account and the EP ceiling stays saturated even with OPcache and MySQL in place, you have reached the design edge of shared hosting. At that point a Cloud VPS is the right move, because you can raise the PHP process pool and database buffer sizes yourself. The distinction that matters: scale when a correctly tuned install still saturates a real limit, not when an untuned SQLite install stalls under its first bit of concurrency.