Configuring Apache Virtual Hosts on Ubuntu with Terraform

For hosting multiple websites, administrators commonly use the ‘Virtual Hosting’ technique. Virtual hosting allows the hosting of multiple websites on a single server and can be achieved using either the ‘IP-based’ method or the ‘name-based’ approach. In ‘IP-based’ hosting, each website has a distinct IP address. On the other hand, ‘name-based’ hosting involves multiple domain names running on a single IP address.

There are numerous tools available today for automating cloud-based infrastructure, and Terraform is one such tool that has recently gained enormous popularity in the DevOps world. Terraform, an open-source tool developed by HashiCorp, uses its own HashiCorp Configuration Language (HCL) to provision multiple cloud service providers. Essentially, Terraform compares your current infrastructure configuration to the desired state and only modifies those parts of the infrastructure that are required to achieve the desired state.

What Will We Cover?

In this tutorial, we will demonstrate how to host two virtual hosts on an Ubuntu 22.04 system using Terraform, utilizing the Apache web server to achieve this setup.

Pre-Flight Check

Before proceeding, ensure you meet the following prerequisites:

  1. Familiarity with Terraform basics.
  2. Terraform installed on your system.
  3. AWS account configured on your local system.
  4. Understanding of setting up a virtual host using the Apache web server.

Setting Up the Lab

We will use an Ubuntu 22.04 server to install the Apache web server. We’ll configure two virtual hosts, each serving a unique index.html file:

  • “Webpage from: Virtual Host 1.” for vhost1
  • “Webpage from: Virtual Host 2.” for vhost2

For simplicity, the domain names for the two virtual hosts (vhosts) are mapped to the localhost IP address (127.0.0.1). This setup uses the following files:

  1. userdata.sh: A bash script to set up the EC2 server and configure the web server for virtual hosts.
  2. sec-grp.tf: Defines a resource for creating a security group.
  3. vhost-template.tf: Contains the actual configuration for the virtual hosts.
  4. main.tf: Declares the web server resource and the rest of the infrastructure.

Multiple files help maintain clarity and facilitate code review. Let’s proceed with the main steps:

Step 1: Create a directory for your project files:

$ mkdir virtual-hosts-terraform

Step 2: Set up the EC2 instance for virtual hosting using a userdata script to automate common server configurations:

$ vi userdata.sh
#!/bin/bash

sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get install apache2 -y
sudo systemctl restart apache2
sudo sh -c "echo 127.0.0.1 www.vhost1.com >> /etc/hosts"
sudo sh -c "echo 127.0.0.1 www.vhost2.com >> /etc/hosts"
sudo mkdir -p /var/www/vhost_1/public_html
sudo mkdir -p /var/www/vhost_2/public_html
sudo chown -R $USER:$USER /var/www/vhost_1/public_html
sudo chown -R $USER:$USER /var/www/vhost_2/public_html
sudo chmod -R 755 /var/www
sudo echo "Webpage from: Virtual Host 1." > /var/www/vhost_1/public_html/index.html
sudo echo "Webpage from: Virtual Host 2." > /var/www/vhost_2/public_html/index.html
sudo cp /home/ubuntu/vhosts.conf /etc/apache2/sites-available/vhosts.conf
sudo a2ensite vhosts.conf
sudo a2dissite 000-default.conf
sudo systemctl restart apache2

Step 3: Configure a security group resource to set the traffic rules, allowing SSH and HTTP traffic:

$ vi sec-grp.tf
resource "aws_security_group" "ec2-sg" {
  name = "ec2-grp"
  description = "Set Ingress and Egress Rules"

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

Step 4: Define the configuration for each virtual host:

$ vi vhost-template.conf
<VirtualHost *:80>
    ServerAdmin admin@vhost1.com
    ServerName vhost1
    ServerAlias www.vhost1.com
    DocumentRoot /var/www/vhost_1/public_html
    ErrorLog ${APACHE_LOG_DIR}/error.log
</VirtualHost>

<VirtualHost *:80>
    ServerAdmin admin@vhost2.com
    ServerName vhost2
    ServerAlias www.vhost2.com
    DocumentRoot /var/www/vhost_2/public_html
    ErrorLog ${APACHE_LOG_DIR}/error.log
</VirtualHost>

Step 5: Set up the main Terraform configuration file:

$ vi main.tf
provider "aws" {
  region = "us-east-1"
}

resource "aws_instance" "webserver" {
  ami                    = "ami-09d56f8956ab235b3"
  instance_type          = "t2.micro"
  key_name               = "Name-of-EC2-Key-Pair"
  vpc_security_group_ids = [aws_security_group.ec2-sg.id]
  associate_public_ip_address = true

  provisioner "file" {
    source      = "vhost-template.conf"
    destination = "/home/ubuntu/vhosts.conf"

    connection {
      type        = "ssh"
      user        = "ubuntu"
      private_key = "${file("/Path/to/EC2-Key-Pair")}"
      host        = "${self.public_dns}"
    }
  }

  user_data = "${file("userdata.sh")}"

  tags = {
    Name = "VirtualHostTutorial"
  }
}

output "IPAddress" {
  value = "${aws_instance.webserver.public_dns}"
}

The file provisioner uploads the ‘vhost-template.conf’ file to the EC2 instance, and the ‘file’ command executes the userdata script.

File Structure

Step 6: Initialize the project directory and apply the configuration:

$ terraform init
$ terraform apply

Initializing project directory

Applying the Terraform setup

Setup successfully completed

Testing the Setup

SSH into your instance and run the following command to test the virtual host setup:

$ curl www.vhost1.com

The above command should return the message from the virtual host1 index page. Similarly, run this command to test virtual host2:

$ curl www.vhost2.com

Testing the setup

Conclusion

Congratulations! You have successfully set up virtual hosting on your system using Terraform. This tutorial can be a foundation for more complex Terraform implementations. Give it a try and explore further possibilities.

FAQ

What is virtual hosting?

Virtual hosting allows multiple domain names to be served by a single web server. It can be implemented using IP-based or name-based hosting.

What is Terraform?

Terraform is an open-source tool by HashiCorp for automating cloud infrastructure. It uses HashiCorp Configuration Language (HCL) to define and provision infrastructure as code.

Why use the Apache web server in this setup?

Apache is a widely-used open-source web server that supports name-based and IP-based virtual hosting, making it a popular choice for hosting multiple domains.

Can I add more virtual hosts using this setup?

Yes, you can add more virtual hosts by modifying the vhost-template.conf to include additional <VirtualHost> entries.