NGINX Reverse Proxy Setup with AWS CloudFormation and Terraform

In this post we set up an NGINX reverse proxy on AWS with an Auto Scaling Groups (ASG) and Route 53 for load balancing. The infrastructure is provisioned using AWS CloudFormation and Terraform.

Overview

The setup includes:
EC2 Instances provisioned within an ASG to ensure high availability and scalability.
NGINX to be installed on each instance to act as a reverse proxy.
Amazon Route 53 used to manage DNS and provide load balancing across the EC2 instances.
Health Checks to monitor instance health and route traffic only to healthy instances.

Prerequisites

Before you begin, ensure you have the following:
- AWS Account with access to EC2, Auto Scaling, and Route 53.
- Properly set up AWS CLI and Terraform on your local machine.
- An SSH key pair created in the AWS region you are deploying to.

Configuration Files

The project includes the following configuration files:
`nginx_cloudformation.yaml`: CloudFormation template to set up the infrastructure.

AWSTemplateFormatVersion: '2010-09-09'
Description: NGINX Reverse Proxy with Route 53 Load Balancing

Resources:
  NginxLaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateName: NginxProxyTemplate
      LaunchTemplateData:
        ImageId: ami-0abcdef1234567890
        InstanceType: t2.micro
        KeyName: your-key-pair
        UserData:
          Fn::Base64: !Sub |
            #!/bin/bash
            apt update -y
            apt install nginx -y
            echo "server {
                listen 80;
                location / {
                    proxy_pass http://localhost:3000;
                    proxy_set_header Host $host;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                }
            }" > /etc/nginx/sites-available/default
            systemctl restart nginx

  NginxASG:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      LaunchTemplate:
        LaunchTemplateId: !Ref NginxLaunchTemplate
        Version: !GetAtt NginxLaunchTemplate.LatestVersionNumber
      MinSize: 1
      MaxSize: 3
      DesiredCapacity: 2
      VPCZoneIdentifier:
        - subnet-12345
      HealthCheckGracePeriod: 300
      HealthCheckType: EC2
      Tags:
        - Key: Name
          Value: nginx-proxy
          PropagateAtLaunch: true

  HealthCheck:
    Type: AWS::Route53::HealthCheck
    Properties:
      HealthCheckConfig:
        Type: HTTP
        IPAddress: !GetAtt NginxASG.Instances[0].PrivateIp
        Port: 80
        ResourcePath: "/health"
        RequestInterval: 30
        FailureThreshold: 3

  DNSRecord:
    Type: AWS::Route53::RecordSet
    Properties:
      HostedZoneId: ZONEID
      Name: "example.com."
      Type: A
      TTL: 60
      ResourceRecords:
        - !GetAtt NginxASG.Instances[0].PublicIp
      HealthCheckId: !Ref HealthCheck


`nginx_terraform.tf`: Terraform configuration file.

provider "aws" {
  region = "us-east-1"
}

resource "aws_launch_template" "nginx" {
  name_prefix   = "nginx-proxy-template-"
  image_id      = "ami-0abcdef1234567890"
  instance_type = "t2.micro"
  key_name      = "your-key-pair"

  user_data = base64encode(<<EOF
#!/bin/bash
apt update -y
apt install nginx -y
cat <<EOT > /etc/nginx/sites-available/default
server {
    listen 80;
    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
systemctl restart nginx
EOT
EOF
  )
}

resource "aws_autoscaling_group" "nginx" {
  launch_template {
    id      = aws_launch_template.nginx.id
    version = "$Latest"
  }

  min_size         = 1
  max_size         = 3
  desired_capacity = 2
  vpc_zone_identifier = ["subnet-12345"]
}

resource "aws_route53_health_check" "nginx" {
  type              = "HTTP"
  resource_path     = "/health"
  ip_address        = aws_instance.nginx.private_ip
  port              = 80
  failure_threshold = 3
  request_interval  = 30
}

resource "aws_route53_record" "nginx" {
  zone_id = "ZONEID"
  name    = "example.com"
  type    = "A"
  ttl



Deployment

CloudFormation

Launch Template Setup: Navigate to the AWS Management Console.
Create Stack: Go to the AWS CloudFormation service, and choose "Create Stack".
Upload Template: Select the `nginx_cloudformation.yaml` file and follow the prompts to create the stack.

Terraform

Initialize Terraform:

terraform init
terraform plan
terraform apply

 

Usage

After deployment, your NGINX reverse proxy setup will route traffic through Route 53 to distribute requests across multiple EC2 instances based on health checks.

Monitoring and Management

- Use **AWS CloudWatch** to monitor the health and performance of your EC2 instances.
- Check **Route 53** health check status to ensure traffic is only routed to healthy instances.

Troubleshooting

- If an EC2 instance fails to pass health checks consistently, check the NGINX logs at `/var/log/nginx/error.log` for more details.
- Ensure that the security groups and network ACLs allow HTTP traffic on port 80.