Skip to main content

Domain Name System Options

Module Selection & Foundation Decisions 

Creating an effective content management systems involves choosing the right tools. While the popular "Drupal Domain Module" suite offer a solution for building affiliate content networks, we found these modules to be heavy and/or complicated.

Also, not to dunk on the Drupal Domain Module which is very solid. This is likely the easy solution for Pantheon Nginx hosted sites. 

Our alternative approach aims to deliver similar "Domain" results while prioritizing efficiency and remaining user-friendly.

Context is Key!
The Context module now supports filtering by Domain! This gives people an easy way to setup Block visibility based on a Domain name.  

Image
Domain Based Filtering



To build dynamic landing pages, we provide a basic Domain list as a "context" filter to our Views Blocks.  Views generate the content for Blocks based on an Affiliation Term. Context then filters the Block's display based on its Domain.  The process of setting Domain Context filters for displaying blocks is simple and an easy concept for teams to understand.

Web Servers: Apache Servers versus Nginx
For our guide, we leverage specific features available with an Apache server.  This may be an important consideration for hosting on platforms like Pantheon, which use the Nginx webserver.  This said, it may still be possible to adjust our guide for Nginx hosting. (HINT: $conf variable w/ value of $_SERVER['DOMAIN_NAME']. )  

The Magic of Apache Domain Variables
Using "Virtual Hosts" in an Apache.conf        

Setting up an Apache PHP variable based on an inbound Domain values can be advantageous to performance. While the Domain modules can help manage DNS from within Drupal, it is also possible to set a simple PHP $domain variable at the Web Server (Apache).       
 

// This goes in an Apache Virtual Host .conf file
// Apache Conf Example for a Virtual Host section
        ServerName snowmaid.com
        ServerAlias snowmaid.com     # Set the DOMAIN variable to the current domain name
        SetEnvIf Host "(.*)" DOMAIN_NAME=$1
        RequestHeader set X-Forwarded-Proto "https"
// This example can go into the settings.php for your site
// Set the domain name based on the Apache variable.
$domain_name = $_SERVER['DOMAIN_NAME'] ?? NULL;
// Set the domain name default if DOMAIN_NAME is empty.
if (empty($domain_name)) {
  $domain_name = "gluebox.com"
}
// Set the domain name as a Drupal environment variable.
putenv("DOMAIN_NAME=$domain_name");


Map the DOMAIN_NAME environment variable to a custom site name based on its value.        
By setting the site name dynamically using the DOMAIN_NAME environment variable, different site names are set based on the inbound domain.     


This is the secret sauce used to bind the user experience where multiple sites are served from a single Drupal installation. :

// Set custom site name based on DOMAIN_NAME environment variable. 
$site_name = ''; 
  switch ($domain_name) { 
      case 'snowmaid.com': 
      $site_name = 'Snowmaid Outdoor Adventures'; 
      break;
      
      case 'gluebox.com': $site_name = 'Gluebox Technology'; 
      break; 
      
      case 'dangercactus.com': $site_name = 'Danger Cactus'; 
      break;    
      
      // Add more cases for other domain names if needed. 
      default: $site_name = 'GlueBox Technology'; 
  break; } 
$config['system.site']['name'] = $site_name;


These are settings for your Theme .theme file. (radix_house_theme.theme)

// Get the DOMAIN_NAME from the environment.
$domain_name = getenv('DOMAIN_NAME') ?? 'default_value';


Setting a Twig page template suggestion based on the Apache variable:


/**
 * Implements hook_preprocess_HOOK() for page templates.
 */
function radix_house_theme_theme_suggestions_page_alter(array &$suggestions, array $variables) {
  // Add a template suggestion based on the domain name.
  $suggestions[] = 'page__'.$domain_name;
}
Image
Template Suggestion



 Setting a Favicon based on the Apache Variable:

/**
* Implements hook_preprocess_HOOK() for html.html.twig.
*/
function radix_house_theme_preprocess_html(array &$variables) {
  // Remove the default favicon link added by Drupal core.
  foreach ($variables['#attached']['html_head_link'] as $key => $link) {
    if ($link[0]['rel'] == 'icon' && $link[0]['href'] == '/core/misc/favicon.ico') {
      unset($variables['#attached']['html_head_link'][$key]);
    }
  }
  // Customize the favicon based on the domain name.
  $favicon_url = '/themes/custom/radix_house_theme/favicon/' . str_replace('.', '_', $domain_name) . '_favicon.png';
  // Add the favicon URL to the page.
  $variables['#attached']['html_head_link'][] = [
    [
      'rel' => 'icon',
      'href' => $favicon_url,
      'type' => 'image/png',
    ],
    'radix_house_theme_favicon',
  ];
}

--

SEO and Meta Tag Set Up
Ensure that each domain's version of common pages has unique title tags and meta descriptions that reflect the specific content or audience of that domain. (Privacy-Policy, Contact Us, About Us, Disclaimer, Term of Conditions)

Content Landing Domain and URL Redirections 
To ensure Content is always contained to its intended Affiliated Domain, a Drupal URL redirect can be used to move the visitor to the proper Domain. For most content, the inbound Domain should match the Affiliated Site Taxonomy.  If the requested Domain does not match the content, a redirect is triggered.  This approach requires a custom module (domain_glue) to achieve the following: 

Retrieve the Taxonomy Term:
Retrieve the Taxonomy Term associated with the current content.

Compare with the Domain Variable:
Compare the value of the Taxonomy Term with the Domain variable set in the settings.php file.

Perform the Redirect: 
If the values do not match, use Drupal's built-in Url and RedirectResponse classes to perform the redirection to the domain specified in the Taxonomy 
 

use Symfony\Component\HttpFoundation\RedirectResponse;

function domain_glue_page_attachments_alter(array &$attachments) {
  // Get the current content and retrieve the Taxonomy Term.
  $node = \Drupal::routeMatch()->getParameter('node');
  if ($node instanceof \Drupal\node\NodeInterface) {
    $taxonomy_term = $node->get('field_taxonomy_term')->entity; // Adjust this field name accordingly.

    // Retrieve the Domain variable.
    $domain_name = getenv('DOMAIN_NAME') ?? 'default_value'; // Adjust as needed.

    // Compare the Taxonomy Term and the Domain variable.
    if ($taxonomy_term && $domain_name !== $taxonomy_term->getName()) {
      // Construct the redirect URL using HTTPS.
      $taxonomy_term_domain = $taxonomy_term->getName();
      $requested_url = \Drupal::request()->getRequestUri();
      $redirect_url = 'https://' . $taxonomy_term_domain . $requested_url;

      // Perform the redirect.
      $response = new RedirectResponse($redirect_url, 301);
      $response->send();
      exit;
    }
  }
}
Image
Google Analytics Domain Settings


Content Caching with Multiple Domains
For a multi-domain Drupal setup, configure the setting "url.site cache context" in the settings.php file. This should help enable domain-specific caching, maintaining a separate content cache for each domain. 

$settings['cache']['contexts'][] = 'url.site';

We recently had some cache issues, where incorrect content was displayed for some Domains.  It only seemed to happen with Anonymous users, and only for some Domains. Clearing the cache would often correct the display temporarily.  The issue was sporadic at first glance. Looking at the Request Headers revealed that a "Cache HIT" was triggering.  The content served from cache was incorrect.

Disabling the Internal Page Cache module corrected the issue.
See Note: Internal Page Cache

Image
Internal Page Cache


 

Image
Cache Issues Incorrect Content

DNS Records for Google Index

Regarding Domain Setups and Apache.  Here's a tip for something that you do not want to see in your access logs. Google is hitting a 403 on our Robots.txt when running a site index.  

>/var/log/apache2# grep -R 403 access.log | grep robot | grep google
...   "GET /robots.txt HTTP/1.1" 403 497 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"

Because we have a valid DNS A Record for "WWW",  Google attempted to use this record when requesting our robots.txt file.
Our Apache did not have a Virtual Host setting for the WWW and was returning a 403.   Removing the A Record for WWW may have been the easiest fix.   

All around bad things happen if you have a DNS entry for "WWW" and your Apache and Drupal are not prepared.

Drupal doesn't know about our WWW DNS Record:

Image
Drupal Site Error

We don't have a cert for our WWW DNS Record:

Image
No Cert for WWW