The DirectAdmin Binary

The directadmin binary file is responsible for running the DirectAdmin panel itself, but also has a variety of uses. You can find the binary here:
/usr/local/directadmin/directadmin
A common way of starting the panel is via the following command:

service directadmin start
1

But you can call the directadmin daemon right from the binary with

/usr/local/directadmin/directadmin d
1

To get the DirectAdmin version, use:

/usr/local/directadmin/directadmin v
1

Another common use is to set directadmin.conf values, for example:

/usr/local/directadmin/directadmin set letsencrypt 1 restart
1

The last restart key means that dataskq should restart the DirectAdmin panel when dataskq is launched next (dataskq is ran every minute).

You can run directadmin in debug mode (should be stopped before):

/usr/local/directadmin/directadmin b2000
1

Where 2000 is a verbosity level of debug information to print.


HTTP/2 on 2222: full Go wrapper

The DirectAdmin daemon is now using a "Go" wrapper to allow for HTTP/2 on port 2222.
This also allows for multiple requests per connection (as it includes HTTP/1.1 as well).

The old directadmin daemon has been refactored to clearly handle this as well, and it listens on a root-only socket at:
/usr/local/directadmin/da.sock
which receives the individual requests as it did before.

This has a huge performance boost:

  1. HTTP/2 is binary, thus smaller packets
  2. Single connection, saving connection/handshake overhead for each request, making noticeably faster page loads.

The packages will increase in size due to the extra included Go libraries, from a previous size of around 12 Meg (static binaries) now to a new average of around 20 Meg (again, static).

General help of the binary itself

# /usr/local/directadmin/directadmin h

Usage: /usr/local/directadmin/directadmin [c|s|d|v|p|i|r|o|b(#)][set name value (restart)]
c       : shows the values in the config file to make sure they were read in correctly
s       : prints out where the program is slowing without forking. For Debugging only.
d       : run as a daemon (required for init.d scripts)
v       : prints the current program version and quits
p       : set file permissions
i       : run the program installer
r       : runs as Deamon, but saves requests to file (debugging)
o       : Shows which OS this binary is compiled on, and when.
b(#)    : Dumps some debug info to stdout. # is optional debug level,eg b5

set name val (restart): sets the given name=val to the directadmin.conf. Optional restart.
Example:
        /usr/local/directadmin/directadmin set dns_ttl 1 restart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

However, aside from those options shown with the help (h) above, there is a number of 'hidden' keys.


To show the license information:

/usr/local/directadmin/directadmin l
1

Expanding format of IPv6

It can also be used to get the expanded format of IPv6:

/usr/local/directadmin/directadmin  --expand-ipv6 ip=::1
1
0:0:0:0:0:0:0:1
1

Output can be in json format if needed:

/usr/local/directadmin/directadmin  --expand-ipv6 ip=::1 json=yes
1
{
        "ip": "0:0:0:0:0:0:0:1",
        "success": "1"
}
1
2
3
4

Errors will be shown like this:

# ./directadmin --expand-ipv6 ip=foo
error=ip=foo is not an ipv6 ip

# ./directadmin --expand-ipv6 ip=foo json=yes
{
        "error": "ip=foo is not an ipv6 ip"
}

1
2
3
4
5
6
7
8

If the full format was returned, directadmin will exit with code 0. If there was any error, you'll get exit code 12.


How to create a one-time login hash

You can now create a one-time use URL which will automatically log you in as the specified User.

Note: If Login Keys are not enabled for the given User in their user.conf, they will be enabled when this script is ran. If the given "user=" account does not have login_keys enabled, any time a --create-login-url is run for this User, login_keys=ON will automatically be set.

A system.log entry will be added if login keys had to be enabled for the user, such as the following for the admin user:

"Authentication::create_one_time_hash: set login_key=ON for admin for login hash."
1

To send someone a login URL to be logged in as admin, type:

/usr/local/directadmin/directadmin --create-login-url user=admin
1

which will output something similar to:

URL: http://1.2.3.4:2222/CMD_LOGIN_URL?hash=cJbIk9GNsXk43....xmAHSTaKFiFe
1

where the hash value is a randomly long length from 120 to 148 characters.

You can even choose the URL path where you'd like the user redirected upon login:

redirect-url=/CMD_PATH?to=whatever
1

For example, if you need an immediate redirect to a specific plugin within the hash, your creation call might be like:

/usr/local/directadmin/directadmin --create-login-url user=admin redirect-url=/CMD_PLUGINS_ADMIN/hello_world/index.html
1

which will generate a hash url, as usual, except when you navigate to this url, after it's accepted, you'll be redirected to this above path.

This must be a GET request, since you cannot redirect into a POST (what you do on something.html is up to you).

Generating keys dynamically as needed

If you have a script/tool that needs to use DA, you'll make a binary call to generate a login key.
This key will be passed to curl/API, generated on the fly if needed.

2 new calls:

  1. --root-keyauth-for
./directadmin --root-keyauth-for=fred
1

which generates output:

https://admin|fred:login_key@hostname:2222
1

where login_key is replace with the key that should be used.

  1. --root-keypath
./directadmin --root-keyauth
1

generates:

https://admin:login_key@hostname:2222
1

You'd be able to use it like this:

curl -k -X -u "$(directadmin --root-keyauth-for=fred)/CMD_API_USERS?json=yes"
1

The generated key will be temporary (rules to be confirmed) thus the --root-keyauth-for / --root-keyauth calls must be run for each attempt.
We may change them to be one-time use, or any other rule, hence the need for repeated calls.

Technical details regarding --create-login-url

  1. The hash is stored on disk the the global file /usr/local/directadmin/data/admin/login_hashes.conf , but it will be crypted as the "left-side" index, with details about this hash on the right-side.

Thus, a lookup of a given hash must cycle through each item, testing the crypt until found.

It does create a Login Key under this User, but instead of a crypted key, it saved "key=hash", signifying that it's a login url, standing by.

  1. Once a valid hash has been accepted, the login key is swapped with a true crypted password, and that password is set in the sessions file. The password for this key is never seen. The original login hash is removed from the global login_hashes file. Cookie is sent, and the login works just like any other Login Key.

Duration of --create-login-url generated login hashes

By Default the Login Hashes live for 3 days, including the end of the Login Key time. So you have up to 3 days to login and logout. (It's not extended upon hash-to-key conversion).

You can set a different time, for example, to one day, by adding the following to the --create-login-url options list:

expiry=1d
1

Valid time units are: s,m,h,d,M,y and ARE case sensitive.

The option also exists to allow one to alter the internal default time:

login_hash_expiry_minutes=4320
1

With the above example of 4320, it remains set the same as the internal default as it was before this option was added, which is 3 days.

Even after setting a new default value, you can still specify a different expiry during creation, eg:

./directadmin --create-login-url user=fred expiry=1d
1

Restrictions regarding --create-login-url

IPs: You can list one or many IPs or 1.2.3.4-7 ranges by adding this to the options: ips=1.2.3.4,5.6.7.8-9


Commands: Allow + Deny

Similar to the Login Keys, you can control which CMDs are allowed or denied by doing something like:

deny=ALL_RESELLER,CMD_LOGIN_KEYS,CMD_API_LOGIN_KEYS
1

which would block all Admin Level functions for this URL hash. Just be careful if you block ALL_ADMIN, as it's difficult NOT to make Admin Level calls for some things like ajax counts, etc.

When logged in with a login hash, upon clicking "Logout" (CMD_LOGOUT), it will destroy the session but will also delete this Login Key so it doesn't hang around afterwards. It should get deleted eventually, after the expiry hits during various cleanup operations.


Running DirectAdmin with custom config

DirectAdmin could be started with a custom config file this way:

cd /usr/local/directadmin
./directadmin --config=/usr/local/directadmin/conf/directadmin.conf.new d
1
2

Note, this flag is not intended for usage other than for running DA as a daemon (i.e., don't run it with the installer, ./directadmin i).

The order of flags will make a difference. If you run:

./directadmin c --config=file.txt
1

vs

./directadmin --config=file.txt c
1

it might give you 2 different outputs, as 'c' before --config will dump out the data when the 'c' is found, before --config is checked.

Same for dataskq, example usage:

./dataskq --config=file.txt
./dataskq d --config=file.txt
./dataskq --config=file.txt
1
2
3

The order with the dataskq does not matter because flags are all processed before anything is run.


Get the main Admin username

Many scripts require the top-level admin account name. This is not always going to be "admin", so a new command is available to output the admin username:

./directadmin a
1

which would output nothing more than the following if the admin username is 'admin':

admin
1

Managing suspensions

These directadmin command line options let you suspend/unsuspend accounts from ssh as rootopen in new window:

  • Suspend account (any account type):
    /usr/local/directadmin/directadmin --suspend-user user=fred

  • Unsuspend account:
    /usr/local/directadmin/directadmin --unsuspend-user user=fred

  • Suspend domain:
    /usr/local/directadmin/directadmin --suspend-domain domain=domain.com

  • Unsuspend domain:
    /usr/local/directadmin/directadmin --unsuspend-domain domain=domain.com

  • You can also include: reason=Xopen in new window where X must be one of the reason indexes (left side) in the file:
    /usr/local/directadmin/data/templates/suspension_reason.txt
    Omitting a reason will set the reason to be "root ssh" as it was before.
    Contents of the file /usr/local/directadmin/data/templates/suspension_reason.txt include:

user_bandwidth=id=12&text=User Bandwidth
user_quota=id=13&text=User Disk Quota
domain_bandwidth=id=14&text=Domain Bandwidth
domain_quota=id=15&text=Domain Quota
reseller_bandwidth=id=16&text=Reseller Bandwidth
reseller_quota=id=17&text=Reseller Quota
billing=id=18&text=Billing Issue
abuse=id=19&text=Abuse
spam=id=20&text=Spam
other=id=21&text=Other
inactive=id=23&text=Inactive
1
2
3
4
5
6
7
8
9
10
11

So, a valid command would be:
/usr/local/directadmin/directadmin --suspend-user user=fred reason=other

NOTE: The suspension_reason.txt now only used from internal list for translation purposesopen in new window, though it can still be copied to the custom/ directory for customizing the suspension reasons as described below.

Customizing the suspension reason

You may customize the supension reasonopen in new window by customizing the DirectAdmin template file suspension_reason.txt. Copy the file to the /usr/local/directadmin/data/templates/custom directory and edit this custom copy in order to add, edit, or remove the reasons for suspensions as desired.

The id values for the key names are internal language pack id numbers set in:
/usr/local/directadmin/data/skins/enhanced/lang/en/internal/suspension.txt

Note, if you just want to set the text, and not make your entries translatable, then simply don't include an id value.

A sample reason without an id:
smelly=text=He Really Smells Bad

Both cases must have a "text" variable, as it will be the fallback in the event that the id cannot be found in the given language file.


Run any CMD_ call via CLI (DEPRECATED)

This functionality is being dropped and was never implemented in production versions of DirectAdmin.

Documentation regarding this feature, retained for documentation/troubleshooting purposes, can be found hereopen in new window, though.


Show DocumentRoots

You can show all documentroots set in your system using the directadmin binaryopen in new window.

This is an option for CMD_DOMAIN or CMD_API_DOMAIN, both of which will only output JSON:

CMD_DOMAIN?action=document_root

Where all domains' documentroots will be output.

This can be used via the directadmin binary like so:

./directadmin --DocumentRoot

Sample output:

{
	"users":
	{
		"fred":
		{
			"domains":
			{
				"test.com":
				{
					"private_html": "/home/admin/domains/test.com/private_html",
					"public_html": "/home/admin/domains/test.com/public_html",
					"subdomains":
					{
						"forum":
						{
							"private_html": "/home/admin/domains/test.com/private_html/forum",
							"public_html": "/home/admin/domains/test.com/public_html/forum"
						}
					}
				},
				"domain.com":
				{
					"private_html": "/home/admin/domains/domain.com/private_html",
					"public_html": "/home/admin/domains/domain.com/public_html",
					"subdomains":
					{
						"sub":
						{
							"private_html": "/home/admin/domains/domain.com/private_html/sub/sub",
							"public_html": "/home/admin/domains/domain.com/public_html/sub/sub"
						}
					}
				}
			}
		}
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

This command can be called by users when directadmin is running in suid mode to show the docroot for the user's domains, or it can be called by root when not running in suid mode, which will show the docroot for all users.

The call to ./directadmin --DocumentRoot figures out the DocumentRoot values for both http and https, for each domain, subdomain, and pointer. These values are very dynamic and can be altered by various different areas, so the only way to know the true value is to fully compute it. Doing this on the fly for all VirtualHosts on the box can take several seconds (in the scenario triggering this change, it took 18s).

To speed things up, we'll create a new file:
/usr/local/directadmin/data/users/fred/DocumentRoot.cache.json
This file is created if the file does not exist, or the cache.json file is older than the current httpd.conf, nginx.conf, or openlightspeed.conf, depending on your active webserver. If the cache is newer than the httpd.conf, this cache is used for the --DocumentRoot call, greatly speeding it up. If the cache is not there, or older, then it's computed normally with the --DocumentRoot call, but written just as the output is generated by the call, ready for next time.

Get dovecot quotas with directadmin suid mode

You can use the directadmin binary to view dovecot quotasopen in new window.

Not likely a feature for most people (at the moment), but if you set:
echo 1 > /root/.suid_directadmin

and set permissions:
./directadmin p

it will set DA to be:
-rwsr-xr-x 1 root diradmin

This is used for per-User calls.

At the moment, just two options exist, one being the ./directadmin --DocumentRoot call, but now it also adds:
./directadmin --doveadm-quota=user@domain.com
which can be called as root, mail or a User.
If called as a User, it will ensure that domain.com belongs to the UID caller (not likely a common usage, but is an option since suid was needed anyway for 'mail').

If root or mail, it will work for any email that exists in the system.

If the email is valid and dovecot quotas work, then it will output something like:
18237:102400
which would be in KB. So, in the above example, the account is using about 20Meg of 100Meg.

You MUST check the exit code of the directadmin call.
If it's not 0, then ignore this directadmin result.

If the account in question has unlimited dovecot quotas, then the output will be:
0:0

This feature uses the doveadm quota call to get the info, as dovecot is going to be what will accept/reject the email anyway.


The purpose of this feature is to allow exim the ability to block an inbound email at smtp-time via ACL, rather than accepting the message and having it bounce after the dovecot lmtp delivery rejects it.

The ACL in question does not yet exist. If it will exist, it wouldn't be for a while after this version of DirectAdmin has been released.

Last Updated: 6/23/2021, 9:36:08 PM