Setting up an Apache proxy on EC2 with Terraform
Dec 14th, 2023This 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/ProxyPassReverseto forward to the target URL. - Enables
SSLProxyEngineso 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*andSSLProxyVerify 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, heresetup-proxy.sh.
Deploy
terraform initto pull providers.terraform applyto create the resources.- 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