Version 1.54.0

Released: 2018-09-14

IDN: punycode domains new

Recognize IDN domains, and add required values to handle them.

New internal variable:


to enable it, set:


in your directadmin.conf and restart DA.

Note, your skin must be using UTF-8, else you'll run into issues.

By default the Enhanced skin does NOT use UTF-8, so use this to switch it over:

The Evolution skin doesn't need this feature, as it converts to punycode before passing any domain to DA.

Applies to adding Users, adding domains to existing Users, and adding domain pointers.

Existing domains will not be touched.

Future additions to this feature will include the ability to convert the punycode domain back to the original UTF-8 charset, for use in various areas displayed in DA.

The Evolution skin does not require this feature, as it encodes domains to punycode on the fly, before passing it to DA.

It also decodes the punycode after the value is sent to the skin (client-side for both cases in Evolution)

dnssec_add_subdomain_ds_to_parent to check Multi-Server Setup zones new

Relating to this option:

DNSSEC: automate adding subdomain's DS and NS records to parent zone

it only works if the top level domain is local.

This changes is not needed if the local parent zone copy is to be pushed remotely, which MSS already handles.

If the parent zone is on a remote MSS server, but not locally (one-way MSS dns), the MSS would need to push the DS records to the remote box.

new internal default:


which applies when DA cannot find any local parent, and there are 2 or more periods in the current zone name (as it could be a subdomain).

This can potentially slow down dns writes if it's a subdomain zone and dnssec + MSS is enabled, so we've provided the option to shut it off, if you know all parent zones are local.

The subdomain server, connects to CMD_API_DNS_ADMIN with the following request:


where, this combination of strings tells the remote box (that received the request) to try and figure out which zone subdomain belongs to.

If it cannot find the parent zone, it's not an error (error=0), but paren_exists=no is returned.


system_user_to_virtual_passwd new

New directadmin.conf, internal default:


The purpose of this is to include the system account in the virtual passwd file at


so you can login with

The main purpose was for the dovecot_proxy option, for remote email.

To enable, add:


to the directadmin.conf and restart DA.


the format of the Username line is the same as othes, except it points to /home/username, instead of /home/username/imap/

The password crypt is taken from the system function:

getspnam (getpwnam on FreeBSD)

so the crypt will match whatever is in the shadow file.

However, for User creation, or other methods where the plaintext password is known, a fresh crypt is made, so it might not match the /etc/shadow file.


This task.queue option has been updated to add the username if it's missing:

echo "action=rewrite&value=email_passwd" >> /usr/local/directadmin/data/task.queue


echo "action=rewrite&value=email_passwd&user=fred" >> /usr/local/directadmin/data/task.queue

Email: last password change time & IP new

New functionality, enabled by default:


Where anytime an email password is changed, either through DirectAdmin GUI (CMD_EMAIL_POP, CMD_API_EMAIL_POP, CMD_CHANGE_EMAIL_PASSWORD, etc), the time and IP will be saved into:


in the format:


If the above setting is set to 1, then for Enhanced, the hover-over usage will include this information.

If no password change has been made after this feature is present, no info will be shown.

JSON will also include the "last_password_change" array, similar to the "last_login" array, again only if present (known).

Absence of data does not imply it has not been recently changed (we don't know when DA was last updated).

So if you want to use this information to enforce a password change every 6 months (for example), we can only guarantee that the absence of data is more than 6 months, after using this feature for 6 months.

But a client can just reset their password to the same value again (if they wish) to update this time, and have it be shown.

Sample JSON output from CMD_EMAIL_POP:

    "account": "fred",
    "login": "fred",
        "apparent_usage": "23.374",
        "imap_bytes": "51482624",
            "ip": "",
            "when": "1535136909"
            "ip": "",
            "when": "1535140911"
        "quota": "100",
        "usage": "49.097",
        "webmail_bytes": "23"
        "send_limit": "42",
        "sent": "0"
    "suspended": "no"

will also include the "when" portion of the data, and will show up as a new variable:


which could be used by things like the RoundCube quota plugin to force a password update (in theory, the RC plugin does not currently force a password reset)

Show 2nd php on Server Info page new

CMD_SYSTEM_INFO will now show the 2nd php version, if set and installed, eg:

Php 7.0.28Installed

Php 5.6.30Installed (php2)

    "name": "php",
    "version": "7.0.28"
    "name": "php",
    "version": "5.6.30"




CMD_API_FTP extended=yes|no new

Previous CMD_API_FTP call didn't return all info, just the login and path.

New optional value, lets you call it like:


which changes the output to include the suspended details for the given ftp account:<encodedinfo>&<encodedinfo>

where <encodedinfo> would contain a sub-url encoded array like:



There is also already a JSON alternative with even more info:


https URLs for (SKINS) new

The "Help" buttons in DA will now only access https URLs.




both files, from:




Not a major issue if they're not changed in your custom skin. now has

Add inode count/limit to show_all_users.cache + CMD_API_ALL_USER_USAGE new

If you have:


set (which is enabled by default), the next time the show_all_users.cache is updated, it will now include the inode limits, in the same format as bandwidth, quota, etc.

Will not affect CMD_ALL_USER_SHOW output (possibly in the future)


To force a rebuild of the show_all_users.cache now, use:

echo "action=cache&value=showallusers" >> /usr/local/directadmin/data/task.queue

however, this should already be called automatically with the scripts/, so it shouldn't really be needed.

The nightly tally also does a full rebuild automatically.

Include Evolution into DirectAdmin update (SKINS) new

This release of DirectAdmin will include the new evolution skin:

As of September 12, 2018, the skin has now been announced as a Release Candidate.

There are no known bugs at the time of the inclusion, but there could still be bugs.

If you find any, please report them to the forum:


change to the enhanced/power_user style.css to show the RC version of the skin:

.skin_version {
    float: right;
    width: 20px;

.skin_version a {
    color: #C1C1C1;

and also added a hover option to the existing edit_cog:hover:

.edit_cog:hover, .skin_version:hover a {
    -webkit-filter: brightness(70%);
    -webkit-transition: all 0.5s ease;
    -moz-transition: all 0.5s ease;
    -o-transition: all 0.5s ease;
    -ms-transition: all 0.5s ease;
    transition: all 0.5s ease;

Allow absence of root domain in dovecot SNI setup fixed

For non wildcard certs, related error message:

"Cannot find domain in the certificate. Not setting up Mail SNI."

This check is still done, but has been changed to just throw the message:

"Cannot find domain in the certificate."

but will continue to write the;


without the entry in that file, if it's not in the cert.

The sni conf did and will continue to load in all cert values.


Show Effective DNS feature caused warning for remote value fixed

Bug with new feature:

Show effective DNS record value (trailing dot issue) (SKINS)

where it complained if the local zone name was not on the right side for things like MX/NS/CNAME values.

Remote domains should be allowed without a message.

This did not block any functionality, but did cause confusion for Users who wanted to use external values (eg: remote MX records)

LetsEncrypt: removed email field as there is only 1 LE account per server (SKINS) fixed

There is only one LetsEncrypt account per server (letsencrypt.key), thus only 1 email account is needed, per server.

The script 1.1.11 will read the email value from the Admin's user.conf file (or any other Admin if "admin" was removed).

As such, when the LetsEncrypt radiobox is selected, the email field is now hidden.

DA will also omit the email check when LetsEncrypt is used, and it's no longer passed to anything.

The san_configs created for LetsEncrypt will also no longer have the emailAddress field.



User action locking to prevent race conditions fixed

If a backup is running, and you try to suspend or delete an account, interesting things can happen.

New feature, internally enabled by default with:


will prevent the account from being suspended or deleted during a backup.

To disable this feature, you can set it to the following in the user.conf file:


The value of the user_action_locking setting represents minutes of patience.

If the lock file is older that 30 minute, DA will assume something went wrong and clear the lock so another lock can be created.

Any of those 3 actions can create this lock.

Whoever goes first will win.

For now, deletion/suspension blocks will not be pushed to the background for later action, they'll just return a lock error, telling the caller to try again later.

Note that the lock of an Account for backups only happens at the start of that account backup, not the start of the entire run.

So you could issue a delete after a list of Users are being backed up (before the User is question is backed up), which will delete the User.

This would then return a backup error, since the User would have vanished.


killUserProcesses: was not killing User processes fixed

Bug was introduced into the code on December 13, 2017, released in DirectAdmin 1.53.0 on March 14, 2018.

The function to kill all User processes aborted early due to incorrect UID check.

Related error message;

killUserProcess::Cannot find home directory for user 'username'. Does this User exist?

Don't overwrite on DA update fixed

Related to thread:

The has a copy stored in the update.tar.gz pack.

I've removed the script from the update.tar.gz, so custombuild will be 100% in control of the initial install.

No changes are needed to enable LetsEncrypt:

MySQL install to check /root/.mysql_secret, if needed fixed

In order to update the default MySQL install to a newer version (specifically for CentOS 6) the newer MySQL 5.6 (vs older 5.5) version sets a default password, rather than a blank one.

The has been updated in order to check for the /root/.mysql_secret if the initial setting of the root password failed.

It also address that default password as expiring immediately,

so it uses the SET PASSWORD option with --connect-expired-password to reset to the mysql=PASS value from the setup.txt, using the /root/.mysql_secrets value.

After this version of DA is released, we'll be able to update the default CentOS 6 MySQL version to 5.6 (which can still be converted to MariaDB, if desired)

Note, to convert to MariaDB, there are some "rules" that you should follow, since MySQL 5.6 cannot go to MariaDB 5.5, eg:

Notify Users about existing LetsEncrypt auto-renewal when they overwrite with a pasted cert/key pair fixed

Some confusion with regards to the "Disable Auto-Renew" feature:

LetsEncrypt: disable auto-renew (SKINS)(LANG)

has come up where clients forget to do that when a new cert/key pair is saved.

The reason for not disabling the auto-renew upon the paste/save was that clients would click it with the current live/cert, which shouldn't change anything.

However, sometimes they do paste in a new value, so they'll need to know if they should disable the auto-renew or not.

This change will give them a notification after they past a cert/key and click save, but only if there is a future auto-renew still setup.

After clicking "Save", they'll be shown:

Certificate and Key Saved.

Note: the previous Let's Encrypt config is still set to renew in %d days.

If you do not wish to overwrite the current certificate, please disable the auto-renewal

and if json is not used, it will add this below that:

<form action='CMD_SSL' method='POST'><input type='hidden' name='domain' value=''><input type=submit name='disable_letsencrypt_autorenew' value="Disable Auto-Renew"></form>

if json IS used, then the extra variable will be present:


Wildcard LetsEncrypt was removed during renewal. fixed

During the renewal of a wildcard certificate, DA checks to ensure all subdomains and other values in the subjectAltName part of the san_config still exist.

If not (say a subdomain was removed) DA would remove that single entry, and continue normally.

If the * wildcard value was not in the zone, the renewal would have failed (likely for most cases), so the fix was to allow * even if it's not in the zone, as LE doesn't lookup a random A record for verification, it uses a specific record.

Any wildcard cert that has renewed already likely is affected.

You can check all of your domains to confirm which no longer have wildcards (assuming you set them all to be wild, so ensure you factor that in from the list)

grep subjectAltName /usr/local/directadmin/data/users/*/domains/*.san_config | grep -v '*'

will show all san_config files which do NOT have the current wildcards setup. (DA won't be able to know which did or did not)

If you need to manually set all domains to be wild again, for each san_config:


change the previous line:,

to be wild again:


and the next renewal should take it from there.

To automate the forced renewal of all certificates (may cause you do hit the daily limit, so do this with caution), set the unix timestamp from more than 60 days ago.

For example if today is September 9th, 61 days ago is July 10th, so in unix timestamp it's 1531273805

Thus put:

echo 1531273805 > /usr/local/directadmin/data/users/USER/domains/DOMAIN.COM.cert.creation_time

and you can force a renewal check right now and it will update any domain who's creation_time is more than 60 days, by typing:

cd /usr/local/directadmin

echo "action=rewrite&value=letsencrypt" >> data/task.queue; ./dataskq d2000

Debian: MySQL/MariaDB will install data to /var/lib/mysql from /home/mysql (SCRIPTS) fixed

Existing systems will not be affected. This only applies to new installs.

For a long time, DirectAdmin has always used /home/mysql as the data path for MySQL/MariaDB.

The binaries and versions are installed to /usr/local/mariadb-10.2.12-linux-glibc_214-x86_64, for example, where this path is a link to:

/usr/local/mariadb-10.2.12-linux-glibc_214-x86_64 -> mysql

Then the data path is also a link:

/usr/local/mysql/data -> /home/mysql

which of course has now been changed to:

/usr/local/mysql/data -> /var/lib/mysql

for new installs.

For backwards compatibility (in case anyone is using the absolute /home/mysql path), a link has been created:

/home/mysql -> /var/lib/mysql

This does mean that you may need to adjust your partition sizes if you're already maxing out your / or /var partitions, as the MySQL data will be moved from /home to /var.


The reason for this is that newer MariaDB versions need read access all the way down the path (not too sure why, but they do), eg:

openat(-1, "/home", O_RDONLY|O_NOFOLLOW|O_PATH) = -1 EACCES (Permission denied)
openat(-1, "/home", O_RDONLY|O_NOFOLLOW|O_PATH) = -1 EACCES (Permission denied)
write(2, "180910 16:04:47 \[ERROR\] Fatal error: Can't open and lock privilege tables: Table './mysql/host.MYI' is read only\", 113180910 16:04:47 \[ERROR\] Fatal error: Can't open and lock privilege tables: Table './mysql/host.MYI' is read only 

and we cannot change /home to 755 for security reasons.

/home should be 711 so it's contents cannot be read by Users.


The debian script:


has very minor changes to swap /home/mysql to /var/lib/mysql, and add the /home/mysql -> /var/lib/mysql link.

The paths in the my.cnf should not be affected, since they use the link paths, eg:


which contains 2 links (mysql and data), so it can be left alone.

plugin iframes utf-8 by default fixed

Related post:

In the event that iframe=yes is passed to the plugin request, the resulting output will be quite minimal, for insertion into an iframe.

However, this has it's own character set, so it had to be specified.

The new default will set:

<meta charset="utf-8" />

into the <head> section of the iframe output.

If you do not wish to have this, include:


into the request.

Confusing dns_ttl=1 vs allow_ttl_override=1 (SKINS) fixed

When both of these are enabled, it can be confusing when the client sets an "Override TTL Value".

Solution is to change TTL input for new record to be a static number, set to that Override TTL Value.

Other side-effects when Override TTL Value is enabled for a given zone, is that the wildcard LetsEncrypt option tries to specify a TTL, but it's not respected.

So avoid using the Override TTL Value option if you need to use LetsEncrypt. (it should still work, but it sets records for longer than needed)




extra checks to convert the TTL_INPUT token to be a static number:


|*if DNS_TTL="yes"|
|?TTL_INPUT=<td class=list_alt align=center><input type=text name=ttl size=6 value="\`TTL_VALUE\`" placeholder="\`LANG_TTL_BLANK_FOR_DEFAULT\`" title="\`LANG_TTL_BLANK_FOR_DEFAULT\`"></td>|
|?BLANK_TD=<td class=list_alt></td>|
<td class=listtitle align=center >|LANG_TTL|</td >
|*if TTL_CUSTOM_SELECTED!="checked"|
|?TTL_INPUT=<td class=list_alt align=center>\`TTL_VALUE\`</td>|
Last Updated: