image

Acesse bootcamps ilimitados e +650 cursos

50
%OFF
Article image
Jader Greiner
Jader Greiner26/05/2024 10:10
Compartilhe

Criando um Servidor EC2 e um Banco de Dados RDS para WordPress com Terraform

  • #Terraform

Neste artigo, vou mostrar como provisionar um servidor EC2 e um banco de dados RDS na AWS para hospedar um site WordPress utilizando Terraform. Vamos criar uma infraestrutura completa, incluindo uma VPC, sub-redes, gateway de Internet, tabelas de roteamento e grupos de segurança.

O que é Terraform?

Terraform é uma ferramenta de Infraestrutura como Código (IaC) que permite definir, provisionar e gerenciar recursos de infraestrutura em diversos provedores de nuvem usando uma linguagem de configuração declarativa.

Infraestrutura a ser Provisionada

  • VPC (Virtual Private Cloud): Rede isolada na AWS onde todos os outros recursos serão provisionados.
  • Sub-redes: Duas sub-redes públicas para distribuir recursos em diferentes zonas de disponibilidade.
  • Internet Gateway: Permite que as instâncias na VPC se comuniquem com a Internet.
  • Tabela de Roteamento: Define como o tráfego será roteado dentro da VPC.
  • Grupos de Segurança: Controla o tráfego de entrada e saída para as instâncias EC2 e o banco de dados RDS.
  • Instância EC2: Servidor onde o WordPress será instalado.
  • Banco de Dados RDS MySQL: Armazenamento dos dados do WordPress.

Código Terraform

Provider

Primeiro, definimos o provedor AWS e a região onde os recursos serão provisionados:

provider "aws" {
region = "us-east-2" # Substitua pela região desejada
}

VPC

Criamos a VPC com um bloco CIDR de 10.0.0.0/16 e habilitamos suporte a DNS:

resource "aws_vpc" "main" {
cidr_block           = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support   = true
tags = {
  Name = "main_vpc"
}
}

Sub-redes

Duas sub-redes públicas são criadas em diferentes zonas de disponibilidade:

resource "aws_subnet" "main1" {
vpc_id                  = aws_vpc.main.id
cidr_block              = "10.0.1.0/24"
availability_zone       = "us-east-2a"
map_public_ip_on_launch = true

tags = {
  Name = "main_subnet1"
}
}

resource "aws_subnet" "main2" {
vpc_id                  = aws_vpc.main.id
cidr_block              = "10.0.2.0/24"
availability_zone       = "us-east-2b"
map_public_ip_on_launch = true
tags = {
  Name = "main_subnet2"
}
}

Internet Gateway e Tabela de Roteamento

Um gateway de Internet e uma tabela de roteamento são criados e associados às sub-redes:

resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id

tags = {
  Name = "main_igw"
}
}

resource "aws_route_table" "main" {
vpc_id = aws_vpc.main.id

route {
  cidr_block = "0.0.0.0/0"
  gateway_id = aws_internet_gateway.main.id
}

tags = {
  Name = "main_route_table"
}
}

resource "aws_route_table_association" "main1" {
subnet_id      = aws_subnet.main1.id
route_table_id = aws_route_table.main.id
}

resource "aws_route_table_association" "main2" {
subnet_id      = aws_subnet.main2.id
route_table_id = aws_route_table.main.id
}

Grupos de Segurança

Definimos grupos de segurança para a instância EC2 e o RDS:

resource "aws_security_group" "ec2_sg" {
name   = "ec2_security_group"
vpc_id = aws_vpc.main.id

ingress {
  from_port   = 22
  to_port     = 22
  protocol    = "tcp"
  cidr_blocks = ["0.0.0.0/0"] # Permite acesso SSH de qualquer lugar
}

ingress {
  from_port   = 80
  to_port     = 80
  protocol    = "tcp"
  cidr_blocks = ["0.0.0.0/0"] # Permite acesso HTTP de qualquer lugar
}

ingress {
  from_port   = 443
  to_port     = 443
  protocol    = "tcp"
  cidr_blocks = ["0.0.0.0/0"] # Permite acesso HTTPS de qualquer lugar
}

ingress {
  from_port   = 8
  to_port     = 0
  protocol    = "icmp"
  cidr_blocks = ["0.0.0.0/0"] # Permite acesso ICMP (ping) de qualquer lugar
}

egress {
  from_port   = 0
  to_port     = 0
  protocol    = "-1"
  cidr_blocks = ["0.0.0.0/0"] # Permite todo o tráfego de saída
}

tags = {
  Name = "ec2_security_group"
}
}

resource "aws_security_group" "rds_sg" {
vpc_id = aws_vpc.main.id

ingress {
  from_port   = 3306
  to_port     = 3306
  protocol    = "tcp"
  cidr_blocks = ["10.0.1.0/24"]
}

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

tags = {
  Name = "rds_security_group"
}
}

Instância EC2

Provisionamos a instância EC2 e configuramos o WordPress:

data "aws_ami" "ubuntu" {
most_recent = true

filter {
  name   = "name"
  values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}

filter {
  name   = "virtualization-type"
  values = ["hvm"]
}

owners = ["099720109477"]
}

resource "aws_instance" "wordpress" {
ami                         = data.aws_ami.ubuntu.id
instance_type               = "t2.micro"
subnet_id                   = aws_subnet.main1.id
vpc_security_group_ids      = [aws_security_group.ec2_sg.id]
associate_public_ip_address = true

user_data = <<-EOF
         #!/bin/bash
         apt-get update
         apt-get install -y apache2 ssl-cert
         
         # Configure Apache to listen on port 80 and 443
         cat << 'APACHE_CONFIG' > /etc/apache2/sites-available/default-ssl.conf
         <IfModule mod_ssl.c>
           <VirtualHost *:80>
             ServerAdmin webmaster@localhost
             DocumentRoot /var/www/html
             ErrorLog /var/log/apache2/error.log
             CustomLog /var/log/apache2/access.log combined
           </VirtualHost>
         
           <VirtualHost *:443>
             ServerAdmin webmaster@localhost
             DocumentRoot /var/www/html
             ErrorLog /var/log/apache2/error.log
             CustomLog /var/log/apache2/access.log combined
         
             SSLEngine on
             SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
             SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
           </VirtualHost>
         </IfModule>
         APACHE_CONFIG
         
         a2ensite default-ssl
         a2enmod ssl
         systemctl restart apache2
         
         # Install MySQL
         apt-get install -y mysql-server
         systemctl start mysql
         systemctl enable mysql
         
         # Install PHP and extensions
         apt-get install -y php libapache2-mod-php php-mysql
         
         # Download and configure WordPress
         cd /var/www/html
         wget http://wordpress.org/latest.tar.gz
         tar -xzf latest.tar.gz
         chown -R www-data:www-data /var/www/html/wordpress
         find /var/www/html/wordpress/ -type d -exec chmod 750 {} \;
         find /var/www/html/wordpress/ -type f -exec chmod 640 {} \;
         mv wordpress/* .
         rm -rf wordpress
         systemctl restart apache2
         EOF

tags = {
  Name = "Wordpress_Server"
}
}

output "wordpress_public_dns" {
description = "Public DNS of the WordPress EC2 instance"
value       = aws_instance.wordpress.public_dns
}

Banco de Dados RDS

Criamos o banco de dados MySQL no RDS:

resource "aws_db_instance" "mysql" {
identifier        = "my-mysql-db"
engine            = "mysql"
engine_version    = "8.0"
instance_class    = "db.t3.micro"
allocated_storage = 20
storage_type      = "gp2"

backup_retention_period = 0
maintenance_window      = "Mon:00:00-Mon:03:00"

db_name              = "wordpressdb"
username             = "admin"
password             = "password"
parameter_group_name = "default.mysql8.0"

vpc_security_group_ids = [aws_security_group.rds_sg.id]
db_subnet_group_name   = aws_db_subnet_group.main.name

skip_final_snapshot = true

tags = {
  Name = "Wordpress_RDS"
}
}

resource "aws_db_subnet_group" "main" {
name       = "main"
subnet_ids = [aws_subnet.main1.id, aws_subnet.main2.id]

tags = {
  Name = "main_subnet_group"
}
}

Dicas e Recomendações Especiais

  1. Caso de Estudo: Este exemplo é um caso de estudo e não possui todas as configurações de segurança necessárias para um ambiente de produção.
  2. Segurança: Permitir acesso SSH de qualquer lugar (0.0.0.0/0) não é recomendado para ambientes de produção. Restringir o acesso a um intervalo de IPs específico para maior segurança.
  3. Configurações Específicas: No código, algumas configurações são específicas à sua conta, como a região (us-east-2) e os IDs de AMI. Certifique-se de adaptar essas configurações às suas necessidades.
  4. Credenciais: Nunca armazene credenciais diretamente no código. Utilize práticas seguras, como o AWS Secrets Manager ou variáveis de ambiente, para gerenciar suas credenciais.

Conclusão

Neste artigo, provisionamos uma infraestrutura completa na AWS para hospedar um site WordPress utilizando Terraform. Criamos uma VPC, sub-redes, gateway de Internet, tabelas de roteamento, grupos de segurança, uma instância EC2 e um banco de dados RDS. Com essa infraestrutura, você está pronto para hospedar seu site WordPress na AWS de forma eficiente e escalável.

Espero que este guia tenha sido útil. Fique à vontade para deixar comentários e compartilhar suas experiências.

Código completo abaixo:

provider "aws" {
 region = "us-east-2" # Substitua pela região desejada
}

# Criar VPC
resource "aws_vpc" "main" {
 cidr_block = "10.0.0.0/16"
 # ... other VPC configuration
 enable_dns_hostnames = true
 enable_dns_support  = true

 tags = {
Name = "main_vpc"
 }
}

# Criar sub-rede 1
resource "aws_subnet" "main1" {
 vpc_id         = aws_vpc.main.id
 cidr_block       = "10.0.1.0/24"
 availability_zone    = "us-east-2a"
 map_public_ip_on_launch = true


 tags = {
Name = "main_subnet1"
 }
}

# Criar sub-rede 2
resource "aws_subnet" "main2" {
 vpc_id         = aws_vpc.main.id
 cidr_block       = "10.0.2.0/24"
 availability_zone    = "us-east-2b"
 map_public_ip_on_launch = true


 tags = {
Name = "main_subnet2"
 }
}

# Criar gateway de Internet
resource "aws_internet_gateway" "main" {
 vpc_id = aws_vpc.main.id

 tags = {
Name = "main_igw"
 }
}

# Criar tabela de roteamento
resource "aws_route_table" "main" {
 vpc_id = aws_vpc.main.id

 route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
 }

 tags = {
Name = "main_route_table"
 }
}

# Associar a tabela de roteamento à sub-rede 1
resource "aws_route_table_association" "main1" {
 subnet_id   = aws_subnet.main1.id
 route_table_id = aws_route_table.main.id
}

# Associar a tabela de roteamento à sub-rede 2
resource "aws_route_table_association" "main2" {
 subnet_id   = aws_subnet.main2.id
 route_table_id = aws_route_table.main.id
}

# Criar grupo de segurança para a instância EC2
resource "aws_security_group" "ec2_sg" {
 name  = "ec2_security_group"
 vpc_id = aws_vpc.main.id

 ingress {
from_port  = 22
to_port   = 22
protocol  = "tcp"
cidr_blocks = ["0.0.0.0/0"] # Allow SSH access from anywhere (not recommended for production)
 }

 ingress {
from_port  = 80
to_port   = 80
protocol  = "tcp"
cidr_blocks = ["0.0.0.0/0"] # Allow HTTP access from anywhere
 }

 ingress {
from_port  = 443
to_port   = 443
protocol  = "tcp"
cidr_blocks = ["0.0.0.0/0"] # Allow HTTPS access from anywhere
 }

 ingress {
from_port  = 8
to_port   = 0
protocol  = "icmp"
cidr_blocks = ["0.0.0.0/0"] # Allow ICMP (ping) access from anywhere
 }

 egress {
from_port  = 0
to_port   = 0
protocol  = "-1"
cidr_blocks = ["0.0.0.0/0"] # Allow all outbound traffic
 }

 tags = {
Name = "ec2_security_group"
 }
}

#Terraform Data Block - To Lookup Latest Ubuntu 20.04 AMI Image
data "aws_ami" "ubuntu" {
 most_recent = true

 filter {
name  = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
 }

 filter {
name  = "virtualization-type"
values = ["hvm"]
 }

 owners = ["099720109477"]
}

# Criar instância EC2
resource "aws_instance" "wordpress" {
 ami             = data.aws_ami.ubuntu.id
 instance_type        = "t2.micro" # Elegível para o free tier
 subnet_id          = aws_subnet.main1.id
 vpc_security_group_ids   = [aws_security_group.ec2_sg.id]
 associate_public_ip_address = true

 user_data = <<-EOF
    #!/bin/bash
    apt-get update
    apt-get install -y apache2 ssl-cert
    
    # Configure Apache to listen on port 80 and 443
    cat << 'APACHE_CONFIG' > /etc/apache2/sites-available/default-ssl.conf
    <IfModule mod_ssl.c>
     <VirtualHost *:80>
      ServerAdmin webmaster@localhost
      DocumentRoot /var/www/html
      ErrorLog /var/log/apache2/error.log
      CustomLog /var/log/apache2/access.log combined
     </VirtualHost>
    
     <VirtualHost *:443>
      ServerAdmin webmaster@localhost
      DocumentRoot /var/www/html
      ErrorLog /var/log/apache2/error.log
      CustomLog /var/log/apache2/access.log combined
    
      SSLEngine on
      SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
      SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
     </VirtualHost>
    </IfModule>
    APACHE_CONFIG
    
    a2ensite default-ssl
    a2enmod ssl
    systemctl restart apache2
    
    # Install MySQL
    apt-get install -y mysql-server
    systemctl start mysql
    systemctl enable mysql
    
    # Install PHP and extensions
    apt-get install -y php libapache2-mod-php php-mysql
    
    # Download and configure WordPress
    cd /var/www/html
    wget http://wordpress.org/latest.tar.gz
    tar -xzf latest.tar.gz
    chown -R www-data:www-data /var/www/html/wordpress
    find /var/www/html/wordpress/ -type d -exec chmod 750 {} \;
    find /var/www/html/wordpress/ -type f -exec chmod 640 {} \;
    mv wordpress/* .
    rm -rf wordpress
    systemctl restart apache2
    EOF



 tags = {
Name = "Wordpress_Server"
 }

}

output "wordpress_public_dns" {
 description = "Public DNS of the WordPress EC2 instance"
 value    = aws_instance.wordpress.public_dns
}

# Criar grupo de segurança para o RDS
resource "aws_security_group" "rds_sg" {
 vpc_id = aws_vpc.main.id

 ingress {
from_port  = 3306
to_port   = 3306
protocol  = "tcp"
cidr_blocks = ["10.0.1.0/24"]
 }

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

 tags = {
Name = "rds_security_group"
 }
}


# Criar banco de dados RDS MySQL
resource "aws_db_instance" "mysql" {
 identifier    = "my-mysql-db"
 engine      = "mysql"
 engine_version  = "8.0"     # Versão compatível com db.t3.micro
 instance_class  = "db.t3.micro" # Elegível para o free tier
 allocated_storage = 20
 storage_type   = "gp2"

 # Remove backup configuration
 backup_retention_period = 0           # Set backup retention period to 0 to disable automated backups
 backup_window      = ""          # Clear the backup window
 maintenance_window   = "Mon:00:00-Mon:03:00" # Keep the maintenance window

 db_name       = "wordpressdb"
 username       = "admin"
 password       = "password"
 parameter_group_name = "default.mysql8.0"

 vpc_security_group_ids = [aws_security_group.rds_sg.id]
 db_subnet_group_name  = aws_db_subnet_group.main.name

 skip_final_snapshot = true


 tags = {
Name = "Wordpress_RDS"
 }
}

# Criar grupo de sub-rede do RDS
resource "aws_db_subnet_group" "main" {
 name    = "main"
 subnet_ids = [aws_subnet.main1.id, aws_subnet.main2.id]

 tags = {
Name = "main_subnet_group"
 }
}
Compartilhe
Recomendados para você
Decola Tech 2025
Suzano - Python Developer
Bootcamp Bradesco - Java Cloud Native
Comentários (0)