Customizing workflow

DirectAdmin has numerous features that allow the admin to change how it looks, what it can do, and how it does things.

The areas that can be customized are described below.

The pre/post sh scripts

The pre/post sh scripts are "hooks" which you can create for most common functions that DirectAdmin does. For example, when creating a DirectAdmin User, if you wish to add some extra functionality, you can use the user_create_post.shopen in new window to add code to perform some function with root access. A you might have guessed, the post scripts run after that task, and the pre scripts run before the task. The pre scripts are handy because if you exit the script with a non-zero return code, DA will halt and not execute that task.

There are numerous scripts available. Search the versions system for the list of available scripts:

There are also numerous examples on how to use these scripts in the KnowledgeBase:

Commands allow and deny

The commands.allow and commands.deny files are per-User files that let you specify which commands you wish to allow and/or deny for a User. The functionality is similar to the script, but without the ability to check the values of variables. It's much simpler in that you just drop in command names, so there is no need for scripting.

There is also a feature (as of DA 1.40.2) called Login Keysopen in new window that can also restrict what commands a user is allowed to execute.

The Login Keys feature allows one account the ability to have multiple passwords to login. However, these new passwords can be heavily restricted on several criteria, including its own commands.allow/deny files, connecting IP, expiry, and number of uses.

Feature Sets

Packages already give control over limits and other features. However, it does not (easily) allow for control over which CMD values are allowed in the account.

"Feature Sets" allow easy selection of various sets, which can be added together.

This affects both user.conf and packages. The user.conf file and User packages will have a new optional variable:


where the values on the right are only an example (no default value).

Submitting a blank "features_set=" for packages/user customization will delete the variable from the file.

The values must be colon separated, no spaces, and must exist. Any bad/missing sets are ignored without errors being thrown.

All feature sets will live here:


where each set is a directory.

Each set directory will have a file commands.allow which acts like the usual commands.allow files (no commands.deny at the moment).

Custom sets can be added to this path using different names, OR you can override the default sets by creating a copy in a custom folder:


Some default sets exist in /usr/local/directadmin/data/templates/feature_sets/ already and may include:

  • dns_only : Users can control their dns records.
  • email_only: All E-Mail related functions
  • tickets: Allows use of the Message and Ticket System
  • view_domain: A base set so User can view the domain overview, stats, change passwords and logout (this set is recommended, but not required if it's API only)
  • core_functions: A combination of the view_domain and tickets feature sets

Example feature set

Here's an example of how you could create your own feature set. First off, either create a new directory under /usr/local/directadmin/data/templates/feature_sets or copy an already existing one:

cd /usr/local/directadmin/data/templates/feature_sets
cp -rp core_functions example_set

This will create a feature set called example_set that already contains all the commands necessary for core functionality. If you go to that directory:

cd example_set

You'll find commands.allow. This is the file that will determine what commands a user with this feature set will be able to run in DirectAdmin's control panel.

Most of the commands that can be added to commands.allow can be found hereopen in new window.

Another option would be to make use of directadmin's debug mode to determine the command your newly added feature set should include. Login as an unrestricted user and click on a feature inside the web panel. You'll see what command was used to load that page. Then you'll just need to add it to your commands.allow file.

So for example, run directadmin in debug mode. In your DirectAdmin control panel click "Domain Setup". You'll see a lot of output being dumped to your terminal. Including the command that's used to access "Domain Setup". In this case it would be /CMD_DOMAIN.

Click hereopen in new window to learn how directadmin can be run in debug mode:

Once you're finished adding all the commands to commands.allow, you'll be able to use this feature set by going to: Admin Level -> Show All Users -> example_user -> Modify -> Feature Sets -> Allow Selected -> check example_set -> Save

This will add this feature set to only one user, but the same can be done to a user package: Admin Level -> Manage User Packages -> either modify or create new package -> Feature Sets -> Allow Selected -> check example_set -> save


Plugins are scripts which you create, allowing you to let your Users to do tasks, but only with the process level of their own user ID*.

The main benefit of plugins is their ability to be installed with 1 click, work on any OS, any Skin, without needing to do any other modifications to your setup. They're also "safe" in the sense that the calls made by a plugin run only as the User, and not root.

*You can get root access with a plugin if you create a plugin binary with chmod 4755, but this can be a huge security risk if done incorrectly, and thus is not usually recommended unless you're completely confident in your secure coding abilities.

Plugins as Package Items

The plugin manager has the ability to enable/disable each plugin in the package in new window

All plugins will be enabled by default, and only shut off on a per-user basis if they're set as such by the system.

Packages exist in your system here (replace USERNAME and PACKAGE_NAME as desired): /usr/local/directadmin/data/users/USERNAME/packages/PACKAGE_NAME

And the user.conf file exists here (replace USERNAME with your desired user): /usr/local/directadmin/data/users/USERNAME/user.conf

A disabled plugin will not be able to run through CMD_PLUGINS/CMD_PLUGINS_ADMIN/CMD_PLUGINS_RESELLER

The following is an example of what you will see set in the packages/user.conf to permit access to only certain plugins:


Alternatively, you may see this to deny certain plugins:


The logic behind which plugins are allowed and which are denied is as follows:

  • If both plugins_allow and plugins_deny are absent from a package, all plugins can run.
  • If plugins_allow exists (even if it's blank), the plugin must be present in order to run ("plugins_allow=" will block any plugin from running).
  • If plugins_deny exists, any plugin listed will be denied.
  • Having both plugins_allow and plugins_deny has no purpose, as plugins_allow will be the 100% deciding factor.

To clear a plugin for a given list pass [clear] to the value, e.g.,




will delete the given variables from the package/user.conf.

Again, setting "plugins_allow=" to an empty value does not delete the variable, it simply sets it as blank, thus no plugins can run.

Saving a package or user.conf change without passing the plugins_allow (or plugins_deny) will have no effect on the value currently set (in case some skins don't support it).

DirectAdmin API

The DirectAdmin API is a tool that lets your own scripts connect to DirectAdmin to perform certain tasks. The scripts can be local or even remote relative to the DirectAdmin install. The scripts would essentially be an imitation of a web browser, in that the calls made to DA with the CMD_API functions will pass the data in the same format as a browser (99% of the time). The only difference between CMD and CMD_API calls is the data that DirectAdmin returns is parsable. Be sure to search the version system for a listing of all API commandsopen in new window because not all CMD_API commands are listed in the api.html page.

Custom domain/package items

Custom Domainopen in new window/Packageopen in new window items let you add options to all Reseller/User packages or domains. They can be any of the typical input types. You can then combine the scripts such as, and to do things like take an action based on these custom package/domains items.

Custom package items will be saved into the reseller.conf and user.conf files, so your scripts determine which actions to take from the contents of these conf files. Custom domain items are saved in file.

Limiting Custom Item Restore to Admin

The Custom Domain Items featureopen in new window now has a new option which can be added to any value inside /usr/local/directadmin/data/admin/custom_domain_items.conf where you can append:


so that, when restoring the custom domain items values from the User's backup, the backup/ custom value will only be restored if:

  1. admin_restore_only=yes is not present in the global config, or
  2. admin_restore_only=yes is present in the global config, and the restore is being done via the Admin Level.

When an item has admin_restore_only=yes set, neither triggering the restore from Reseller Level nor User Level will restore the given custom item line from the domain.conf in the backup.

Custom per-User/Reseller widgets

The user.conf and reseller.conf support the ability to control which widgets are allowed to be shown.


  • widgets=ON blank/missing is the same default value
  • widgetes=OFF all widgets disabled, not likely to get much use
  • widgets=ON:WGT_DB|WGT_PLUGINS_HELLO_WORLD only allows these 2 widgets
  • widgets=OFF:WGT_DB disables only WGT_DB, all other widgets are still allowed

At this time, it's not an interface/package item, but you can control it with the custom packageopen in new window items.


For the Evolution skin, just use the "Customize Evolution Skin" feature in the panel.

If you would like to create/edit custom skin files manually, please note that Evolution skin uses a default skin.conf at /usr/local/directadmin/data/skins/evolution/skin.conf.

You may create custom skin.conf file at /usr/local/directadmin/data/users/CREATOR/skin_customizations/evolution/skin.conf. If this custom skin.conf path exists, it will be read in, overriding any variable that exists.

For example, if you want to reduce the number of widgets available to a User, you'd need to only add the line:


with the desired widgets.

Any User created under "CREATOR" (eg: admin), will have this custom list, instead of the default list. You do not need to copy the whole skin.conf, just the line(s) you wish to override.

For other, Enhanced-like skins, these allow the easiest form of control over what the User physically sees. This is good for basic hiding of features, or removing links to areas that you've disabled (if not already hidden). A good starting point would be skin customization from Reseller level (of admin) > Customize Evolution Skin.

Or to create your own skin is to copy ours, e.g.,

cd /usr/local/directadmin/data/skins
cp -Rp evolution yourskin

where yourskin is the name of the skin you will be creating.

Note that the skins support embedded scriptingopen in new window (php, perl, etc.,) as well as a basic if-then-else systemopen in new window, allowing for a "more efficient" method of checking variables and controlling what data to show.

Relating to skins are the language packs for enhanced or evolution skins.

Also, if you want to change the display of one of DirectAdmin's hard-coded items, like a table, you'd have to use this guide.

To change the appearance of the login page, see this guide.

To change one page of a skin without copying the entire skin, and have the changes safe from update overwrites, use this guide.

General DirectAdmin options

There are hundreds of options for DirectAdmin, each to accomplish a different functionality. Please be very careful if you chose to make changes to your directadmin.conf. Always make note of what you add or change and what the previous value was, just in case you need to undo your changes.

Combining all for E-Mail only type package

The following outlines how you can combine multiple DA features to accomplish a goal. For this particular goal, though, the Feature Sets is now available as an option and is likely the most suitable for this.

Say you want to control which CMDs are valid in a given account, and control this in a package. This can be done using a combination of above features, e.g.,

  • Custom Package Items to set up the choice in the package.
  • The and hooks to take action after the account is changed.
  • And the commands.allow and/or commands.deny to be the final list of settings that govern what the User can do based on the selected option in the package.

Let's say we want an "E-mail Only" type package. So we'll use the commands.allow to only list commands needed for this.

  1. Create the file /usr/local/directadmin/data/admin/custom_package_items.conf with content:
account_allow=type=listbox&item1txt=All Features&item1val=all&item2txt=E-Mail Only&item2val=email&string=Select Featureset&desc=Ability to select core features&default=all

This should let your packages show 2 options (you can add more if needed), just note that we're naming it "account_allow" and when "account_allow=all" is used, that's when we restrict things.

  1. Create a hook to control what happens when a User is set to a given "account_allow" option. Create the /usr/local/directadmin/scripts/custom/ file with the following code:
if [ "${account_allow}" = "email" ]; then
      cp -f /root/allows/email.list $CA
if [ "${account_allow}" = "" ] || [ "${account_allow}" = "all" ]; then
       rm -f $CA
exit 0;

And make it executable with:

chmod 755 /usr/local/directadmin/scripts/custom/
  1. Create the /root/allows/email.list file which will contain email-related commands:

Adjust this however you need. Alternatively, you could invert it to control commands.deny. For example, if you want a 100% block of CMD_DB_* functions, just list all CMD_DB* and CMD_API_DB calls (although, simply setting a max of 0 databases would accomplish the same).

  1. Relating to the, there is a hook script. Since you may want to turn a feature on/off, we need this too, but since the literally does the same thing, we can simply create a symlink to it:
cd /usr/local/directadmin/scripts/custom
ln -s

That's basically it. You can now select the "E-Mail Only" option from the package or for a given User, and it will apply this commands.allow file to them. We'd also recommend setting all other related functions to 0 (e.g., Max: 0 databases, 0 FTP accounts, etc.,) as applicable.

Which tokens are available in the template/skin?

Anytime you're working with anything that uses tokens, you may want to know which tokens are available. Some tokens are always present, others can be variable depending on scenarios or config settings. Sifting through documentation can often be tedious, but we do have a "magic" tokenopen in new window, we call:


which can be added to any file you're working on.

When DA then processes or generates this file, it will dump all tokens that are currently available into this token. The format is one line per token=value.

NOTE: this will typically break things, like Apache httpd.conf files, so you'd usually only use it for testing purposes and quickly remove it once you have the info you're looking for.

For skin, plugins, or anything that gives you html output, I often use it like this:


How to use logical && and || in a template?

If you're trying to write template codeopen in new window and realized that the template code is too simplistic for what you need, no need to worry because it can still be done.

Before you jump into the guide below, see if the template you're using supports scripts, as that will make your life much easier: in new window

If not, we'll break down the logical operators for && and || in the DA template form.


The equivalent code for

if (A == "1" && B == "1")

in DA template form, would be:

|*if A!="1"|
|*if B!="1"|
|*if TRUE="1"|

which is the same logical equivalent.


The equivalent code for

if (A == "1" || B == "1")

in DA template form, would be:

|*if A="1"|
|*if B="1"|
|*if TRUE="1"|

which is the same logical equivalent.


Normal code:

if (A == "1")
elseif (A == "2")
     //else something

would look like the following in template form:


|*if A="1"|

|*if A="2"|

//else something

NOTE: Pay special attention to the ! characters in the template comparisons, as well as the initializing values. They're the key to the logic being correct.

Last Updated: