Setting up an Apache proxy on EC2 with Terraform

This post walks through provisioning an EC2 instance with Terraform and using its user_data to configure Apache as an HTTP-to-HTTPS proxy. Handy for forwarding traffic to an internal service, or fronting a backend that only speaks HTTPS.

Apache configuration script

The EC2 instance runs setup-proxy.sh on first boot. The script:

  • Installs Apache and mod_ssl.
  • Writes a vhost using ProxyPass / ProxyPassReverse to forward to the target URL.
  • Enables SSLProxyEngine so traffic to the backend stays encrypted.

Breakdown:

yum update -y
yum install -y httpd mod_ssl
  • yum update -y: refresh packages.
  • yum install -y httpd mod_ssl: install Apache and the SSL/TLS module.
cat <<'EOF' > /etc/httpd/conf.d/proxy.conf
<VirtualHost *:80>
  <Proxy *>
    Require all granted
  </Proxy>

  ProxyPass / https://target-url.com/
  ProxyPassReverse / https://target-url.com/

  SSLProxyEngine On
  SSLProxyCheckPeerCN off
  SSLProxyCheckPeerName off
  SSLProxyCheckPeerExpire off
  SSLProxyVerify none
</VirtualHost>
EOF

Writing the vhost config:

  • <VirtualHost *:80>: listen on port 80.
  • Require all granted: allow all clients (lock this down via security group, not Apache).
  • ProxyPass / https://target-url.com/: forward root requests to the target.
  • ProxyPassReverse: rewrite the backend’s redirect/Location headers to point back at the proxy.
  • SSLProxyEngine On: enable SSL on the upstream leg.
  • SSLProxyCheck* and SSLProxyVerify none: skip cert validation. Use this only if the backend has a self-signed or non-standard cert and you accept the trade-off.
systemctl enable httpd  # start automatically at system's boot
systemctl start httpd   # start immediately

Then enable and start Apache.

Security group

Restrict the proxy to traffic from inside the VPC. Adjust the CIDRs to match your network.

resource "aws_security_group" "proxy" {
  vpc_id = "XXXXXX"   # your VPC id
  name   = "proxy-security-group"

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

  # Allow inbound SSH (port 22), HTTP (port 80), and HTTPS (port 443) traffic from the VPC's IP range.
  ingress {
    from_port   = 22
    protocol    = "tcp"
    to_port     = 22
    cidr_blocks = ["10.0.0.0/8"]
  }
  ingress {
    from_port   = 80
    protocol    = "tcp"
    to_port     = 80
    cidr_blocks = ["10.0.0.0/8"]
  }
  ingress {
    from_port   = 443
    protocol    = "tcp"
    to_port     = 443
    cidr_blocks = ["10.0.0.0/8"]
  }

  tags = { Name = "proxy-security-group" }
}

Key pair

Generate a key pair locally with ssh-keygen (defaults are fine; keys land in ~/.ssh/id_rsa and ~/.ssh/id_rsa.pub). Then print the public key:

cat ~/.ssh/id_rsa.pub

Import it into AWS:

resource "aws_key_pair" "ec2" {
  # this is how the key will be identified in AWS
  key_name = "imported-key"

  # The public key portion of the key pair
  public_key = "ssh-rsa XXXXXXXX"
}

EC2 instance

resource "aws_instance" "proxy" {
  ami           = "ami-0ed961fa828560210"
  instance_type = "t2.micro"
  
  key_name               = aws_key_pair.ec2.key_name
  subnet_id              = "xxx"
  vpc_security_group_ids = [aws_security_group.proxy.id]

  user_data = file("setup-proxy.sh")

  tags = {Name = "proxy"}
}

Notes:

  • ami: a small Amazon Linux. Pick another one from the AMI catalog if you need a different distro.
  • t2.micro: fine for testing; bump it up for real traffic.
  • subnet_id: the subnet to start the instance in.
  • user_data: the bootstrap script, here setup-proxy.sh.

Deploy

  1. terraform init to pull providers.
  2. terraform apply to create the resources.
  3. Hit the instance’s IP in a browser to verify the proxy is forwarding.

Debugging

SSH in:

ssh -i /path/to/your-key.pem ec2-user@your-instance-ip

Check Apache is up:

systemctl status httpd

Inspect the rendered config:

cat /etc/httpd/conf.d/proxy.conf

Read the error log:

cat /var/log/httpd/error_log

Complete code

Comments