Mark Malkasian
July 2020
This tutorial is intended to provide step-by-step instructions to setting up a dedicated server with a basic LAMP installation. There are plenty of tutorials out there that fit the same description. What sets this tutorial apart is the attention to detail and the intended audience.
If you wish to offer your suggestions or comments, you're welcome to contact me. You're also welcome to submit like-minded tutorials on related topics for publication on the site.
You may be wondering why the focus is on Hostwinds. I came to Hostwinds as an exile from Dream Hosts. Although the server farm at Dream Hosts had a solid performance record, their business model revolves around herding customers toward managed server and VPS (virtual private server) packages, supplemented by selling add-on services. Eventually, the constraints and limitations imposed by Dream Hosts took all the fun out of running a dedicated server.
With Hostwinds, I was back in the driver's seat. Of course, that means being more self-reliant, but that's the point. I found the Hostwinds support staff to be professional and courteous during the transition. (Most of my questions pertained to domain transfers.) Like technical support staffs everywhere, they are clearly overstretched.
Much more disappointing was Hostwinds' online documentation. The Knowledge Base is littered with broken links and outdated articles, and little of it addresses the needs of dedicated server admins. My original intent was to post my tutorial in the Knowledge Base. I contacted Hostwinds twice to offer my tutorial at no charge. Unfortunately, I never received even so much as a boilerplate rejection. That leads me to question whether I made the right choice in signing up with Hostwinds. So far, knock on wood, the server itself is running smoothly.
My fear is that the business model at Hostwinds isn't much different than that of Dream Hosts (and seemingly the vast majority of web hosting providers). I'm in business myself, so I can appreciate the bottom-line forces driving the market. There's not much money to be made from the hands-on, do-it-yourself, command-line types these days. However, if you're proud to fit in that category, Hostwinds hasn't completely slammed the door in your face. I'm hoping that this tutorial helps fill the gap in their online documentation. By the time you finish, you should be well on your way to hosting multiple web sites on your new server. Let's jump in.
Once your Hostwinds dedicated server order is complete, you'll receive an email with a password that will enable you to log in as the "root" user with your SSH client (I use PuTTY). One of your first tasks should be to change the root password and create a new user with "sudo" privileges. Conventional wisdom says that you shouldn't log in as root. Instead, create a separate user with "sudo" (i.e. "superuser do") privileges equal to the root user.
Change the root password from the default...
Create a new account...
Give the new user "sudo" privileges...
After you log in as "myusername", you give yourself sudo privileges by entering the command below, followed by a password prompt...
The above command means you'll have sudo privileges throughout your session. You'll be able to proceed through the rest of the server setup without prefacing each command with "sudo".
Ubuntu includes a built-in firewall, known as UFW (or "uncomplicated firewall"). The firewall is disabled by default. Before enabling UFW, you'll need to make sure that UFW doesn't block your SSH client from connecting to your server. First, check the list of UFW applications...
The output should be similar to the following: Available applications: Apache Apache Full Apache Secure OpenSSH
To prevent UFW from blocking your SSH client, permit SSH connections with the following command...
You'll also want to permit connections to the Apache web server on ports 80 (http) and 443 (https) with the following command...
Now it's time to enable the firewall with the following command...
Check to make sure that OpenSSH and Apache connections are allowed...
Two command line utilities -- apt and rysnc -- will quickly become your new best friends during the server setup process. Both are simple to use and battled-tested. Let's get acquainted.
APT is an abbreviation for Advanced Package Tool and serves to interact with the dpkg (Debian packaging) system. Debian (or Debian GNU/Linux) is the open-source operating system launched in 1993 that is the basis for Ubuntu and a few other flavors of Linux. APT makes installing, upgrading, and deleting software quick and easy. Before installing software on your new server, execute the "update" and "upgrade" commands to ensure you have access to the latest applications...
View the impressive list of applications available for installation through APT...
The standard command for installing an application is...
If you need to remove a program, use the following commands...
rsync (remote sync) quickly transfers and synchronizes files between two servers. If you're moving your web sites from another hosting provider to Hostwinds, you'll find rsync an indispensable tool. It's certainly quicker and more efficient than FTP. rsync can also be used to copy files on your server from one directory to another.
To move a directory from your old server to your Hostwinds server, issue the following command from your Hostwinds server...
To move a single file from your old server to your Hostwinds server, issue the following command from your Hostwinds server...
To establish a connection and initiate the transfer, you will be prompted to enter the password for "myusername" on your old server.
rsync has a wide range of options. Below is a guide to the options used in the commands above: a = archive mode, which is the equivalent of "-rlptgoD", meaning rsync will transfer files recursively and preserve almost everything. v = verbose reporting. z = compress file data during the transfer.
After you download application packages or update Ubuntu, you may see the following message when you log in to your shell account: *** System restart required ***
You can reboot from the command line or from the Client Area.
From the Client Area main menu, click the "Manage" button for your dedicated server, scroll down to the "Server Management" section, and click the "Reboot" link.
From the command line...
Rebooting takes a few minutes, so it's an action you want to avoid on a live server.
Soon after its release in 1995, Apache established itself as the world's most popular web server (although Nginx is not far behind). Apache was crafted with adaptability in mind. The application's core functionality is extended by a variety of compiled modules, such as mod_rewrite and mod_ssl. Other modules accommodate the use of server-side programming languages, such as PHP and Python. The Apache community also maintains a robust support network centered around https://httpd.apache.org. Apache is easy to install and easy to customize. Let's start with the basic installation.
Install Apache (or more correctly the latest stable version of apache2)...
Verify the Apache version...
In my case, the output was the following: Server version: Apache/2.4.29 (Ubuntu)
By default, the Apache configuration files are installed in the /etc/apache2/ directory, with the main config file located at /etc/apache2/apache2.conf. The path to the Apache HTTP daemon is /usr/sbin/apache2.
Start Apache and check status...
Assuming the "status" command reports "Active: active (running)", you should be able to enter your primary IP address into the location bar of a web browser and see the default index.html page generated by Apache in /var/www/html.
Below are a few other useful commands to manage Apache...
The standard repository for web site files is the /var/www/html/ directory. The standard repository for log files is the /var/log/apache2/ directory. As you'll see, you can customize both paths in the Apache configuration files.
Although it's tempting to tweak some of the directives (e.g., MaxKeepAliveRequests) in the main Apache configuration file located at /etc/apache2/apache2.conf, it's probably better to get your web sites up and running before fine tuning. If you can't resist the temptation, first make a back-up copy of the config file...
As noted above, adding compiled modules makes Apache even more powerful. Several of them will be enabled during installation of the Apache package. Let's review the inventory.
Determine which modules have been enabled...
If your web sites require additional modules, such as mod_rewrite, mod_ssl, etc., enable them with a2enmod and restart Apache...
By most measures, MySQL is the world's most popular database. First released in 1995, MySQL serves as the foundation for many of the web's most popular database-driven applications, such as WordPress, phpBB, and Drupal. It has also been adopted as a platform by many of the Internet's giants, including Facebook, Twitter, and YouTube. Although Oracle bought MySQL in 2010, it continues to provide an open-source version. (At the time of Oracle's acquisition, MariaDB was created by one of MySQL's founders to preserve the open-source MySQL project.) In addition, free, online support for MySQL remains as strong as ever.
Install MySQL...
The default settings in MySQL are not secure. Fortunately, there is a single configuration command that protects the database against the most common attacks. Secure MySQL...
You will be prompted to enter a password and answer "y" (for "yes") for questions about security.
Log in to MySQL...
MySQL can be operated from the command line, but managing the database through a web-based application, such as phpMyAdmin, will make your life a lot easier. We'll get to that later.
Below are a few key commands to start and stop the database...
As with Apache, it's probably best not to tweak MySQL configuration settings until your web sites are up and running. That doesn't mean, however, that you shouldn't familiarize yourself with your database's settings.
View the current MySQL settings...
To see all MySQL settings...
Although MySQL has a my.cnf configuration file (actually a symlink that points to /etc/mysql/mysql.cnf), the key settings are found in /etc/mysql/mysql.conf.d/mysqld.cnf. It's possible to edit mysqld.cnf. However, the best practice for adjusting your database settings is to place a new file with a ".cnf" extension in the /etc/mysql/conf.d/ directory. For example, you might call your file "myDBoptions.cnf" so you'll remember that it's your own creation. (The ".cnf" extension tells MySQL to incorporate the settings when you restart the database.) Your custom file should follow the format of mysqld.cnf. For example, [mysqld] key_buffer_size = 16M max_allowed_packet = 16M thread_stack = 192K thread_cache_size = 8
After creating a custom configuration file, restart MySQL...
Serious web applications demand a serious server-side programming language. Among the most popular at the moment are PHP, Python, and Ruby. I use PHP (Hypertext Preprocessor), so I'll guide you through the process of putting it to work on your server.
Install PHP
Because I didn't specify a version of PHP (e.g., php7.3, php5.6, etc.), the default package of PHP on your server is installed.
Restart Apache...
PHP includes a wide range of extensions that broaden PHP's functionality and enable it to interface with other programs, such as MySQL.
Install common PHP extensions...
Restart Apache...
Now that PHP is installed, you might want to explore the configuration by creating a simple file that executes the phpinfo() function. First, open your favorite text editor (e.g., nano, pico, vi, etc.) and enter the three lines below... phpinfo();
Save the file at /var/www/html/phpinfo.php.
Open your newly created file by entering 111.222.333.4/phpinfo.php in the location bar of a web browser (with 111.222.333.4 being your primary IP address). The resulting display should include all the vital details of your PHP configuration.
If you're like me, you have web sites written in older versions of PHP that you haven't updated (and may never get around to updating). Parsing an application written in version 5.6 with version 7.3 will result in syntax errors. Fortunately, the Ubuntu community has developed a method for accessing applications not included in Ubuntu's default installation. The solution comes in the form of a Personal Package Archive, or PPA. A PPA is a repository of applications, typically focusing on a single program. A PPA will usually include both older and newer versions of an application. The PPA for PHP you'll need to enable is maintained by Ondřej Surý. (Like so many other individuals in the open-source community, Ondřej Surý is not a tech billionaire with a personal brand to promote. He puts his time and effort into maintaining the PHP PPA out of the goodness of his heart and a commitment to the open-source ethos.)
Enable the Ondrej PPA...
Install PHP version 5.6...
Restart Apache...
Install common PHP 5.6 extensions...
Restart Apache...
Your PHP executables can be found at... /usr/bin/php5.6 /usr/bin/php7.2 /usr/bin/php7.3
Over the years, the PHP community has continued to improve the integration between PHP and Apache. As of this writing, the consensus is to serve up PHP web pages with the help of the Apache mod-fcgid module and the PHP php-fpm extension.
The mod_fcgid module uses the FastCGI protocol to provide an interface between Apache and Common Gateway Interface (CGI) programs. It starts up several CGI program instances to handle concurrent requests to your web site.
The "fpm" in the php-fpm extension stands for FastCGI Process Manager, which runs as a daemon and interprets Fast/CGI requests. Each version of PHP requires installation of its own php-fpm extension. We'll use php7.3-fpm for the example below.
Enable the FastCGI module for Apache2...
Restart Apache...
Enable the configuration that instructs Apache to pass PHP requests to php-fpm for processing...
Restart Apache...
Start FastCGI Process Manager...
Verify the status of FastCGI Process Manager...
FastCGI Process Manager requires the following Apache2 modules: actions, fcgid, alias, proxy_fcgi. Make sure the modules are enabled...
Enable modules as needed...
Restart Apache...
When you run your phpinfo() script, you should now see a new entry: Server API FPM/FastCGI
Enabling the FastCGI module created the configuration file below at /etc/apache2/mods-available/fcgid.conf, so there's no need to add a new directive in apache2.conf.
Just as there are version-specific php-fpm extensions, you'll find version-specific configuration files (e.g., php7.3-fpm.conf) for each version of php-fpm in the /etc/apache2/conf-available directory.
FastCGI Process Manager's security.limit_extension setting is used to limit the file extensions that will be parsed by PHP. If your web site has ".html" pages that require PHP parsing, limit_extension will block access and display an "Access denied" message with a 403 status error. To change or disable security.limit_extension, edit /etc/php5/fpm/pool.d/www.conf:
security.limit_extensions =.php.html
or
security.limit_extensions = (allows any extension to be executed)
Restart FastCGI Process Manager...
Using FastCGI Process Manager to serve your web pages requires editing Apache's VirtualHost directive, but we'll save the details for the section on Virtual Hosting.
If you've been programming with PHP long enough, you probably have some code running on a neglected web site that you're less than proud of. Bringing the code up to speed might be the right thing to do, but it's a lot easier to edit PHP's configuration settings to cut yourself some slack.
PHP's configuration files are called php.ini and can be found in the /etc/php/ directory. Each version of PHP has its own set of configuration files. Below are paths for version 7.3... /etc/php/7.3/apache2/php.ini /etc/php/7.3/cli/php.ini /etc/php/7.3/fpm/php.ini
If you've enabled the php-fpm module to serve web pages, the settings in /etc/php/7.3/fpm/php.ini are in effect. To confirm, run your phpinfo() script and check the value for "Loaded Configuration File".
The /etc/php/7.3/cli/php.ini file is used by the CLI version of PHP. The CLI version comes into play when you run PHP from the command line or use it in a cron script.
Confirm the path to the CLI version of PHP...
The output should be: Loaded Configuration File => /etc/php/7.3/cli/php.ini
The apache2/php.ini and fpm/php.ini files are identical and can be copied one to the other. The cli/php.ini file is slightly different.
After modifying fpm/php.ini, restart Apache and the php-fpm module...
If you're a server admin for a top-secret government agency or a too-big-to-fail financial institution, securing the Internet's most sensitive data is a constant concern for you, and I sincerely hope you're not reading this tutorial. For the rest of us, we're more likely to be the target of a runaway bot or a bored teenager. Taking a few prudent steps will help minimize our vulnerability.
The mod-evasive module is intended to thwart distributed denial-of-service (DDoS) attacks. The purpose of a DDoS attack is to block access to a web site by flooding it with page requests.
Install mod-evasive...
The installation interface asks how sending mail is configured. In most cases, you should select "Internet". You'll also be asked to enter a domain name for your SMTP server. Note that libapache2-mod-evasive includes the installation of Postfix (more on that later).
The configuration file for mod-evasive is found at /etc/apache2/mods-available/evasive.conf. By default, all settings are commented out.
Uncomment the following settings, leaving the default values in place: DOSHashTableSize 3097 DOSPageCount 2 DOSSiteCount 50 DOSPageInterval 1 DOSSiteInterval 1 DOSBlockingPeriod 10
You should probably leave the following settings commented out unless you want to closely monitor your server: DOSEmailNotify DOSSystemCommand DOSLogDir.
Restart Apache...
The mod-security2 Apache module is a popular firewall application. Known as ModSecurity, or Modsec, the module helps protect your web server from several common attacks, including SQL injection, XSS, trojans, nasty bots, session capture/hijacking, and more.
Install mod-security2...
By default, no security rules are configured at installation. You need to copy and edit /etc/modsecurity/modsecurity.conf-recommended to put ModSecurity to work.
Copy the configuration file to /etc/modsecurity/modsecurity.conf...
Edit the "SecRuleEngine" setting in /etc/modsecurity/modsecurity.conf:
Change
DetectionOnly
to
On
Restart Apache...
ModSecurity can be configured to fine tune the level of security you wish to apply. You should start by setting up the OWASP ModSecurity Core Rule Set (CRS). The CRS is a set of generic attack detection rules that aim to protect web sites from the most common threats.
Replace the default CRS with an updated version...
Copy the file crs-setup.conf.example to crs-setup.conf...
In /etc/apache2/mods-available/security2.conf, add the following lines after "IncludeOptional /etc/modsecurity/*.conf": IncludeOptional "/usr/share/modsecurity-crs/*.conf IncludeOptional "/usr/share/modsecurity-crs/rules/*.conf
In the same file, make sure the following line has been entered above "": IncludeOptional /usr/share/modsecurity-crs/owasp-crs.load
Enable the Apache mod_headers module (if not already be enabled)...
Restart Apache...
Not surprisingly, experts in Internet security are particularly worried about cyberthreats. The developers of ModSecurity are no exception (the settings for the CRS are ranked by "paranoia level"). You'll almost certainly want to dial down the fear factor. ModSecurity's default installation comes in blocking mode and with an "anomaly threshold" of 5 for page requests. I found that setting triggered too many "false positives". To address the issue, I uncommented the section below in /usr/share/modsecurity-crs/crs-setup.conf and raised the defaults of inbound_anomaly_score_threshold and outbound_anomaly_score_threshold to 10: SecAction "id:900110, phase:1, nolog, pass, t:none, setvar:tx.inbound_anomaly_score_threshold=10, setvar:tx.outbound_anomaly_score_threshold=10"
ModSecurity provides more fine-tuning tools to exclude URLs from being subjected to specific rules. If you post content with HTML or JavaScript tags through a content management system, you'll probably want to take advantage of them. For example, I created /usr/share/modsecurity-crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf by copying the ".example" file and added the rule exclusion below to disable all SQLi and XSS rules for my "content_management.html" page: SecRule REQUEST_URI "@beginsWith /content_management.html" "id:1000, phase:1, pass, nolog, ctl:ruleRemoveById=941000-942999"
Note that each rule exclusion must have a unique "id" and Apache must be restarted after each configuration edit.
To disable specific rules with one-line exceptions (e.g., SecRuleRemoveById 942100), edit /usr/share/modsecurity-crs/rules/REQUEST-999-EXCLUSION-RULES-AFTER-CRS.conf.
Fail2Ban is a software package designed to protect Apache servers from a range of attacks. Fail2Ban blocks specific IP addresses by monitoring your log files to identify suspicous activity, such as rapid-fire login attempts, brute force denial-of-service (DDOS) assaults, requests for sketchy URLs, probes for executables, etc. The offending IPs are blocked from accessing your server for a time period you define.
Install Fail2Ban...
Fail2Ban files reside in the /etc/fail2ban directory. The primary configuration file, jail.conf, should not be edited. Instead, you should create a separate file (e.g., jail.local) in the /etc/fail2ban directory to define customized filters. In Fail2Ban parlance, each filter (or set of rules) is known as a "jail". The text between the brackets (e.g., "apache", "http-get-dos") defines a distinct jail that holds malevolent IP addresses. Several parameters enable you to customize the filters.
logpath is the file path monitored by Fail2Ban.
maxretry defines the maximum number of failed login attempts allowed before an IP address is blocked.
findtime specifies the time period in seconds used by "maxretry".
bantime specifies the number of seconds that an offending IP address will be blocked (i.e., held in Fail2Ban jail).
ignoreip lists IP addresses that should not be blocked by Fail2Ban. Each address should be separated by a space.
Below is a basic working example of jail.local:
# Blocks failed login attempts.
[apache]
enabled = true
port = http,https
filter = apache-auth
logpath = /var/log/apache2/*error.log
maxretry = 15
bantime = 600
ignoreip = 111.222.333.4
# Blocks failed login attempts to the SSH server.
[ssh]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
bantime = 600
ignoreip = 111.222.333.4
# Blocks requests for suspicious URLs.
[apache-overflows]
enabled = true
port = http,https
filter = apache-overflows
logpath = /var/log/apache2/*error.log
maxretry = 10
bantime = 600
ignoreip = 111.222.333.4
# Blocks requests for executable scripts.
[apache-noscript]
enabled = true
port = http,https
filter = apache-noscript
logpath = /var/log/apache2/*error.log
maxretry = 10
bantime = 600
ignoreip = 111.222.333.4
# Blocks requests for malicious bots.
[apache-badbots]
enabled = true
port = http,https
filter = apache-badbots
logpath = /var/log/apache2/*error.log
maxretry = 3
bantime = 600
ignoreip = 111.222.333.4
# Blocks brute force denial-of-service (DDOS). Each file in logfile should be separated by a newline character.
[http-get-dos]
enabled = true
port = http,https
filter = http-get-dos
logpath = /var/log/apache2/access.log
/var/log/apache2/access_log_mydomain
/var/log/apache2/access_log_yourdomain
maxretry = 400
findtime = 400
bantime = 200
ignoreip = 111.222.333.4
action = iptables[name=HTTP, port=http, protocol=tcp]
# Block attempts to exploit PHP for malicious purposes.
[php-url-fopen]
enabled = true
port = http,https
filter = php-url-fopen
logpath = /var/log/apache2/*access.log
ignoreip = 111.222.333.4
Create jail.local...
Create http-get-dos.conf...
Start Fail2Ban and check its status...
View the rules added by Fail2Ban (you should find a few incarcerated IP addresses)...
Install phpMyAdmin...
Restart Apache...
phpMyAdmin files are located at: /usr/share/phpmyadmin -- web site files. /etc/phpmyadmin and /etc/dbconfig-common -- config files. /etc/phpmyadmin/config.inc.php -- main configuration file.
phpMyAdmin requires the PHP mbstring extension to function (it may already be installed). Install and enable php-mbstring...
You may also need to uncomment the line below in php.ini: extension=mbstring
Restart Apache...
By default, phpMyAdmin is served out of the /var/www/html directory. If the FastCGI Process Manager handles PHP requests to your server, add the following to 000-default.conf:
You can now access phpMyAdmin by visiting your server's IP address followed by "/phpmyadmin": http://111.222.333.4/phpmyadmin
Because phpMyAdmin is popular, it's a frequent target of malevolent hackers. A few precautions will reduce your vulnerability.
By default, the initial setup of phpMyAdmin allows access through the IP address of your server (e.g., http://111.222.333.4/phpmyadmin). To enable access through a domain, edit /etc/phpmyadmin/apache.conf.
Wrap the config file in a VirtualHost directive that assigns a domain you control to the ServerName and ServerAlias:
Add Basic Authentication by inserting the following below the "Alias" line:
Insert "AllowOverride All" under the "
Create a symlink to /etc/phpmyadmin/apache.conf and enable phpmyadmin.conf...
Restart Apache...
Now that you've assigned a domain to phpMyAdmin, the next step is to add encryption. I won't go into detail here about encrypted URLs. Instead, you'll want to follow the instructions below about generating a Let's Encrypt certificate for the domain serving phpMyAdmin (mydomain.com) and revising the apache.conf file.
DNS is often compared to a phonebook. It maps IP addresses to domain names. This means that visitors to your web site can find you by entering mydomain.com instead of 111.222.333.4.
Managing DNS records is complicated. Fortunately, Hostwinds provides a convenient web interface to manage DNS. The first step involves pointing your domains to Hostwinds' nameservers.
If you are registering new domain names, the process is simple. From the home page of the Client Area, go to Domains > Register a New Domain, and purchase an available domain.
If you are transferring a domain from another registrar to Hostwinds, go to Domains > Transfer Domains to Us. In addition to entering the domain name to be transferred, you'll need to enter an authorization code from the existing domain registrar (e.g., godaddy.com) to initiate the transfer. Also, be sure to "unlock" the domain name with the existing domain registrar. Be patient. The transfer process can take up to a week.
If Hostwinds is acting as your registrar, you can monitor the status in the Client Area at Domains > My Domains. If the status is "Active" (as opposed to "Pending"), you can select "Manage Nameservers" in the pulldown menu to the right of the domain name. Make sure the "Use custom nameservers (enter below)" radio button is highlighted. Enter nameserver records for the "Nameserver 1" (e.g., mdns5.hostwindsdns.com) and "Nameserver 2" (e.g., mdns6.hostwindsdns.com) fields, and click the "Change Nameservers" button.
If you are happy with your current registrar (e.g., godaddy.com), you need to repoint the domain's nameservers to Hostwinds' nameservers (e.g., mdns5.hostwindsdns.com and mdns6.hostwindsdns.com) and change the IP address of the "A" records to the primary IP of your Hostwinds server.
Next, you'll need to associate your domains with your server. In the Client Area, go to Domains > Manage DNS. (As you'll see, this takes you to the Cloud Control interface.) Click the "Create" button, select "Domain (Add a domain name)", enter the domain (e.g., mydomain.com) you want to host on your server, and click "Add Domain". The nameservers associated with your account will be your defaults.
If a domain is registered with Hostwinds and its status is "Active", you have the ability to add, edit, and delete DNS records in the Hostwinds interface. In the Client Area, go to Domains > Manage DNS (this takes you back to the Cloud Control interface). You should see a list of domains associated with your account. Assuming the status of the domain is "Active", clicking the "Actions" link will open a link to "Records".
The interface for adding records has four fields: the first field is the record "type" (e.g., A, TXT, CNAME, etc.); the second field is the "name" or "host"; the third field is the "value" or "points to"; and the fourth field is the "TTL" (time to live) or time in seconds until the record begins propagating.
A (address) Records
The most basic web hosting DNS record is the A record, which maps a domain name to an IP address. You'll need two of them. The default for the record type in the first field is "A". In the second field, enter "@" (which signifies the core domain name). In the third field, enter your primary IP address. The default TTL is 3600 seconds (one hour). Your second A record should match the first, except in the second field you'll enter "www" instead of "@". This record will point to "www.mydomain.com".
NS (nameserver) Records
Likewise, you'll need two NS records for your two nameservers. In the pulldown menu of the first field, select "NS". In the second field, enter "@". In the third field, enter your first nameserver (e.g., "mdns5.hostwindsdns.com"). Repeat the procedure to add a second NS entry for your second nameserver (e.g., "mdns6.hostwindsdns.com").
CNAME (canonical name) Records
If you need to create a subdomain, such as "blogs.mydomain.com", you should select "CNAME" in the first field. In the second field, enter "blogs". In the third field, enter "mydomain.com".
MX (mail exchange) Records
If you plan on sending email from your domain, three records are required.
Record 1. In the first field, select "CNAME". In the second field, enter "mail". In the third field, enter "mydomain.com". This creates a subdomain -- "mail.mydomain.com".
Record 2. In the first field, select "MX". In the second field, enter "@". In the third field, enter "10 mail.mydomain.com". The number indicates the priority of the record (the lower the number, the higher the priority).
Record 3. As a backup, repeat the procedure above to create another MX record. In the third field, enter "20 mail.mydomain.com". The other fields should match the first MX record.
PTR (pointer) Records
If you plan to send email on behalf of the domain name (i.e., entering "myname@mydomain.com" in the "From" field), you'll want to create a "pointer", or PTR, record, that maps an IP address to a domain. The PTR is used for reverse DNS (rDNS) lookup. Your Hostwinds account comes with a single primary IP address and several "assigned" IP addresses. The assigned IPs come in handy when PTR records need to be generated. Unlike other DNS records, the PTR is not created through the Cloud Control interface. Instead, you must return to the Client Area and go to Domains > Manage rDNS. There you'll see a list of your assigned IPs. Click on the edit icon of an IP address to map the IP address to a domain. (There's no need to create a separate PTR record in the DNS interface.)
Confirm that the PTR has been set...
SPF (Sender Policy Framework) Records
SPF records are intended to validate the email sent from your domain. Although the Sender Policy Framework is a complex subject, entering a basic SPF record is simple. Start by selecting "TXT" in the first field. In the second field, enter "@". In the third field, enter something like "v=spf1 mx ip4:111.222.333.4 include:_spf.google.com ~all" (in this case, you're allowing email to be sent from your IP address and from your Gmail account). You can check the syntax of your SPF record by plugging it into an SPF Validator (such as https://www.kitterman.com/spf/validate.html).
DKIM (DomainKeys Identified Mail) Records
Unlike SPF, creating a DKIM record is not simple. In fact, there's a separate section below titled "Create DKIM Keys". You can deal with that later.
DMARC (Domain-based Message Authentication, Reporting and Conformance) Records
DMARC is an email authentication protocol with the best of intentions. It gives owners of a domain name the ability to defend their domain against spoofers. A DMARC record instructs receiving email servers how an email from your domain should be authenticated based on your SPF and DKIM records. If you send email from your domain only from your server, you can construct a strict DMARC policy. On the other hand, if you send email with your domain in the "From" field from your Gmail, Yahoo, Hotmail (you name it) account, a strict DMARC policy will result in a lot of rejected email. In that case, you should create a lax DMARC record (i.e., something is better than nothing).
In the first field, select "TXT". In the second field, enter "_dmarc". In the third field, enter "v=DMARC1; p=none; pct=100; rua=mailto:webmaster@mydomain.com".
If you have a domain name that does not send emails, you should created a record with a "p=reject" policy (e.g., "v=DMARC1; p=reject; pct=100; rua=mailto:webmaster@mydomain.com").
One final word about DNS: don't worry if you make a mistake. You can delete the record and replace it with a new one. The new record may take some to propagate across the Internet, but you haven't done any lasting damage to your domain.
At this stage, you should have a functioning web server. Of course, the point of a functioning web server is to host a functioning web site. In this section, we'll get to the heart of the matter. You'll create a user, transfer files, and configure Apache to serve up your web site.
I'm assuming that you signed up for a dedicated server because you wanted the flexibility of hosting multiple domains on a single server. That's where Virtual Hosting comes in to play. For each virtually hosted domain, you'll repeat the process below.
Add a user for your domain...
The "adduser" command will prompt you to make several entries.
The "User Name" should match the core username of the account (e.g., mydomainuser).
If you are the sole admin on your server, you can enter your name for "Full Name" and accept the empty defaults for the other identifiers ("Room Number", "Work Phone", etc.).
The results of "adduser" will be the creation of a new directory for a virtually hosted account in the /home/ directory (e.g., /home/mydomainuser/).
The standard path for web files is the /var/www/html/ directory. In the example below, however, I'll use the /home/ directory to house my web files.
Create a "www" directory in the /home/mydomainuser/ directory...
From your Hostwinds server, use rsync to transfer files from your old server...
For convenience, add a symlink from / (the root directory) to the web content directory.
If you have a configuration file with passwords, email addresses, and other sensitive information, you should place it in a more remote, protected area of your server.
By default, "mydomainuser" is the owner of the directory created by running "adduser". That's fine if you edit your web files with one of Ubuntu's built-in text editors (such as nano or vm) and don't use SFTP to upload files. In my case, however, I prefer to edit web files with my favorite desktop text editor (UltraEdit), which connects to my server by SFTP. I also use WS_FTP to upload files on occasion. Because I rely on the SFTP protocol, I want to give my SFTP user easy access to my web files by changing the ownership of the files in the newly created /home/mydomainuser/ directory.
Change ownership...
Log in to phpMyAdmin.
To create and set up a new database, click the "New" link in the phpMyAdmin sidebar and enter a database name (e.g., "MyDatabase"). Accept the defaults and click "Create".
To grant privileges to a new user, update the "mysql" database that was automatically created when MySQL was installed. (To repeat, all of these steps could be accomplished by running MySQL from the command line. Using phpMyAdmin just makes them easier.)
Go to the "mysql" database and add a new user to the "user" table with the following SQL statement...
The fields for the newly created user "mydomainuser" in the "user" table will be set to "no" by default.
Next, set the privileges for the user "mydomainuser" in the "db" table...
Reload the grant tables...
Dump database on your old server (the path to mysqldump may need to be changed)...
From your Hostwinds server, transfer the database dump and rebuild the database...
Execute check, repair, optimize, and analyze the tables of your MyDatabase.
In past versions of Apache, you probably put all of your VirtualHost directives into a single configuration file. In Apache2.4, standard practice is to create a separate VirtualHost configuration file for each of your domains. The VirtualHost config files reside in the /etc/apache2/sites-available directory. A default file -- 000-default.conf -- serves as an example. (You'll want to make a back-up copy of the default file.)
Copy the default file...
The "mydomainuser" in "mydomainuser.conf" must match the username you created above with the "adduser" command.
Now it's time to open mydomainuser.conf in the text editor of your choice and plop in your VirtualHost directive. VirtualHost directives can be as simple or complex as you desire. In the example below, we'll keep things fairly simple, but with a nod to the use of PHP and Apache's mod_rewrite module:
You'll notice that the VirtualHost directive uses a wildcard in place of an IP address (
If the domain features a subdomain (e.g., blog.mydomain.com), you'll need to include a separate VirtualHost directive in the config file for the subdomain. The ServerName and ServerAlias must reflect the subdomain. Place VirtualHost directives for subdomains above the VirtualHost directive of the core domain (e.g., mydomain.com). Subdomains must be associated with a CNAME DNS record.
The example above assumes you're using FastCGI Process Manager to serve requests for PHP pages. The three lines of the
Below that are two rewrite rules. The first rewrites URL requests without "www" (e.g., http://mydomain.com) to http://www.mydomain.com. The second redirects all requests that are not for actual files to my traffic_director.php script, which, as the filename suggests, routes page requests to their proper destination.
Once you've finished editing mydomainuser.conf, you need to enable the configuration file. The a2ensite command creates a symlink in the /etc/apache2/sites-enabled directory...
Before restarting Apache, check the syntax of the new VirtualHost directive...
Restart Apache...
Once 000-default.conf is no longer needed, you should disable the default config file...
Encryption is quickly becoming the standard on the web, with Google favoring sites that use the https protocol over http. Fortunately, there's Let's Encrypt -- a non-profit certificate authority that provides SSL certificates at no cost. To generate a Let's Encrypt certificate, you can use Certbot -- yet another free, open-source software tool.
To begin the process, go to https://certbot.eff.org/instructions.
Select your web server (e.g., Apache) and operating system (e.g., Ubuntu 18.04 LTS (bionic)). Certbot's web site presents command-line instructions for you to follow to install the most up-to-date version of certbot from the Certbot PPA. (Note that Python will be installed along with certbot if it's not already on your server.)
Once certbot is installed, you are in a position to generate Let's Encrypt certificates on your server. (Certificates can be created only if a domain's nameserver and A records resolve to your server.)
Create a certificate for mydomain.com...
The certificate generated above will encrypt requests for both https://mydomain.com and https://www.mydomain.com.
You will find several certificate-related files in the /etc/letsencrypt/ directory.
Next, we need to reconfigure the Apache configuration file for your domain. You'll notice in the VirtualHost example above, the directive was instructed to listen to port 80. We need to change that to port 443:
Within the same VirtualHost directive, add the SSLCertificate section just below the ServerAdmin parameter. This tells Apache where to find the certificates you generated: SSLEngine on SSLCertificateFile /etc/letsencrypt/live/mydomain.com/cert.pem SSLCertificateKeyFile /etc/letsencrypt/live/mydomain.com/privkey.pem SSLCertificateChainFile /etc/letsencrypt/live/mydomain.com/chain.pem.
You also need to include a VirtualHost directive listening to port 80 that redirects requests from http://www.mydomain.com to https://www.mydomain.com. Insert the port 80 directive above the port 443 directive:
WARNING: Do not enable a domain that is listening to port 443 until the Let's Encrypt certificate has been generated and the SSLCertificate paths defined. Otherwise, Apache will throw a syntax error when you restart and ALL sites on your server listening to port 443 will fail to connect and instead trigger errors.
Let's Encrypt certificates expire in 90 days. Fortunately, all of your certificates can be renewed with a single command...
Even easier is to renew your certificates through a cron job, which is our next subject.
Cron is a utility included with Ubuntu and other Unix-based operating systems. The software is nothing more than a task scheduler. The power of cron derives from the scripts you choose to schedule.
Cron scripts can be scheduled to run as often as you like -- from every minute to once a year. They can execute single shell commands or lengthy scripts written in PHP or other programming languages. I use cron jobs to automate a variety of chores, such as renewing Let's Encrypt certificates, cleaning up temp files, optimizing my databases, sending emails to customers, settling credit card transactions, generating XML sitemaps, etc. You get the picture.
Cron is already installed on your server but you do need to enable it...
Cron responds to instructions in the crontab (short for cron table) file. You could edit crontab directly. However, for convenience I suggest you create a separate file that contains a schedule of your cron jobs and can be easily edited at /var/spool/cron/mycronjobs.
If you use PHP to write cron scripts, the top of the file needs a "shebang" line pointing to the CLI version of PHP required. #!/usr/bin/php7.3 -q
After editing mycronjobs, refresh crontab...
Check crontab to make sure your changes have been recorded...
Logrotate is installed and activated when you order your server. As the name suggests, it rotates the many types of log files found in the /var/log/ directory. The default configuration file is located at /etc/logrotate.conf. In addition, there are application-specific config files in the /etc/logrotate.d/ directory.
If you find that too many log backup files are being saved, you can edit the files in the /etc/logrotate.d/ directory. Lowering the value of the "rotate" parameter reduces the number of backup files saved in /var/log/.
By default, logrotate runs on a daily basis by executing the shell script /etc/cron.daily/logrotate.
Postfix is an open-source email server (or mail transfer agent). It was developed by Wietse Venema at IBM and debuted in 1998. Venema and others in the Postfix community continue to support its improvement. Postfix is the default email server in Ubuntu.
Postfix serves to both send and receive email. Personally, I'm very wary of hosting email accounts on my server. Past experience has taught me that email hosting brings non-stop headaches and few rewards. Instead, you should focus on making sure that email sent from your server reaches as many inboxes as possible.
Installing and configuring Postfix is a relatively lengthy process, with many optional detours. I opted for a fairly simple installation. It largely follows the instructions written by Xiao Guoan (aka, the Linux Babe). If you're looking for more detail, please visit https://www.linuxbabe.com/mail-server/setup-basic-postfix-mail-sever-ubuntu. (In general, Xiao's site is an outstanding resource for anyone working on an Ubuntu server, or other Debian-based systems.)
Before you delve into Postfix, you need to set up a FQDN (fully qualified domain name) for your email server, such as mail.mydomain.com. Revisit the "MX (mail exchange) Records" heading in the DNS section to define the FQDN for your mail server.
Assign the domain as your FQDN...
If you installed the Apache mod-evasive module, Postfix was installed as well. Execute the command below to determine if a version of Postfix resides on your server...
If Postfix is not found or the version needs to be updated, install it...
Below are the key paths to managing Postfix on your server: /etc/postfix -- Postfix configuration files. /usr/sbin -- Postfix executables. /var/log/mail.log -- log file. /var/mail -- inboxes for each user.
Postfix uses port 25. Make sure it's not blocked by the UFW firewall...
To use an email client, such as Thunderbird, for email, you'll need to unblock additional ports from the firewall...
By default, the /etc/aliases file contains only one line -- postmaster: root. Generally, root is not used as an email address. Instead, the postmaster should use a login name alias to access emails. root: myemailuser
Implement changes to /etc/aliases...
Most of the configuration parameters you may want to adjust can be found in /etc/postfix/main.cf. As you'll see, Postfix gives you a lot of flexibility. For now, we'll begin with a few basic edits.
Change the "myhostname" parameter to your FQDN (e.g., mail.mydomain.com).
Edit the "TLS parameters" as follows (I'm assuming you've already created a Let's Encrypt certificate for mydomain.com): smtpd_tls_cert_file=/etc/letsencrypt/live/mail.mydomain.com/fullchain.pem smtpd_tls_key_file=/etc/letsencrypt/live/mail.mydomain.com/privkey.pem smtpd_tls_security_level=may smtpd_tls_loglevel = 1 smtpd_tls_session_cache_database = btree:/smtpd_scache smtp_tls_security_level = may smtp_tls_loglevel = 1 smtp_tls_session_cache_database = btree:/smtp_scache smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
By default, the /etc/postfix/main.cf file contains the following line to prevent your email server from acting as an open relay: smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
To send email from an email client, such as Thunderbird, uncomment the "submission inet" section in /etc/postfix/master.cf.
Reload Postfix...
Dovecot works hand-in-hand with Postfix. It mainly acts as a mail storage server employing the IMAP and POP3 protocols. Notwithstanding my reluctance to host email accounts, you might as well install Dovecot in conjunction with Postfix (let's hope you can avoid becoming a serious Dovecot admin).
Install the IMAP and POP3 versions of Dovecot...
Edit the main Dovecot config file at /etc/dovecot/dovecot.conf by adding the following at the end of the file: protocols = imap protocols = imap pop3
Open /etc/dovecot/conf.d/10-mail.conf to check if the "mail_location" and "mail_privileged_group" parameters are properly set.
By default, "mail_location" is already set to /var/mail (mail_location = mbox:~/mail:INBOX=/var/mail/%u), which is fine.
The other important line -- mail_privileged_group = mail -- is also present by default.
Add dovecot to the mail group so that Dovecot can read the INBOX...
Edit the authentication file at /etc/dovecot/conf.d/10-auth.conf.
Uncomment the following line:
disable_plaintext_auth = yes
Add the following line to require a full email address (myusername@mydomain.com) to log in:
auth_username_format = %n
Make the following changes in the SSL/TLS config file at /etc/dovecot/conf.d/10-ssl.conf:
ssl = required (from "yes")
ssl_cert =
Disable SSLv3, TLSv1 and TLSv1.1 by adding the following line:
ssl_protocols = !SSLv3 !TLSv1 !TLSv1.1
In /etc/dovecot/conf.d/10-master.conf, change the "service auth" section to the following: unix_listener /var/spool/postfix/private/auth { mode = 0660 user = postfix group = postfix }
In /etc/dovecot/conf.d/15-mailboxes.conf, find the "Drafts", "Junk", "Trash" and "Sent" mailboxes. Below the opening bracket of each mailbox, add "auto = create".Restart Dovecot and confirm that it's running...
Restart Postfix...
If you get sucked into hosting email accounts, you'll need to set up a cron job to delete email from the "Junk" and "Trash" folders of your email users. Below are examples of commands that delete emails in the "Junk" and "Trash" folders at least two weeks (2w) old...
PostfixAdmin is a web-based application for managing Postfix. It's written in PHP and requires integration with MySQL. The PostfixAdmin interface is a little clunky and dated, but it gets the job done.
Because PostfixAdmin relies on MySQL, you first need to prevent the installation from reconfiguring your database...
Install PostfixAdmin...
Remove dbconfig-no-thanks...
Run the PostfixAdmin Configuration Wizard...
The wizard will prompt you to enter a few responses: Reinstall database: yes MySQL database connection: Unix socket Database name: postfixadmin (default) MySQL username for postfixadmin database: postfixadmin Database password: *********** Database admin user: debian-sys-maint
The wizard will install two new databases: "information_schema" and "postfixadmin".
Edit /etc/dbconfig-common/postfixadmin.conf to integrate MySQL: dbc_dbtype='mysqli'
Edit /etc/postfixadmin/dbconfig.inc.php to integrate MySQL: ='mysqli'
The web files are installed under /usr/share/postfixadmin/ directory, which is owned by root. You need to give the "www-data" user read, write, and execute permissions on the Smarty template compile directory. Grant permissions...
In the Client Area, go to Domains > Manage DNS and create a new CNAME record for your mydomain.com domain: postfixadmin.mydomain.com
Create a new VirtualHost directive at /etc/apache2/sites-available/postfixadmin.conf:
Enable the config file...
Restart Apache...
You should be able to access the PostfixAdmin web-based install wizard at http://postfixadmin.mydomain.com/setup.php.
The set-up process populates the postfixadmin database. The three most important tables are: domain -- contains information on the domains that are using your mail server to send and receive email. mailbox -- contains information on every email address, including hashed passwords and the location of mail files. alias -- contains the alias of each email address.
By default, Postfix delivers emails only to users with a local account on your server. To make it deliver emails to virtual users whose information is stored in the database, you need to configure Postfix to use virtual mailbox domains. At this point, the postfix-mysql module should have been already installed.
Add the following to the end of /etc/postfix/main.cf: virtual_mailbox_domains = proxy:mysql:/etc/postfix/sql/mysql_virtual_domains_maps.cf virtual_mailbox_maps = proxy:mysql:/etc/postfix/sql/mysql_virtual_mailbox_maps.cf, proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf virtual_alias_maps = proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_maps.cf, proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_maps.cf, proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cfvirtual_mailbox_domains points to a file that will tell Postfix how to look up domain information from the database.
virtual_mailbox_maps points to files that will tell Postfix how to look up email addresses from the database.
virtual_alias_maps points to files that will tell Postfix how to look up aliases from the database.
You'll need to create several config files in the /etc/postfix/sql/ directory. Start by creating the directory...
Create the files below in the /etc/postfix/sql/ directory by following the instructions at https://www.linuxbabe.com/mail-server/postfixadmin-ubuntu: mysql_virtual_domains_maps.cf mysql_virtual_mailbox_maps.cf mysql_virtual_alias_domain_mailbox_maps.cf mysql_virtual_alias_maps.cf mysql_virtual_alias_domain_maps.cf mysql_virtual_alias_domain_catchall_maps.cf
Restrict access to /etc/postfix/sql...
Since we are using virtual mailboxes, we need to remove the core domain name (mydomain.com) from the "mydestination" parameter.
Add the following lines to the end of the file: virtual_mailbox_base = /var/vmail virtual_minimum_uid = 2000 virtual_uid_maps = static:2000 virtual_gid_maps = static:2000
The first line defines the base location of mail files. The remaining three lines define which user ID and group ID Postfix will use when delivering incoming emails to the mailbox. We use the user ID 2000 and group ID 2000.
Restart Postfix...
Create a user named "vmail" with ID 2000 and a group with ID 2000...
Create the mail base location with vmail as the owner of the directory...
Configure Dovecot to use MySQL by installing the dovecot-mysql module...
Edit /etc/dovecot/conf.d/10-mail.conf:
Change:
mail_location = maildir:/var/vmail/%d/%n
Add:
mail_home = /var/vmail/%d/%n
Edit /etc/dovecot/conf.d/10-auth.conf:
Change:
auth_username_format = %u
Uncomment:
!include auth-sql.conf.ext
Add:
auth_debug = yes
auth_debug_passwords = yes
Set the parameters below in /etc/dovecot/dovecot-sql.conf.ext: driver = mysql connect = host=localhost dbname=postfixadmin user=postfixadmin password=********* default_pass_scheme = ARGON2I password_query = SELECT username AS user,password FROM mailbox WHERE username = '%u' AND active='1' user_query = SELECT maildir, 2000 AS uid, 2000 AS gid FROM mailbox WHERE username = '%u' AND active='1' iterate_query = SELECT username AS user FROM mailbox
Restart Dovecot...
Before we get completely lost in the weeds, lets remind ourselves that the main purpose of Postfix is to send email from your server into the inboxes of your recipients. To repeat, we want our email to land in the inbox. Not spam, not junk, not trash, and certainly not out in the ether. That's the reason we are once again addressing the issues of SPF (Sender Policy Framework) and DKIM (DomainKeys Identified Mail) in the Postfix section. For now, follow along. There is light at the end of the tunnel.
Install the SPF Policy Agent...
Edit /etc/postfix/master.cf by adding the following lines at the end of the file: policyd-spf unix - n n - 0 spawn user=policyd-spf argv=/usr/bin/policyd-spf
Edit /etc/postfix/main.cf by adding the following lines at the end of the file: policyd-spf_time_limit = 3600 smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, check_policy_service unix:private/policyd-spf
Restart Postfix...
Install OpenDKIM...
Add postfix user to opendkim group...
Edit /etc/opendkim.conf by uncommenting the following lines, replacing "simple" with "relaxed/simple": Canonicalization relaxed/simple Mode sv SubDomains no
Add the following lines below "SubDomains no": AutoRestart yes AutoRestartRate 10/1M Background yes DNSTimeout 5 SignatureAlgorithm rsa-sha256
Add the following lines at the end of the file: # Map domains in From addresses to keys used to sign messages KeyTable refile:/etc/opendkim/key.table SigningTable refile:/etc/opendkim/signing.table # Hosts to ignore when verifying signatures ExternalIgnoreList /etc/opendkim/trusted.hosts # A set of internal hosts whose mail should be signed InternalHosts /etc/opendkim/trusted.hosts
Create a directory for opendkim keys...
Change the owner and permissions for the newly created directory...
Change the OpenDKIM Unix socket file so Postfix can communicate with it.
Create a directory to hold the OpenDKIM socket file and allow only "opendkim" user and "postfix" group to access it...
Edit /etc/opendkim.conf and replace:
Socket local:/var/run/opendkim/opendkim.sock
with
Socket local:/var/spool/postfix/opendkim/opendkim.sock
Add the following lines to the end of /etc/postfix/main.cf: # Milter configuration milter_default_action = accept milter_protocol = 6 smtpd_milters = local:opendkim/opendkim.sock non_smtpd_milters =
Restart opendkim and postfix service...
Now that opendkim is installed and configured, we can finally generate DKIM records for your domains.
Create/edit the signing table at /etc/opendkim/signing.table and add entries for each domain that requires a DKIM key: *@mydomain.com default._domainkey.mydomain.com *@myotherdomain.com default._domainkey.myotherdomain.com
Create/edit /etc/opendkim/key.table and add entries for each domain that requires a DKIM key: default._domainkey.mydomain.com mydomain.com:default:/etc/opendkim/keys/mydomain.com/default.private default._domainkey.myotherdomain.com myotherdomain.com:default:/etc/opendkim/keys/myotherdomain.com/default.private
Create/edit /etc/opendkim/trusted.hosts and add the following: 127.0.0.1 localhost *.mydomain.com *.myotherdomain.com
For each domain, you will generate a private key for signing and a public key for remote verification. The public key will be published in your DNS records.
Create a separate directory for each domain...
Generate keys for each domain using opendkim-genkey tool...
Change the owner of the private keys...
Display the public key for the domain...
In the Client Area, go to Domains > Manage DNS to create a DKIM record for each domain. In the first field, select "TXT". In the second field, enter "default._domainkey," which will default to default._domainkey.mydomain.com. For CNAME domains (e.g., mail.mydomain.com), type out the second field in full (e.g., default._domainkey.mail.mydomain.com). In the third field, enter everything displayed by the above command that lies within the parentheses. This can be tricky, because you also have to remove all double quotes, line breaks, and tabs from the display.
Restart opendkim...
Test the key...
The results should look like the following: opendkim-testkey: using default configfile /etc/opendkim.conf opendkim-testkey: checking key 'default._domainkey.mydomain.com' opendkim-testkey: key not secure opendkim-testkey: key OK
Don't worry about "key not secure". That means DNSSEC isn't enabled on your domain name.
Test your DKIM, SPF, and DMARC records at https://www.mail-tester.com.
To pass a DMARC check, an email needs to meet one of the following requirements:
1. Score an SPF "pass" with the Return-Path domain name being the same as the header.from domain.
2. Score a DKIM "pass" with the domain of the DKIM-Signature (d=mydomain.com) being the same as the header.from domain.