PHP Webserver with loadbalancers

Note: This example is still undergoing tests!

If you encounter any issue trying to run this, please contact support@faxter.com

  1. Project Setup: Creates a Faxter project.
  2. Network Configuration: Sets up a private network with subnets and a router connecting to the external network.
  3. Security Groups: Defines security groups for the web servers and the database server to control traffic.
  4. SSH Keys: Manages SSH keys for secure access.
  5. Volumes: Creates a persistent volume for the MySQL database.
  6. Servers: Deploys three PHP web servers and one MySQL database server with appropriate cloud-init scripts.
  7. Load Balancer: Sets up a load balancer with a public IP to distribute traffic to the web servers.

Terraform Configuration

terraform {
  required_providers {
    faxter = {
      source  = "local/faxter/faxter"
      version = "0.1.0"
    }
  }
  required_version = ">= 1.0.0"
}


provider "faxter" {
  token = var.faxter_token
}

variable "faxter_token" {
  description = "API token for Faxter provider"
  type        = string
}

variable "ssh_public_key" {
  description = "Path to SSH public key"
  type        = string
}

variable "project" {
  description = "Project name"
  type        = string
}

# 1. Create a Private Network with Subnets
resource "faxter_network" "private_network" {
  project = var.project
  name    = "private-network"

  subnets {
    name = "web-subnet"
    cidr = "192.168.10.0/24"
    gateway = "192.168.10.1"
    static_routes {
        destination = "192.168.11.0/24"
        nexthop     = "192.168.10.1"
    }

  }

  subnets {
    name = "db-subnet"
    cidr = "192.168.11.0/24"
    gateway = "192.168.11.1"
    static_routes {
        destination = "192.168.10.0/24"
        nexthop     = "192.168.11.1"
    }
  }
}

# 2. Set Up a Router to Connect the Private Network to the External Network
resource "faxter_router" "private_router" {
  project          = var.project
  name             = "private-router"
  connect_external = true
  subnets = [
    faxter_network.private_network.subnets[0].name, # web-subnet
    faxter_network.private_network.subnets[1].name  # db-subnet
  ]
}

# 3. Define Security Groups

## 3.1 Security Group for Load Balancer
resource "faxter_security_group" "lb_sg" {
  project = var.project
  name    = "lb-sg"

  rules {
    protocol         = "tcp"
    port_range_min   = 80
    port_range_max   = 80
    direction        = "ingress"
    remote_ip_prefix = "0.0.0.0/0" # Allow HTTP from anywhere
  }

  rules {
    protocol         = "tcp"
    port_range_min   = 443
    port_range_max   = 443
    direction        = "ingress"
    remote_ip_prefix = "0.0.0.0/0" # Allow HTTPS from anywhere
  }

  rules {
    protocol         = "tcp"
    port_range_min   = 22
    port_range_max   = 22
    direction        = "ingress"
    remote_ip_prefix = "0.0.0.0/0" # Replace with your IP or range
  }
}

## 3.2 Security Group for Web Servers
resource "faxter_security_group" "web_sg" {
  project = var.project
  name    = "web-sg"

  rules {
    protocol       = "tcp"
    port_range_min = 80
    port_range_max = 80
    direction      = "ingress"
    remote_group_id = faxter_security_group.lb_sg.id # Allow traffic from Load Balancer SG
  }

  rules {
    protocol         = "tcp"
    port_range_min   = 22
    port_range_max   = 22
    direction        = "ingress"
    remote_ip_prefix = "0.0.0.0/0" # Replace with your IP or range
  }
}

## 3.3 Security Group for Database Server
resource "faxter_security_group" "db_sg" {
  project = var.project
  name    = "db-sg"

  rules {
    protocol        = "tcp"
    port_range_min  = 3306
    port_range_max  = 3306
    direction       = "ingress"
    remote_group_id = faxter_security_group.web_sg.id # Allow traffic from Web SG
  }

  rules {
    protocol         = "tcp"
    port_range_min   = 22
    port_range_max   = 22
    direction        = "ingress"
    remote_ip_prefix = "0.0.0.0/0" # Replace with your IP or range
  }
}

# 4. Manage SSH Keys

## 4.1 SSH Key for Web Servers
resource "faxter_ssh_key" "web_ssh" {
  project    = var.project
  name       = "web-ssh-key"
  public_key = file(var.ssh_public_key)
}

## 4.2 SSH Key for Database Server
resource "faxter_ssh_key" "db_ssh" {
  project    = var.project
  name       = "db-ssh-key"
  public_key = file(var.ssh_public_key)
}

# 5. Create a Volume for the MySQL Database
resource "faxter_volume" "db_volume" {
  project = var.project
  name    = "db-data"
  storage = 100 # Size in GB
}

# 6. Deploy the MySQL Database Server
resource "faxter_server" "db_server" {
  depends_on = [ faxter_network.private_network ]
  project             = var.project
  name                = "mysql-db-server"
  key_name            = faxter_ssh_key.db_ssh.name
  flavor              = "gold" # Choose appropriate flavor
  image               = "Ubuntu2204"
  security_groups     = [faxter_security_group.db_sg.name]
  sub_networks        = [faxter_network.private_network.subnets[1].name] # db-subnet
  request_floating_ip = false
  volumes          = [faxter_volume.db_volume.name]

  cloud_init = base64encode(data.local_file.db_cloud_init.content)
}
data "local_file" "db_cloud_init" {
  filename = "${path.module}/db_cloud_init.yaml"
}

# 7. Deploy Three PHP Web Servers
resource "faxter_server" "web_servers" {
  depends_on = [ faxter_network.private_network ]
  count            = 3
  project             = var.project
  name                = "php-web-server-${count.index + 1}"
  key_name            = faxter_ssh_key.web_ssh.name
  flavor              = "silver" # Choose appropriate flavor
  image               = "Ubuntu2204"
  security_groups     = [faxter_security_group.web_sg.name]
  sub_networks        = [faxter_network.private_network.subnets[0].name] # web-subnet
  request_floating_ip = false
  cloud_init = base64encode(data.local_file.web_cloud_init.content)

}

data "local_file" "web_cloud_init" {
  filename = "${path.module}/web_cloud_init.yaml"
}

# 8. Set Up the Load Balancer
resource "faxter_loadbalancer" "web_lb" {
   depends_on = [
    faxter_network.private_network, # Ensure the network is created and connected to router before loadbalancer deployment
    faxter_router.private_router
  ]
  project             = var.project
  name                = "web-loadbalancer"
  port                = 80
  sub_networks        = [faxter_network.private_network.subnets[0].name] # web-subnet
  request_floating_ip = true
  ssl_enabled         = false
  security_groups     = [faxter_security_group.lb_sg.name]
  key_name            = faxter_ssh_key.web_ssh.name

  dynamic "servers" {
    # for_each is your list of created servers
    for_each = faxter_server.web_servers[*]

    # content describes each 'servers { ... }' block
    content {
      ip       = servers.value.ip_addresses[0]
      port     = 80
      endpoint = "/"
    }
  }
}

db_cloud_init.yaml

#cloud-config
package_update: true
packages:
  - mysql-server
runcmd:
  # Configure MySQL
  - systemctl enable mysql
  - systemctl start mysql
  - mysql -e "CREATE USER 'phpuser'@'%' IDENTIFIED BY 'YOUR_DB_PASSWORD';"
  - mysql -e "CREATE DATABASE phpsite;"
  - mysql -e "GRANT ALL PRIVILEGES ON phpsite.* TO 'phpuser'@'%';"
  - mysql -e "FLUSH PRIVILEGES;"

  # Format and mount the attached volume
  - mkfs.ext4 /dev/vdb  # Replace /dev/vdb with the appropriate device name for the attached volume
  - mkdir -p /mnt/mysql_data
  - mount /dev/vdb /mnt/mysql_data
  - echo "/dev/vdb /mnt/mysql_data ext4 defaults 0 0" >> /etc/fstab

  # Move MySQL data directory to the mounted volume
  - systemctl stop mysql
  - mv /var/lib/mysql /mnt/mysql_data/mysql
  - ln -s /mnt/mysql_data/mysql /var/lib/mysql
  - chown -R mysql:mysql /mnt/mysql_data/mysql
  - systemctl start mysql

web_cloud_init.yaml

#cloud-config
package_update: true
packages:
  - apache2
  - php
  - libapache2-mod-php
  - git
runcmd:
  - systemctl enable apache2
  - systemctl start apache2
  - rm -fr /var/www/html
  - git clone https://github.com/banago/simple-php-website.git /var/www/html
  - chown -R www-data:www-data /var/www/html
  - systemctl restart apache2

terraform.tfvars

faxter_token       = "YOUR_AKI_TOKEN"
ssh_public_key     = "~/.ssh/id_rsa.pub"
project            = "PROJECT_NAME"

Explanation & Placeholders

  1. Private Network (faxter_network)

    • Subnets: Two subnets are created: web-subnet for PHP web servers. db-subnet for the MySQL database server.
    • CIDR Blocks: Adjust CIDR blocks (192.168.10.0/24 and 192.168.11.0/24) if needed.
    • Router (faxter_router)

    Connects the private network to the external/public network. Name: "private-router" can be changed as needed. 3. Security Groups (faxter_security_group)

    • Web SG (web-sg): Allows HTTP (port 80) traffic from the Load Balancer security group. Allows SSH (port 22) from your specified IP.
    • DB SG (db-sg): Allows MySQL (port 3306) traffic from the Web SG. Allows SSH (port 22) from your specified IP.
    • Load Balancer SG (lb-sg): Allows HTTP (port 80) and HTTPS (port 443) from anywhere. Allows SSH (port 22) from your specified IP.

    Placeholders to Replace:

    • "YOUR_SSH_ACCESS_IP/32": Replace with your actual IP address or CIDR range for SSH access.
    • "YOUR_PUBLIC_SSH_KEY": Replace with your actual SSH public key content.
    • SSH Keys (faxter_ssh_key)

    Web Servers SSH Key (web_ssh) and DB Server SSH Key (db_ssh):

    - Replace "YOUR_PUBLIC_SSH_KEY" with your actual SSH public key.
    
    1. Volume (faxter_volume)

    2. Database Volume (db_volume):

      • Name: "db-data" can be changed as needed.
      • Storage: Adjust the storage size as required.
    3. MySQL Database Server (faxter_server.db_server)
    4. Cloud-Init Script:
      • Installs MySQL server.
      • Creates a MySQL user (phpuser) and database (phpsite).
      • Placeholders to Replace:
        • "YOUR_DB_PASSWORD": Replace with a secure password for the MySQL user.
    5. PHP Web Servers (faxter_server.web_servers)

    6. Count: Deploys three instances (count = 3).

    7. Cloud-Init Script:
      • Installs Apache, PHP, and Git.
      • Clones your PHP application from GitHub into /var/www/html.
    8. Placeholders to Replace:
      • "YOUR_GITHUB_REPO": Replace with your actual GitHub repository URL.
    9. Load Balancer (faxter_loadbalancer.web_lb)

    10. Distributes incoming HTTP traffic to the three PHP web servers.

    11. Port: Listens on port 80.
    12. Public IP: Automatically requests a floating/public IP.
    13. SSL: Disabled (ssl_enabled = false). Enable and configure SSL as needed.
    14. Servers: Dynamically includes the three web servers by referencing their private IPs.

Additional Notes

  • Security: Ensure that sensitive information like database passwords is managed securely, possibly using Terraform's sensitive variables.
  • Scaling: Adjust the number of web servers (count) based on your scalability needs.
  • Monitoring & Logging: Implement monitoring and logging solutions as needed for production environments.
  • SSL Configuration: If you plan to enable HTTPS, ensure SSL certificates are properly managed and configured.