I don't think that anybody genuinely likes any webhosting control panel sofware currently on the market. It's all one big bloated, unnavigable mess of quickly hacked together, insecure scripts that collectively consume an inordinate amount of resources, but in spite of all their shortcomings, they can and do still save a lot of time if you've got to keep tabs on more than a couple of domains.

cPanel and WHM are not what I would call quality software, but they lay down fairly sane directory structures and config files, so I tend to recommend them over Plesk and DirectAdmin which do not. With that out of the way, here's a running list of things I spent entirely too much time figuring out how to do simply because I couldn't find a list of things like this anywhere.



Make Exim listen on a non-standard port

Everybody's ISP blocks port 25 these days, so every hosting company provides an alternate SMTP port for their clients to use. WHM provides a means of accomplishing this through its UI in the "Service Manager" config page, but all this does is fire off an extra copy of Exim which is bound to another port. It makes little sense to dedicate extra resources to a redundant daemon when Exim itself allows you to accomplish the same thing without WHM's help.

Say you wanted to send mail through port 2525, you'd add something like this to the top of your Exim config file located in /etc/exim.conf:

daemon_smtp_ports = 25 : 2525 : 587

Port 25 is the standard SMTP port which will need to remain enabled for compatibility's sake, 2525 would be your custom port, and 587 is the standard for SSL/TLS connections. These can appear in any order you like so long as they are separated by colons.

If you add this directive to the config file through WHM's own Exim config editor, you can ensure that the custom port setting will persist across upgrades.

 

Make Exim use SSL/TLS for SMTP

There are a lot of public WiFi networks out there today, and it's generally a bad idea to send clear text passwords over them for anything, including email. To enable secure communications in Exim you must add the following to its config file:

tls_certificate = /etc/ssl/yourcert.crt
tls_privatekey = /etc/ssl/private/yourkey.key

Obviously, you'll need to substitute actual paths to your certificate and private key files (they can both be in the same file as well, just provide the same path to each directive), but you'll also need to make certain that these are kept somewhere that Exim has read access, and that's sometimes a little less obvious.

Contrary to popular belief, you can use self-signed certificates for this purpose so long as the client software will support them. Exim itself does not care.

NOTE: Current WHM builds include a service SSL certificate manager which obviate the need for this process.

 

Make Courier use SSL/TLS for POP

You might think you'd be able to get away with adding something similar to another file in /etc for this, but WHM puts Courier's config files elsewhere and provides no UI to access them. You'll have to manually open up /usr/lib/courier-imap/etc/pop3d-ssl and add something like:

TLS_CERTFILE=/etc/ssl/yourcert.crt

This can (and probably should) be the same certificate you supplied to Exim.

NOTE: Current WHM builds include a service SSL certificate manager which obviate the need for this process.

 

Stop Dropping the Mail!

Exim has a wonderful little spam fighting feature known as "callouts" that verifies the existence of all acounts which are attempting to send a message through your server. In a nutshell, if bob@flybynighthost.com tries to send a message, Exim will go through all the motions of trying to send bob@flybynighthost.com a message of its own, and if the mail server for flybynighthost.com says bob doesn't exist, Exim will kick bob to the curb.

This is all well and good, but many perfectly legitimate companies like to send perfectly legitimate messages with bogus return addresses such as noreply@suchandsuch.com in order to ensure that their customers contact them through alternate means, and all that extra work validating addresses wastes time, too. If you want to purposely spoof a From header for this reason, or if you want to serve as a relay for some external process such as an Asterisk PBX running on a private intranet that uses an address which isn't publicly routable like asterisk@pbx.local, you'll probably want to turn callouts off.

There's two ways to do this:

  1. Uncheck the "Use callouts to verify the existence of email senders." checkbox in the basic Exim configuration editor
  2. Find the line in the check_recipient ACL that reads "require verify = sender/callout" and delete the "/callout" part.

According to all the documentation I've read, you should also be able to blindly accept anything from an authenticated sender by adding something like

accept authenticated = *

before the sender verification requirement, but in practice, this does not actually seem to accomplish anything. I have no idea why, and I have no idea what kind of crack the guy who cooked up the Exim configuration file syntax was smoking. If you love Perl so much, why not just make everything use Perl so you don't have to waste so much time documenting some obscure little pseudolanguage?

 

Enable Dynamic DNS

I won't go into why you might want to do this, but WHM does install a fully functional copy of BIND 9, and if you want to enable dynamic DNS updates, there's nothing stopping you from doing so.

Step 1: Create a new file somewhere that named can access it. We'll call our example file /etc/ddns.conf

Step 2: Open up /etc/named.conf and add the following line to it

include "/etc/ddns.conf";

BIND is now configured to look in /etc/ddns.conf for additional configuration directives. It's good to break our custom settings out into their own file in case cPanel decides it needs to rewrite named.conf at some point and blows away all our changes. This way, the most we'll ever lose is that one piddly little include line.

Step 3: Now we're going to add a new zone declaration to ddns.conf on which dynamic DNS updating will be permitted. It is best to restrict such activity to its own little corner, as once you enable dynamic updating for a zone, its zone file will no longer be human (or cPanel) editable.

zone "ddns.domain.com" { type master; file "/var/named/ddns.domain.com.db"; update-policy { grant *.ddns.domain.com. self ddns.domain.com. A; }; };

Make sure named has write access to /var/named/. It probably won't by default.

You'll have to consult your BIND manual if you want an explanation of how the update policies work. Suffice to say that the configuration I've provided allows clients to update their own A records in the ddns.domain.com zone provided they supply keys with names that match the zone they're trying to update. There are many other possibilities.

Step 4: Generate some keys. BIND's definition of a key is basically just a Base 64 encoded string, so you can make this pretty much any way you like. What I like to do is MD5 and Base 64 encode the MAC address of the computer that will be using the key and pass that off as the shared secret, but for now let's just assume our key is any random garbage like OMWxZj22QnZvoDLSidlKS8dc== and move on.

Still in /etc/ddns.conf, add a key definition for each zone which will be dynamically updated

key client1.ddns.domain.com. { algorithm hmac-md5; secret "OMWxZj22QnZvoDLSidlKS8dc=="; };

Since this file now contains keys, make sure it's not world-readable, eh.

Remember, you're defining the name of the key and its associated secret here. These can be anything you like, but because of the update-policy I've specified in this example, each key needs to have the same name as the zone it corresponds to. That's why my key name looks exactly like the zone name. This is not always the case.

Step 5: Restart BIND. rndc reload just won't cut it for some reason.

BIND should now be willing to accept dynamic updates for this zone. You can test it out by supplying the nsupdate utility with the following commands:

; First we get rid of any existing records so we can add a new one server ns1.domain.com key client1.ddns.domain.com. OMWxZj22QnZvoDLSidlKS8dc== prereq yxdomain client1.ddns.domain.com. update delete client1.ddns.domain.com. A send ; Then we add a new one with the correct IP server ns1.domain.com key client1.ddns.domain.com. OMWxZj22QnZvoDLSidlKS8dc== prereq nxdomain client1.ddns.domain.com. update add client1.ddns.domain.com. 300 A 127.0.0.1 send

Obviously you'll need to supply your real names, keys and IP addresses where appropriate.

 

Keep Script Kiddies Away

If added to /usr/local/apache/conf/httpd.conf the following directives will foil the plans of idiots who go out trolling for insecure scripts to exploit and keep your logs clean.

<FilesMatch "xmlrpc\.php"> ErrorDocument 404 "This script is not allowed on this server." </FilesMatch> <FilesMatch "^formmail"> ErrorDocument 404 "This script is not allowed on this server." </FilesMatch>

There are obviously many more naughty scripts out there, but these two pop up in my logs far more frequently than anything else. Don't let your users run them.