Masdika Loading..
Masdika.ID

DevOps Engineer

Cloud Engineer

System Administrator

  • Home
  • Portfolio
  • Services
  • Resume
  • Skills
  • Blog
  • Contact
Masdika.ID

DevOps Engineer

Cloud Engineer

System Administrator

Download CV

Recent Posts

  • Deploy Website High-Availability di AWS dengan Terraform, Docker (Nginx) & Load Balancer (ALB + HTTPS/ACM)
  • Tutorial AWS Lengkap: Belajar EC2, S3, dan IAM dari Nol
  • Jangan Gunakan latest Tag pada Docker Images! Ini Alasannya
  • Panduan Lengkap Anti-DDoS: Installasi Iptables, Hardening, dan Cloudflare Proxy
  • Panduan Lengkap Install K3s di Ubuntu dan Konfigurasi Remote Kubectl dari Windows PC/Laptop

Recent Comments

  1. Alif on Jangan Gunakan latest Tag pada Docker Images! Ini Alasannya
  2. Sahrull on Panduan Lengkap Anti-DDoS: Installasi Iptables, Hardening, dan Cloudflare Proxy
  3. VSTRA on Cara Cerdas Menguasai Kubernetes (K8s): Panduan Lengkap Orkestrasi Kontainer untuk Developer Modern
  4. Rikiy on Cara Mudah Deploy Website Node.js Menggunakan Docker
  5. Masdika.BIZ.ID on Disaster Recovery Cluster (DRC) WordPress dengan MariaDB Galera dan Load Balancer Caddy

Categories

  • Tutorial

Masdika.ID

  • About
  • Terms & Conditions
  • Privacy Policy
BLOG POST

Deploy Website High-Availability di AWS dengan Terraform, Docker (Nginx) & Load Balancer (ALB + HTTPS/ACM)

September 8, 2025 Tutorial by Masdika.ID
Deploy Website High-Availability di AWS dengan Terraform, Docker (Nginx) & Load Balancer (ALB + HTTPS/ACM)

Lab ini disusun dengan pendekatan praktis step-by-step, sehingga bahkan pemula bisa langsung mengikuti tanpa bingung. Kita mulai dari menyiapkan akun AWS dan user IAM, menginstal Terraform, menulis file konfigurasi .tf, lalu membuat sertifikat SSL di ACM lewat Console (klik per klik). Setelah itu, kita menambahkan record CNAME di DNS (Cloudflare/Route53) agar domain terhubung dengan benar, hingga akhirnya website otomatis redirect ke HTTPS.

Setiap langkah dilengkapi dengan perintah verifikasi dan juga tips troubleshooting umum (termasuk error klasik seperti 502 Bad GatewayπŸ”₯

Gambaran Arsitektur

  • ALB terminasi TLS (pakai ACM). EC2 cukup HTTP:80.
  • Failover: kalau EC2 #1 mati, trafik tetap ke EC2 #2.

1) Prasyarat Wajib

  1. Akun AWS aktif (region contoh: ap-southeast-1, Singapore).
  2. IAM User (disarankan khusus lab) dengan akses:
    • Untuk lab cepat: AdministratorAccess (⚠️ hanya lab). Atau minimal: EC2, ELBv2, VPC, ACM, Route53.
  3. AWS CLI & Terraform terpasang di vps/vm Anda.
  4. Konfigurasi kredensial: aws configure # isikan: AWS Access Key, Secret, region: ap-southeast-1, output: json
  5. EC2 Key Pair (mis. masdika-key) untuk SSH.
    • Simpan .pem, set permission: chmod 600 masdika-key.pem.
  6. Domain (mis. syslab.my.id) & akses DNS (Cloudflare/Route53).

Keamanan: jangan commit kredensial ke git. Pakai aws configure/ENV. πŸ”’

2) Siapkan Proyek Terraform

Struktur folder

aws-lb/
β”œβ”€ main.tf
β”œβ”€ variables.tf
β”œβ”€ outputs.tf
└─ terraform.tfvars

2.1) variables.tf

variable "key_name" {
  description = "Nama Key Pair EC2 untuk SSH"
  type        = string
}

variable "certificate_arn" {
  description = "ARN sertifikat ACM (region sama dengan ALB: ap-southeast-1)"
  type        = string
}

2.2) outputs.tf

output "alb_dns" {
  description = "DNS publik ALB"
  value       = aws_lb.app_lb.dns_name
}

output "alb_zone_id" {
  description = "Hosted zone id ALB (untuk alias record)"
  value       = aws_lb.app_lb.zone_id
}

2.3) terraform.tfvars

key_name        = "masdika-key"
# ARN diisi setelah ACM Issued (sementara kosongkan, atau isi bila sudah ada)
certificate_arn = "arn:aws:acm:ap-southeast-1:123456789012:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

Kalau belum punya ARN (sertifikat belum dibuat), Anda bisa isi string kosong "" sementara dan aktifkan HTTPS nanti.

2.4) main.tf

rovider "aws" {
  region  = "ap-southeast-1" # ganti region kalau mau
  profile = "default"        # sesuai aws configure
}

# Ambil VPC & Subnets default
data "aws_vpc" "default" {
  default = true
}

data "aws_subnets" "default" {
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.default.id]
  }
}

# Security Group (HTTP, HTTPS, SSH dari IP kamu)
resource "aws_security_group" "web_sg" {
  name        = "web-sg"
  description = "Allow HTTP, HTTPS & SSH"
  vpc_id      = data.aws_vpc.default.id

  # HTTP (80)
  ingress {
    description = "HTTP"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # HTTPS (443)
  ingress {
    description = "HTTPS"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # SSH (22) hanya dari IP kamu
  ingress {
    description = "SSH from my IP"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["206.237.105.16/32"] # ganti kalau IP berubah
  }

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

# EC2 Instances (2 server dengan Docker + Nginx)
resource "aws_instance" "web" {
  count         = 2
  ami           = "ami-0933f1385008d33c4" # Ubuntu Server 24.04 LTS
  instance_type = "t2.micro"
  subnet_id     = element(data.aws_subnets.default.ids, count.index)
  vpc_security_group_ids      = [aws_security_group.web_sg.id]
  associate_public_ip_address = true
  key_name      = var.key_name

  # Kalau script user_data berubah, EC2 otomatis recreate
  user_data_replace_on_change = true

  user_data = <<-EOF
              #!/bin/bash
              set -eux

              # Update & install dependencies
              apt-get update -y
              apt-get install -y ca-certificates curl gnupg lsb-release

              # Setup Docker repo
              install -m 0755 -d /etc/apt/keyrings
              curl -fsSL https://download.docker.com/linux/ubuntu/gpg | tee /etc/apt/keyrings/docker.asc > /dev/null
              chmod a+r /etc/apt/keyrings/docker.asc

              CODENAME=$(lsb_release -cs)
              echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $${CODENAME} stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

              apt-get update -y
              apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

              systemctl enable docker
              systemctl start docker

              # Tunggu Docker benar-benar siap
              sleep 10
              systemctl is-active --quiet docker || (echo "Docker gagal start" && exit 1)

              # Jalankan Nginx di port 80
              docker run -d -p 80:80 --restart always --name web nginx

              # Tambahkan halaman index
              echo "<h1>Hello from Server $(hostname)</h1>" > /tmp/index.html
              docker cp /tmp/index.html web:/usr/share/nginx/html/index.html
              EOF

  tags = {
    Name = "web-${count.index + 1}"
  }
}

# Load Balancer
resource "aws_lb" "app_lb" {
  name               = "web-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.web_sg.id]
  subnets            = data.aws_subnets.default.ids
}

# Target Group
resource "aws_lb_target_group" "tg" {
  name     = "web-tg"
  port     = 80
  protocol = "HTTP"
  vpc_id   = data.aws_vpc.default.id

  health_check {
    path                = "/"
    interval            = 30
    timeout             = 5
    healthy_threshold   = 2
    unhealthy_threshold = 2
    matcher             = "200"
  }
}

# Listener HTTP -> Redirect ke HTTPS
resource "aws_lb_listener" "http" {
  load_balancer_arn = aws_lb.app_lb.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type = "redirect"

    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }
}

# Listener HTTPS (pakai sertifikat ACM)
resource "aws_lb_listener" "https" {
  load_balancer_arn = aws_lb.app_lb.arn
  port              = "443"
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-2016-08"
  certificate_arn   = var.certificate_arn

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.tg.arn
  }
}

# Attach EC2 ke Target Group
resource "aws_lb_target_group_attachment" "attach" {
  count            = 2
  target_group_arn = aws_lb_target_group.tg.arn
  target_id        = aws_instance.web[count.index].id
  port             = 80
}

Catatan: Listener HTTPS dibuat hanya jika certificate_arn tidak kosong.

3) Deploy Bagian Infrastruktur (tanpa HTTPS dulu pun bisa)

cd aws-lb
terraform init
terraform plan -var="key_name=masdika-key"
terraform apply -auto-approve -var="key_name=masdika-key"

Output penting: alb_dns contoh: web-alb-1151437619.ap-southeast-1.elb.amazonaws.com

Saat titik ini, ALB port 80 aktif & mengarah ke 2 EC2 (Docker Nginx). Redirect 80β†’443 belum aktif kalau certificate_arn kosong.

4) Membuat Sertifikat di AWS Certificate Manager (ACM)

Tujuan: mendapat sertifikat untuk lab.syslab.my.id agar ALB bisa HTTPS.

  1. Masuk AWS Console β†’ pilih region ap-southeast-1 (kanan atas).
  2. Di kolom Search, ketik “Certificate Manager” β†’ buka Certificate Manager.
  3. Klik Request (atau Request a certificate).
  4. Pilih Request a public certificate β†’ Next.
  5. Di Add domain names β†’ klik Add another name (jika perlu) β†’ isi: lab.syslab.my.id β†’ Next.
  6. Validation method: pilih DNS validation β†’ Next.
  7. Tags (opsional) β†’ Review β†’ Confirm and request.
  8. Setelah dibuat, klik sertifikatnya β†’ tab Domains β†’ klik domain lab.syslab.my.id β†’ akan tampil CNAME untuk validasi.
    • Name/Record name: mirip _xxxxxxxxxxxxxxxx.lab.syslab.my.id
    • Type: CNAME
    • Value/Record value: mirip _yyyyyyyyyyyyyy.acm-validations.aws
  9. Jangan tambahkan A record di sini. Untuk validasi, cukup CNAME ini saja.

Berikutnya, kita tambahkan CNAME tersebut di DNS provider Anda.

5) Tambahkan CNAME Validasi di Cloudflare (atau Route53)

Cloudflare:

  1. Login β†’ pilih zone syslab.my.id.
  2. Buka tab DNS β†’ klik Add record.
  3. Type: CNAME
  4. Name: tempel persis Record name dari ACM (contoh: _c89b24....lab.syslab.my.id)
  5. Target: tempel persis Record value dari ACM (contoh: _3dd9f....acm-validations.aws)
  6. Proxy: DNS Only (awan abu-abu)
  7. TTL: Auto (atau 300 detik)
  8. Save.

Tunggu 5–30 menit β†’ balik ke halaman sertifikat ACM β†’ status berubah Issued βœ…

Route53 (opsional): jika domain Anda di-host di Route53, klik Create records in Route 53 langsung dari ACM.

Setelah Issued, Anda sudah punya ARN. Salin ARN tersebut.

6) Aktifkan HTTPS & Redirect di Terraform

  1. Buka terraform.tfvars, isi certificate_arn dengan ARN dari ACM.
  2. Jalankan: terraform apply -auto-approve
  3. Sekarang listener 443 aktif dan listener 80 sudah redirect β†’ 443 (HTTP_301).

7) Pointing Domain Utama β†’ ALB

Di DNS (Cloudflare/Route53), buat record untuk akses website:

Type:   CNAME
Name:   lab
Value:  <alb_dns>   # contoh: web-alb-1151437619.ap-southeast-1.elb.amazonaws.com
Proxy:  DNS Only (Cloudflare: abu-abu)
TTL:    Auto

Record ini berbeda dengan CNAME validasi ACM. Yang ini adalah host utama untuk website.

8) Verifikasi & Tes

8.1) Cek Health Target Group

aws elbv2 describe-target-health --target-group-arn <TG_ARN>

Hasil sehat:

"TargetHealth": { "State": "healthy" }

Kalau unhealthy β†’ lihat bagian Troubleshooting.

8.2) Cek Redirect & HTTPS

curl -I http://lab.syslab.my.id
# Expect: HTTP/1.1 301 Moved Permanently β†’ Location: https://lab.syslab.my.id/

curl -I https://lab.syslab.my.id
# Expect: HTTP/2 200 (atau HTTP/1.1 200) dari Nginx

8.3) Cek Round-Robin

Buka https://lab.syslab.my.id beberapa kali β†’ konten <h1>Hello from Server <hostname></h1> akan berganti antara web-1 dan web-2. πŸ”

9) Troubleshooting (Paling Sering)

A. 502 Bad Gateway dari ALB

  • Penyebab utama: target Unhealthy (Nginx tidak listen 80).
  • Cek di EC2: docker ps -a
  • Perbaikan:
    • Pastikan user_data memakai sleep 10 & --restart always.
    • Di Terraform, properti user_data_replace_on_change = true sudah ada.
    • Kalau tetap kosong, force recreate: terraform taint aws_instance.web[0] terraform taint aws_instance.web[1] terraform apply -auto-approve

B. Sertifikat ACM tak kunjung Issued

  • Cek CNAME validasi: nama & value harus persis (termasuk underscore _).
  • Di Cloudflare, Proxy harus DNS Only.

C. Tidak bisa SSH

  • Pakai .pem (OpenSSH), bukan .ppk.
  • chmod 600 your-key.pem
  • Format koneksi: ssh -i your-key.pem ubuntu@<public_ip_ec2>

D. DNS belum resolve

  • Cek: dig +short lab.syslab.my.id β†’ harus mengarah ke ALB DNS.
  • Tunggu propagasi; kurangi TTL bila perlu.

10) (Opsional) Route53 Alias Record

Jika domain Anda di Route53 dan ingin alias ke ALB (bukan CNAME):

# Contoh (butuh hosted zone Anda)
resource "aws_route53_record" "lab_alias" {
  zone_id = "ZXXXXXXXXXXXXX"   # ganti dengan hosted zone ID domain Anda
  name    = "lab.syslab.my.id"
  type    = "A"
  alias {
    name                   = aws_lb.app_lb.dns_name
    zone_id                = aws_lb.app_lb.zone_id
    evaluate_target_health = true
  }
}

11) Cleanup (Hemat Biaya)

Jika lab selesai:

terraform destroy -auto-approve

Ini menghapus ALB, EC2, SG, dsb (kecuali DNS di Cloudflare/Route53 yang Anda buat manual).

Penutup

Dengan panduan ini, anda bisa build dari nol sampai live: infrastruktur dibuat oleh Terraform, aplikasi serve oleh Docker Nginx di 2 EC2, domain tersambung ke ALB dengan SSL valid (ACM) dan redirect otomatis ke HTTPS. Selamat ngelab! πŸŽ‰

Share:
Tags: acmalbawsdockernginxterraform
Related Posts
Tutorial AWS Lengkap: Belajar EC2, S3, dan IAM dari Nol

Belajar AWS paling efektif kalau langsung praktik. Pada panduan ini kamu akan membuat IAM User, menjalankan EC2 Instance, menyiapkan S3…

Jangan Gunakan latest Tag pada Docker Images! Ini Alasannya

🧩 Pendahuluan Dalam workflow DevOps, Docker sudah menjadi tulang punggung untuk membangun aplikasi modern. Ia membuat aplikasi lebih mudah dipaketkan,…

Post navigation

Prev
Write a comment Cancel Reply

Β© 2025 www.masdika.id β€” Semua hak cipta dilindungi