Hook scripts

DirectAdmin pre/post hook scripts allow you to expand upon common DirectAdmin functions by adding your own custom scripting to the actions for which they are named for (or, more recently, for which their parent directory is named for). For example, when creating a DirectAdmin User, if you wish to add some extra functionality, you can use the user_create_post.sh to add code to perform some additional functionality with root access following successful user creation.

The post scripts run after that task, and the pre scripts run before the task.

The pre scripts are handy because they allow you to control CMD execution by specifying whether or not the task halts execution by exiting the script with a non-zero return code. If pre script returns non-zero exit, the command is not executed and error message gets generated.

Post scripts also generate error messages on non-zero exits. All stderr is piped to stdout for DA in all pre/post hook scripts.

Hook Script Locations

Hook scripts can be located in any of the following locations, which are listed below according to their order of execution:

  1. scripts/custom/<HOOK NAME>/*.sh (from version 1.60.0)
  2. scripts/custom/<HOOK NAME>.sh
  3. plugins/*/hooks/<HOOK NAME>.sh (from version 1.60.0)

If any script fails, the entire set is considered failed and therefore throws all generated error messages. This means that command execution fails when any one of the pre hooks for the CMD fails. "Result" (shell returns with 0) and "Error" (shell returns with 1) messages are passed and concatenated in "result" and "error" environment variables. If 2 scripts both throw errors/results, their outputs will be appended, so no output should be lost. All scripts will be run, even if one returned a non-zero result. If any one script returns an error, then the entire set of hooks will be an error (e.g., user_create_pre.sh would abort if any of them return a non-zero exit code).

Passing custom variables via POST/GET

There are many pre/post.sh scripts in DA, used as hooks for almost any action.

However, sometimes, you might want to give some custom variable to these scripts via GET or POST, without having to fight with the custom package items or other convoluted means.

The solution to this is to use an set of prefixed variables, that are exclusive to the scripts.

The directadmin.conf value hook_custom_vars can be used for this.

The internal default value is 0, which is disabled. To enable the feature, add it to your directadmin.conf, and set it to 1.

You can use any GET/POST variable name you want matching this regex pattern ^custom_var_[a-zA-Z_-]*$.

So, a sample variable, passed with GET or POST might be custom_var_do_something=yes, which would let you access $custom_var_do_something in any hook script that is called with that request.

Note that the maximum length of an environmental value is 125749 bytes. Anything greater than or equal to that length will be ignored, and its ENV variable will be unset if it was present already.

Ability to hide script file location in output

If you have custom scripts in /usr/local/directadmin/scripts/custom/*.sh for example, a non-zero exit status will usually lead to an error message similar to the following:

Script Output: /usr/local/directadmin/scripts/custom/script_name.sh

before echoing your echo'd data. This is typically done to avoid confusion as to what's throwing the error.

But if you're fully aware of it, and are sure you're echoing data on non-zero output, then you should be able to use the directadmin.conf variable show_custom_script_path to control this output.

The internal default is:


So, to hide the "Script Output" line, you'd add this to your directadmin.conf, and restart directadmin:


pipe_post for all pre/post.sh scripts

If you set ?pipe_post=yes in a request's query string, then the POST data will be sent to the pre/post.sh scripts via stdin.

DA will still try and load everything else into the ENV anyway, but long values are chopped according to length limits, so if you're trying to get everything from POST, this is how you'd do it.

DA will set env var POST="stdin=true" if the above has happened, so you know to check for it.

Include ?pipe_post=yes in the GET portion of the method=POST request, e.g.,

<form action='CMD_SOMETHING?pipe_post=yes' method='POST'>

Then in your script, the posted data can be read in like this:


if ($P == "stdin=true")
    echo "Got some info from stdin!!<br>";

    $data = '';

    $stdin = fopen('php://stdin', 'r');
    while (($buffer = fgets($stdin, 1024)) !== false)
        $data .= $buffer;
    if (!feof($stdin))
        echo "Error: unexpected fgets() fail";

    echo "Data: ".htmlspecialchars($data);



If you want the POST to always be set, regardless if a GET/POST has passed pipe_post=yes, then you can change the internal default value:


(to be set in the directadmin.conf) to something like this:


Which is a colon separated, no spaces, list of scripts that you want to force the post to be piped through. Of course, if no method=POST is done, this won't kick in.


If you do set pipe_post=true, but the script does not read any of it, you might run into a full stdin buffer, which may vary or might be fine. Just be sure to actually read the data if you're using the option, else DA may be trying to push data into a pipe with a full buffer. If your script quits, this should close the pipe and DA would stop sending, so in theory, it should be fine.

File Uploads won't show you the whole file, since that would already be stored in a temporary area. You'd get something like the file0 variable pointing to to the actual location on disk, prior to it being moved by DA (should that be the instructions called, e.g., FM file upload).

POST-only case

In some cases, like saving an edited file in the File Manager, GET cannot be used at all. An exception has been added where cases such that the custom variables passed to the .sh scripts may be a direct dump from the GET+POST already.

In these cases, when the full dump happens to be passed anyway (e.g., including the File Manager edit "save"), you can include:


to the POST value, and everything else should continue normally. Of course, this means you'll get pipe_post=yes passed in your POST data, but you'd just decode it anyway.

Shared environment variables

  • login_key_name:
    Name of the key used to login, if the login was done using a "Login Key". Note, that custom hooks scripts can be called by things that do not use a login at all, such as restores, for example. So there is no guarantee that it will be set if any of those other methods are used... not to mention all normal logins not using a login key. 😃

  • login_as_master_name:
    Anytime a login-as call is made for any pre-post script, an extra variable is added with the name of the master (logged in from). If login-as is not used, the variable will not exist at all.

always_load_all_script_env_vars for session variables

The all_pre.sh and all_post.sh will end up loading in some specific environmental variables.

In some cases, these still hang around for other custom hook scripts, which is sometimes useful.

The issue is that we might not want to impose the large overhead of these scripts, just to have those variables loaded.

Solution is a new internal variable, off by default:


So that when you turn it on in the directadmin.conf:


even if the all scripts are not present, DA will still load in the environmental variables from these scripts, so they might be available later on.

Last Updated: