Knowledge Base

Browse our knowledge base for free solutions to common problems

Easily Set Per User PHP FPM Disable Functions Within DirectAdmin

Created On: 20 May 2025
Written by: Ben

Introduction

The disabled_functions directive in php.ini is used to disable certain PHP functions that may pose a security risk (e.g., exec, shell_exec, system, etc.). This is typically used to harden shared hosting environments, such as DirectAdmin

In this article we look through the limitations of disable_functions within DirectAdmin and look at a workaround for setting customised disable_functions per-user within DirectAdmin.

Limitations in DirectAdmin with PHP-FPM & Secure PHP

PHP-FPM uses a shared php.ini pool

  • PHP-FPM pools are typically configured per-user or per-domain, but they often share global configuration values from the main php.ini or common pool configuration.
  • While per-user php-fpm.conf files exist, disabled_functions is not always reliably honored or isolated when overridden per user.

disable_functions is not modifiable via .user.ini or php_value

  • disabled_functions is a PHP INI_SYSTEM level directive.
  • This means it can only be set in php.ini or FPM pool configuration, not via .htaccess, .user.ini, or php_value.

DirectAdmin and Secure PHP restrict overrides

  • When Secure PHP is enabled in DirectAdmin:
    • The system enforces strict defaults (e.g., via templates like: /usr/local/directadmin/data/templates/php-fpmXX.conf).
    • Any attempt to customize disabled_functions per user is usually overwritten by Secure PHP’s enforcement mechanism.
    • Users cannot bypass these settings even if they modify custom configs or use php_admin_value.

Template Limitations

  • DirectAdmin does not offer a GUI-level override for per-user disabled_functions.
  • Customizations require manual template editing (custom/php-fpmXX/) and rebuilding configs.
  • Even then, per-user overrides are tricky to manage and error-prone due to how Secure PHP applies default security profiles.

Conflicts with hardened permissions

  • Secure PHP often disables or locks down file access (open_basedir, disable_functions, etc.).
  • Changing disabled_functions could inadvertently weaken security policies intended for all users on the server.

Script To Set Custom Disable Functions & Bypass Limitations

The following script can be used to set custom disable_functions per-user within DirectAdmin:


#!/bin/bash
# Author: Ben (ICTU LTD)
# Email: [email protected]
# Filename: custom_per_user_disable_functions_php_fpm.sh
# Description: This DirectAdmin modification will allow you to have custom PHP disable functions per user when using php-fpm.
#              By default his functionality is not allowed in DirectAdmin and disable functions are inherited from server wide conf.
#              If you have a weak server wide configuration with limited fuctions disabled this will not be required and addition 
#              functions can be blocked using the control panel (see reading below).
#              Using this script will allow you to use Secure PHP and have custom disable functions per user with ease.
# Reading:
#          [01] https://docs.directadmin.com/webservices/php/php-fpm.html
#          [02] https://docs.directadmin.com/webservices/php/secure-php.html
#          [03] https://forum.directadmin.com/threads/cant-enable-exec-functions.56391/
#          [04] https://forum.directadmin.com/threads/enable-exec-function-in-php-just-for-1-user.72640/
#          [05] https://forum.directadmin.com/threads/limit-disable_functions-for-one-user-domain.62875/

######################################################################################################################################
# HOW TO USE
######################################################################################################################################
# [01] Copy phpfpm_disabled_functions.mods to a user PHP directory in DirectAdmin:
# cp -a phpfpm_disabled_functions.mods /usr/local/directadmin/data/users/$USERNAME/php/phpfpm_disabled_functions.mods

# [02] Edit the file and remove the functions you wish to enable for the user:
# vim /usr/local/directadmin/data/users/$USERNAME/php/phpfpm_disabled_functions.mods

# [03] Allow this file to execute:
# chmod +x custom_per_user_disable_functions_php_fpm.sh

# [04] Run the file:
# sh /root/custom_per_user_disable_functions_php_fpm.sh

# GLOBAL VARIABLES
USERS_PATH=/usr/local/directadmin/data/users
PHP_PATH=php
CONFIG_FILE=phpfpm_disabled_functions.mods

################################################################################################################
# START: PROCESS FILE CHANGES
################################################################################################################
for USERNAME in $(ls -1 $USERS_PATH); do
    echo "======================================================================================================"
    echo  Processing user: $USERNAME
    echo "======================================================================================================"
    # SET VARIABLE FOR CUSTOM PHP DISABLED_FUNCTION FILE
    CUSTOM_CONFIG_FILE="$USERS_PATH/$USERNAME/$PHP_PATH/$CONFIG_FILE"
    if [ -e $CUSTOM_CONFIG_FILE ]; then
        echo "Custom disabled_functions modification file exists for username: $USERNAME"
        echo ""
        echo "File path: $CUSTOM_CONFIG_FILE"
        echo ""
        echo "Locating php-fpm configuration files for: $USERNAME"
        echo ""
        # SET VARIABLE FOR LOCATING PHP FPM CONFIG FILE SPECIFIC TO USER
        PHP_FPM_FILES=$(find "$USERS_PATH/$USERNAME/$PHP_PATH" -maxdepth 1 -type f -name 'php-fpm*.conf')
        if [ -n "$PHP_FPM_FILES" ]; then
            while IFS= read -r PHP_FPM_CONFIG_FILE; do
                echo "Working on applying changes to: $PHP_FPM_CONFIG_FILE"
                echo ""
                # READ THE FULL CONTENTS OF THE CUSTOM FILE (ESCAPING FOR SED)
                DISABLED_LINE=$(< "$CUSTOM_CONFIG_FILE")
                ESCAPED_LINE=$(printf '%s\n' "$DISABLED_LINE" | sed 's/[&/\]/\\&/g')
                sed -i.bak "s|^php_admin_value\[disable_functions\].*|$ESCAPED_LINE|" "$PHP_FPM_CONFIG_FILE"
                echo "Changes sucessfully applied to: $PHP_FPM_CONFIG_FILE"
                echo ""
            done <<< "$PHP_FPM_FILES"
        else
            echo "For some reason we cannot locate a PHP FPM config file for $USERNAME."
        fi
    else
        echo "No modifications file exists for user $USERNAME."
        echo ""
        echo ""
    fi
done
################################################################################################################
# END: PROCESS FILE CHANGES
################################################################################################################


################################################################################################################
# START: RESTART PHP FPM PROCESS
################################################################################################################
for PHP_VERSION in $(systemctl list-units --type=service | grep php-fpm |  awk '{print $1}'); do
    echo "======================================================================================================"
    echo  Detected PHP version: $PHP_VERSION
    echo "======================================================================================================"
    echo "Attempting to restart $PHP_VERSION"
    echo ""
    systemctl restart $PHP_VERSION
    sleep 5
    if systemctl is-active --quiet $PHP_VERSION; then
        echo "SUCCESS: PHP_VERSION is running after being restarted."
        echo ""
    else
        echo "FAILED: PHP_VERSION does not seem to be running. Please manually check the service."
        echo ""
    fi
    echo ""
done
################################################################################################################
# END: RESTART PHP FPM PROCESS
################################################################################################################

Example of phpfpm_disabled_functions.mods:

php_admin_value[disable_functions] = exec,system,passthru,shell_exec,escapeshellarg,escapeshellcmd,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname,mail

What the script does:

  1. Look for all DirectAdmin users
  2. Check to see if the users have phpfpm_disabled_functions.mods present in there config directory.
  3. If they do have the custom mods file apply these disabled_function preferences to per-user PHP-FPM configuration
  4. Restart PHP to apply the changes

How to use the script:

1. Copy phpfpm_disabled_functions.mods to a user PHP directory in DirectAdmin:

      cp -a phpfpm_disabled_functions.mods /usr/local/directadmin/data/users/$USERNAME/php/phpfpm_disabled_functions.mods

      2. Edit the file and remove the functions you wish to enable for the user:

      vim /usr/local/directadmin/data/users/$USERNAME/php/phpfpm_disabled_functions.mods

      3. Allow this file to execute:

      chmod +x custom_per_user_disable_functions_php_fpm.sh

      4. Run the file:

      sh /root/custom_per_user_disable_functions_php_fpm.sh

      Download Scripts

      You can download the scripts as a zip:

      Additional Reading

      You can read more about how DirectAdmin applies disable_functions using the following guides:

      You can check out our other useful guides by searching our Knowledge Base.

      ICTU LTD is a company registered England and Wales (Company No. 09344913) 15 Queen Square, Leeds, West Yorkshire, England, LS2 8AJ
      Copyright © 2025 ICTU LTD, All Rights Reserved.
      exit