Zikula sits on top of Symfony, Doctrine, and Twig, which means an upgrade touches far more than a handful of files. A point release moves vendor libraries, runs Doctrine schema migrations against your live database, rebuilds the Symfony cache, and re-registers every installed module through the extension system. When any one of those steps fails partway through on a shared account, you are left with a half-migrated database and a cache that no longer matches the code on disk. The site then throws HTTP 500 errors or a blank Symfony error page, and there is no root shell to repair it from the server side.

The current 3.x branch (3.0.4 and 3.1.0 being the last published builds) is based on Symfony 5 and is no longer actively maintained upstream, so there is no auto-updater quietly fixing mistakes for you. Every upgrade you perform is a manual, deliberate operation. That is actually an advantage for a hosting user: because the whole application is self-contained in your account under public_html plus one MySQL database, you can capture a complete, restorable snapshot before you touch anything, and you can rehearse the entire procedure in a staging copy. This walkthrough keeps every action inside cPanel Jupiter, DirectAdmin Evolution, phpMyAdmin, File Manager, and the Zikula bin/console runner available through your hosting account.

Capture a complete, restorable snapshot first

A Zikula backup has exactly two parts: the full document root and the single application database. Skip either and the restore will not work, because the code and the schema version must agree. Start with the files. In cPanel open Files → File Manager, navigate to the parent of your Zikula install (usually /home/USERNAME/public_html), select the installation folder, and use Compress to produce a .tar.gz archive named with the date, for example zikula-pre-upgrade-2026-10-22.tar.gz. In DirectAdmin the equivalent is System Info & Files → File Manager, where selecting the folder exposes the Add to Archive action. Download that archive to your local machine with the File Manager Download button so a copy lives off the server.

Pay special attention to a few paths that hold your real state and must survive any restore: app/config/ (your services_custom.yaml and generated parameters), web/uploads/ or public/uploads/ depending on the build, and any custom themes or modules under modules/ and themes/. The var/cache/ and var/log/ directories do not need preserving; they are regenerated.

Next, export the database. Open phpMyAdmin from cPanel (Databases → phpMyAdmin) or DirectAdmin (Account Manager → MySQL Management → phpMyAdmin), select your Zikula database in the left tree, and choose Export. Use the Custom method so you can set these options explicitly:

Format:            SQL
Structure:         Add DROP TABLE / VIEW / PROCEDURE statement
Data:              Complete inserts
Compression:       gzipped
Charset:           utf8mb4

The Add DROP TABLE option matters: it lets you re-import over a damaged database cleanly instead of colliding with existing tables. Save the resulting .sql.gz next to your file archive. You now hold a matched pair that represents the known-good site, and a rollback is simply the act of putting both halves back.

Build a staging clone to rehearse the upgrade

Never run a first-attempt upgrade against production. Clone the site into a subdomain so a failure only affects a URL nobody is using. In cPanel go to Domains → Domains → Create A New Domain and add something like staging.yourdomain.com, pointing its document root to /home/USERNAME/staging. DirectAdmin users create the same thing under Account Manager → Domain Setup or the subdomain manager. Extract your backup tarball into that new directory with File Manager, then create a second empty database and user (cPanel MySQL Databases or DirectAdmin MySQL Management) and import your .sql.gz into it through phpMyAdmin.

Point the clone at its own database by editing the connection parameters. In Zikula 3.x this lives in app/config/services_custom.yaml (or the generated app/config/parameters.yaml on older builds). Open it in File Manager's editor and change the database name, user, and password to the staging credentials:

parameters:
    database_host: localhost
    database_name: USERNAME_zikstage
    database_user: USERNAME_zikstage
    database_password: 'your-staging-password'
    router.request_context.host: 'staging.yourdomain.com'

Before running any console command, confirm the PHP version. Zikula 3.x on Symfony 5 wants PHP 7.4 or 8.0/8.1. Set it per-domain in cPanel under Software → Select PHP Version (MultiPHP) or DirectAdmin's PHP Selector / Select PHP Version, and verify the pdo_mysql, intl, gd, mbstring, and zip extensions are enabled. Raise execution limits for the upgrade run by dropping a .user.ini into the staging document root, since the migration can be slow:

memory_limit = 256M
max_execution_time = 300

With the clone live, perform the actual upgrade there first and only promote the procedure to production once it completes cleanly.

Run the upgrade and verify before promoting

Replace the core code with the target release while keeping your own state intact. Download the new Zikula Core 3.x package, upload it to the staging folder through File Manager, and extract it so the framework and vendor files are refreshed. Do not overwrite your preserved app/config/, modules/ custom extensions, themes, or uploads. After the files are in place, clear and warm the Symfony cache, then run the upgrade routine. If your hosting plan exposes a Terminal in cPanel (Advanced → Terminal) or DirectAdmin, run these from the install root:

php bin/console cache:clear --env=prod
php bin/console zikula:upgrade --env=prod

The zikula:upgrade command applies Doctrine schema changes and re-runs each module's upgrade handler. If no Terminal is offered on your plan, the equivalent web routine is to visit https://staging.yourdomain.com/upgrade.php (the bundled upgrader), which performs the same migration steps through the browser and reports each module as it processes. Either way, watch for failures and tail var/log/prod.log or your account's error_log in File Manager for any Doctrine or extension exceptions.

Once staging reports a successful upgrade, log into the Zikula admin console at /index.php?module=ZikulaExtensionsModule and walk the Extensions list. Any module showing an "upgrade available" state must be upgraded individually from that screen so its database schema matches the new core. Click through the public pages, confirm the theme renders, test a login, and check that uploads still resolve. Only after the clone is clean do you repeat the identical file swap and console commands against production.

If production breaks despite the rehearsal, the rollback is mechanical and fast. Delete the production install folder in File Manager, extract your pre-upgrade tarball back into place, then in phpMyAdmin select the production database, use Operations → to empty it or simply import your .sql.gz (the DROP TABLE statements overwrite the broken schema), and clear var/cache/. Because your snapshot captured a matched code-and-schema pair, the site returns to its exact prior state. Keep the pre-upgrade archive and SQL dump for at least a week after the change in case a subtle module issue surfaces later. If outbound mail from Zikula stops working after the move, review your authenticated SMTP and DNS alignment settings, as upgrades sometimes reset mailer configuration.