Criando um Servidor EC2 e um Banco de Dados RDS para WordPress com 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
- 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.
- 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. - 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. - 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"
}
}