A missing PHP extension can remove database drivers, outbound HTTP support, image handling, or cache adapters even when the interpreter still starts cleanly. Enabling the right module restores the capability an application expects without replacing PHP itself or guessing at the wrong runtime.
Packaged Ubuntu and Debian builds keep each optional module definition under /etc/php/<version>/mods-available and load it per SAPI through runtime-specific /conf.d symlinks for environments such as cli, fpm, and apache2. phpquery reports which versions and SAPIs exist plus whether a module is enabled, while phpenmod creates the live symlink back to the shared module file for the selected runtime.
Current distro packages often enable a newly installed module automatically for every detected SAPI, so the usual job is to confirm the installed branch, install the matching package only when the module file is missing, and run phpenmod only when the target runtime still shows the module as disabled. Keep -v and -s explicit so the change stays limited to the intended PHP branch and SAPI, and expect custom source builds, Homebrew installs, bundled stacks such as XAMPP, and built-in extensions without a separate .ini file to require a different enablement path.
$ phpquery -V 8.3 $ phpquery -S -v 8.3 apache2 cli
Replace 8.3 with the installed branch on the host. Current Ubuntu 24.04 packages commonly report 8.3, while current Debian 12 packages commonly report 8.2.
Related: How to check PHP version
$ ls -l /etc/php/8.3/mods-available/curl.ini -rw-r--r-- 1 root root 68 Jan 27 03:09 /etc/php/8.3/mods-available/curl.ini
If the file is missing, install the matching extension package before trying phpenmod. Built-in extensions without a separate .ini file are not enabled through this helper flow.
$ sudo apt-get install --yes php8.3-curl Reading package lists... Done Building dependency tree... Done Reading state information... Done The following NEW packages will be installed: php8.3-curl 0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded. Setting up php8.3-curl (8.3.6-0ubuntu0.24.04.x) ... Creating config file /etc/php/8.3/mods-available/curl.ini with new version
Use the explicit versioned package such as php8.3-curl on hosts with multiple PHP branches so the module lands in the intended runtime tree.
$ phpquery -v 8.3 -s cli -m curl No module matches curl (Disabled for cli by local administrator)
A fresh package install often already reports Enabled for cli by maintainer script, Enabled for apache2 by maintainer script, or the matching status for the active runtime. If the query already reports Enabled, the module is active for that runtime and the next action is runtime verification.
Related: How to show loaded PHP extensions
$ sudo phpenmod -v 8.3 -s cli curl $ phpquery -v 8.3 -s cli -m curl curl (Enabled for cli by local administrator)
If -v or -s is omitted, phpenmod applies the change to every installed PHP version or every detected SAPI instead of only the intended runtime.
phpenmod creates the runtime-specific conf.d symlink back to /etc/php/8.3/mods-available/curl.ini.
$ sudo systemctl reload apache2
The CLI SAPI does not need a service reload because the next shell invocation reads the updated module list immediately. Use sudo systemctl reload php8.3-fpm when the extension was enabled for fpm instead of apache2.
$ phpquery -v 8.3 -s cli -m curl curl (Enabled for cli by local administrator) $ php -m | grep --ignore-case '^curl$' curl
Repeat the phpquery check with -s apache2 or -s fpm when the application runs behind a web server, because each SAPI reads its own configuration tree.
Related: How to show loaded PHP extensions
Related: How to find PHP configuration files