Version 1.60.2

Released: 2020-02-08

JSON: domain pointers to CMD_SHOW_USER new

The call to:


will now include Domain Pointers within the "domains" array:



                "domain": "",
                        "limit": "shared",
                        "usage": "0.000000"
                "quota": "1.44531",
                "log_usage": "0.000000",
                "nsubdomains": "0",
                "suspended": "no",
                        "cgi": "ON",
                                        "type": "alias"
                        "php": "ON",
                        "ssl": "ON"
                        "domain": "1",
                        "bandwidth": "2",
                        "quota": "3",
                        "log_usage": "4",
                        "nsubdomains": "5",
                        "suspended": "6",
                        "settings": "7"
                "current_page": "1",
                "ipp": "50",
                "rows": "1",
                "total_pages": "1"


Admin Settings: Set Server Timezone (SKINS) new

New option for the Admin Settings page: Server's Timezone

  1. This is based on the /etc/localtime file, which DA reads as a symlink (see below if it's not)

  2. The list is generated from:


and if that doesn't exist, it falls back to:


Where DA is mainly only concerned with the "America/Edmonton" style entries.






to hold the "timezone" select dropdown.



To save the seting, it makes use of the already existing:


method: POST





Where all other config values should also be passed.

Any valid path from:


would be accepted, even if the timezone value is not in the

eg: Canada/Mountain



The select box will be filled into the |TIMEZONE_SELECT| token.

Values from the or are used.

In the even that a zone not from the is used, DA will set and read the TZ env var with tzset.

The zone info can be determined from this. For example "MST" might be returned.

Should that fall-back zone not be in the list, then DA will ensure it exists, then add it, eg:

/usr/share/zoneinfo/MST does exist, so "MST" happens to be a valid timezone, just like America/Edmonton (in list) or Canada/Mountain (not in list), but would be added.




JSON["server_settings"]["timezone"] : "America/Edmonton"

as well as another top-level array: "timezones", eg:

        "Africa/Abidjan": "",
        "Africa/Accra": "",
        "Africa/Algiers": "",
        "Africa/Bissau": "",
        "Africa/Cairo": "",
        "Africa/Casablanca": "",
        "Africa/Ceuta": "Ceuta, Melilla",
        "Africa/El_Aaiun": "",
        "Africa/Johannesburg": "",
        "Africa/Juba": "",
        "Africa/Khartoum": "",
        "Africa/Lagos": "West Africa Time",
        "Africa/Maputo": "Central Africa Time",
        "Africa/Monrovia": "",
        "Africa/Nairobi": "",
        "Africa/Ndjamena": "",
        "Africa/Sao_Tome": "",
        "Africa/Tripoli": "",
        "Africa/Tunis": "",
        "Africa/Windhoek": "",
        "America/Adak": "Aleutian Islands",
        "America/Anchorage": "Alaska (most areas)",
        "America/Araguaina": "Tocantins",
        "America/Argentina/Buenos_Aires": "Buenos Aires (BA, CF)",
        "America/Argentina/Catamarca": "Catamarca (CT); Chubut (CH)",
        "America/Argentina/Cordoba": "Argentina (most areas: CB, CC, CN, ER, FM, MN, SE, SF)",
        "America/Argentina/Jujuy": "Jujuy (JY)",
        "America/Argentina/La_Rioja": "La Rioja (LR)",
        "America/Argentina/Mendoza": "Mendoza (MZ)",

Where the value of the timezone is a comment from the file (or



If you're on a LAN, and you're writing an external IP to a VirtualHost

but internally in your LAN, you only have: (for example)

and you forgot to add it to your DA ips.list & forgot to link it to the external IP,

Then DA will automatically add the server's main IP, as determined by the new script, below to the VirtualHost, automatically.

DA requires that either /root/.lan exist or directadmin.conf:lan_ip= be set, to be considered a LAN (for this feature to do anything)



which will try and sort out the server's main local/usable device IP address.

In the case of a LAN, it should return (with our example)

DA will then ensure that is included in the |MULTI_IP| list.

Enhanced: Show Domain Pointer count on HTM_INDEX_USER new

The HTM_INDEX_USER fills a table into the |DOMAINTABLE| token.

This table will now have a span in each cell, similar to:

<span class='float_right'>(<a href='/CMD_DOMAIN_POINTER?'>2 Domain Pointers</a>)</span>

But this extra span only shows up if:

  • Domain Pointers limit is greater than zero (user.conf)
  • Domain Pointers usage is greater than zero (user.usage)
  • CMD_DOMAIN_POINTER is allowed to be run (commands.deny/commands.allow)
  • per-row: if this domain has more than 0 pointers (domains/

Note: sorting has been updated to only look at the domain.

Previously the text in the cell was used, but now it's just the domain, and the <a href> bits and <span> will not be sorted

(which wouldn't have mattered anyway, since the first change of character is in the href="...", which is still alphabetical.)


Ability to hide "Main account spambox" option in SpamAssassin settings (SKINS) new

By default, there are 4 choices as to where to redirect spam messages to.

  • Inbox (no redirect)
  • Main imap spambox
  • per-account spambox
  • drop the email

The "Main imap spambox" option, aka:

"Redirect it to the catch-all spam folder in your main imap account."

refers to:


regardless as to which email account was receiving the email.

This option has been confusing for some clients, so we've added a new directadmin.conf option with internal default:


where nothing changes when set to 1.

If you set this to 0, eg:

cd /usr/local/directadmin
./directadmin set show_main_spambox 0
service directadmin restart

Then this main account spambox option is hidden from the skin.

Attempting to save where=spamfolder will also throw an error, as the option is blocked internally.



When calling:


a new option will be present:

"show_main_spambox": "1",

if you find this set to 0, then hide the main imap account spambox option.

If it's not present, assume it to be set to 1.




CMD_SYSTEM_INFO?bytes=yes new

Option to show memory usage in bytes.

Mainly for:




The scripts/ has been updated to:

  • check if we're on a LAN

  • Find the main IP of the server with the new scripts/ script

  • Attempt to bind to this IP to confirm that the external IP matches what we originally though it should

  • if it does, then add the LAN IP to the ips.list, link the LAN IP to the server IP, setup the directadmin.conf:lan_ip setting, ./build rewrite_confs for directadmin-vhosts.conf

Read in /root/.os_override to internal os_override setting new

If the /root/.os_override setting is filled (which is is, with a "./ auto" call), and if os_override is not set in the conf/directadmin.conf,

then during DA's startup and read of the directadmin.conf, should the os_override not be in the directadmin.conf file,

then the internal os_override value will be set to the value from the /root/.os_override file.

Admin Settings: max_username_length new

Ability to edit the max_username_length setting in the Admin Settings.

Compile time: Feb 7 2020 at ~13:48:04

global VirtualHost pre/post CUSTOM templates: allow scripting by setting username fixed

Related to global templates for CUSTOM token pre/post insertions:

Error thrown:

"The username hasn't been set. Won't run the script without dropping privileges"

Meaning adding scripts to these pre-post templates won't be able to run.

Fixed by setting the "root" user on this tokenizer call.


JSON: UTF-8 encoding fixed

Some character were not included in the decision to encode them as UTF-8.

For example:


was not being encoded, as will now be shown at:


in the json output.

Applies to all areas where json strings are output.

Compile time: Jan 29 2020 at 00:16:21

License read on a VPS: decrypt error: error:2406C06E:random number generator:RAND_DRBG_instantiate:error retrieving entropy fixed

Report on openvz where the license read throws the following error:

[root@server /]# /usr/local/directadmin/directadmin b2000
Debug mode. Level 2000

Unable to read the license file
reason: An error has occurred while attempting to decrypt the data<br>
Check your DA binaries, your license, and /dev/urandom (chmod 666)<br>
decrypt error: error:2406C06E:random number generator:RAND_DRBG_instantiate:error retrieving entropy<br>
  1. We have seen the same error in the past for other reasons, but the solution was a similar method to previous solutions.

Since we now compile openssl statically in our binaries, from our our build of openssl, the original was using:

./config --prefix=$(pwd)/../out no-shared no-ssl2 no-ssl3 no-tests

the previous fix was:

./config --prefix=$(pwd)/../out no-shared no-ssl2 no-ssl3 no-tests --with-rand-seed=devrandom,rdcpu,os

where we needed to control the order of which random generator was used by openssl.

  1. In this specific openvz case, it's using a custom kernel which doesn't include getrandom(), so the call to:
strace ./directadmin

was throwing;

getrandom(0x555e7c7bc0c0, 32, 0)        = -1 ENOSYS (Function not implemented)

In this case, the solution was to add one extra option compiled into openssl:

./config --prefix=$(pwd)/../out no-shared no-ssl2 no-ssl3 no-tests --with-rand-seed=devrandom,rdcpu,os,getrandom

simply adding "getrandom" to the end of the --with-rand-seed option, so that's also included in openssl.. thus preventing the need for openssl to look in the kernel for the function.

The order of the devrandom,rdcp,os,getrandom are intentional, as /dev/urandom (via getrandom()) had zero entropy in the original scenario #1.


Cluster: Timeout inline fixed

If a remote server happens to be down, previously, the entire action would have waited until the usual 60 second DA timeout.

By default, the cluster (Multi-Server Setup) has a 5 second timeout, however, although it was triggering the signal/hook, that hook was stepping out of the sequence.

Fix was to use the set flag, and when the process returned to the connect/transfer section, the process would abort, instead of trying to move forward, hanging for the full 60s.

Now, should the remote box be down, the proper 5s timeout will now work (for the connection part), and abort accordingly.

User creation, deletion, and Admin record adding/deletion will also include a bold message embedded in the success result about the downed remote IP.


SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 fixed

In addition to the SSL_CTX_new change to TLS_server_method in 1.56.0, this change also specifies:


to block TLSv1.0 through TLSv1.2

Compile time: Jan 30 2020 at ~15:31:17

Named: Read zone if SOA line does not span multiple lines (no brackets) fixed

The SOA line is a record like any other. This change allows the SOA line to be a single line, without any multi-line (brackets)


@ IN SOA 2020013000 14400 3600 1209600 86400

When DA saves the zone, the named.db template will be used, and it will reset back to the multi-line zone with the brackets, but this will at least be a able to read the zone in either format.


Messages/Tickets: rework logic if ticket system is disabled fixed

Bug where a Reseller could not send a message to their Users, if the creator of that Reseller (eg: admin) had their ticket system disabled.

After the work, the logic is:


  • A User can only create a ticket, no messages to other Users.

  • Creator's ticket system must be enabled to do anything.


  • A Reseller can always create messages to their Users.

  • A Reseller can only create a ticket (up to Admin) if the Admin's ticket system is enabled

  • A Reseller can always reply to a User ticket, even if their ticket system is disabled (User cannot reply if disabled)


  • An Admin can never create a ticket (nobody to send to).

  • A 2nd Admin can also never create a ticket, even if admin2's creator=admin.

  • An Admin may send a message to anyone on the system.

JSON: CMD_LICENSE: remove newlines, add current_time_string, timezone_offset fixed

More information for the CMD_LICENSE?json=yes call.

All formatted dates now have the trailing newlines stripped out.

New items:

"current_time_string": "Fri Jan 31 18:50:23 2020",

"timezone_name": "MST",

"timezone_offset": "-07.00",

"true_expiry_string": "Mon Jan 18 20:14:07 2038",

Where the timezone_offset is a standard +-hour:minute, eg:


The timezone_name is taken from the tzset() call, tzname array, where the "daylight" value determines which of the 2 possible timezone names to use,

depending on whether or not daylight savings is in effect.

Linux 64-bit static: dynamic check for systemd fixed

Default change for the Linux 64-bit static DirectAdmin binaries, where instead of a single default for systemd of 0|1,

for this change, the static bins will get an internal default of -1.

If DA has systemd=-1 value after the read of the directadmin.conf, then it will scan for either:



( /usr/bin OR /usr/bin/systemctl )

If the above is true, DA will set systemd=1

else, it will set systemd=0


The template:



|*if allow_blank_referer!="yes"|
        RewriteCond %{HTTP_REFERER} !^$

which has been correct to:

|*if allow_blank_referer="yes"|
        RewriteCond %{HTTP_REFERER} !^$

Where the RewriteConf is for NOT blank, thus to allow blank, it must be present.

CMD_WIDGET: returning empty json index fixed

A previous fix from Dec 27th 2019 to prevent a segfault, introduced a new bug which was missed during testing and release candidacy testing.

Causes widget details to be blank, eg:


where the fix is now:

           "main": "Where are the snacks? We're hungry."

Forwarder anti-loop check fixed

For local forwarders, if they end up pointing back to the original name, DA will abort the creation of the forwarder.

Sample error message::

Forwarder loop found: : has Loop Found: from from from from

Where setup was an attempt to create: ->

Where is local to the same box, and that domain had forwarders:






As the process is recursive, the parent forwarder value is added to the end of the string with the ": from", but should be enough to track it down.

The max recursion depth is 20, at which point DA will declare it to be a loop anyway (20 levels of loop recursion seems a bit much anyway)


Block PMA SSO if there are zero databases fixed

To prevent confusion, DA will now throw an error if the User uses the system account PhpMyAdmin SSO (one-click-login) with zero databases.

There is a warning in the GUI that phpMyAdmin won't work, but a proper error if they attempt it anyway.

Filter/Forwarders html encode errors (SECURITY):low fixed

User is able to provide invalid characters in some cases to inject their own results with arbitrary JS.

The threat level is essentially zero as the XSS protection would work correctly, so it can only be self inflicted, but a bug nonetheless.

Credit: Bartosz Kwitniewski

Missing wildcard in /etc/virtual/ prevent catch-all page from loading all tokens fixed

Found issue where a missing * value in the:


sample that could have been there:

*: :fail:

but without the *, the function that loads the tokens bailed assuming the file read failed.

Changed code to continue and default to :fail:

Upon saving the desired catch-all setting, the new value is saved.


Last Updated: