[アップデート] Application Load Balancer のリスナールールでトランスフォームを構成し、ターゲットにルーティングする前にホストヘッダーや URL パスを書き換えれるようになりました

[アップデート] Application Load Balancer のリスナールールでトランスフォームを構成し、ターゲットにルーティングする前にホストヘッダーや URL パスを書き換えれるようになりました

2025.10.16

いわさです。

みなさんよく Application Load Balancer を使われていると思います。
負荷分散や TLS/SSL終端させる目的で導入することが多いと思いますが、リクエストの内容に応じてターゲットへのリクエスト転送内容や転送先をカスタマイズすることもあると思います。

Apache や Nginx でリバースプロキシを構成していた場合でも Application Load Balancer のみで代用できることがあるのですが、それでも仕様上 Application Load Balancer のみで対応できないケースがあって、場合によっては結局 Apache や Nginx でリバースプロキシを構成することも稀にありました。

先日のアップデートでリスナールールでカスタマイズできる項目が増えまして、Application Load Balancer のみで対応できる項目が増えました。
リスナールール上でトランスフォームというものを設定することで、ターゲットへ転送する前に URL パスとホストヘッダーを正規表現ベースで置換できるようになりました。

https://aws.amazon.com/about-aws/whats-new/2025/10/application-load-balancer-url-header-rewrite/

これによってバックエンドでバーチャルホストを構成している場合とか、パスまで書き換えの必要がある場合とか、今までよりも ALB 単体で対応できるケースが増えそうです。
今回は設定方法の確認と、実際に設定した前後での動作確認を行ってみましたので紹介します。

設定方法

ロードバランサーのコンソールにアクセスしてみると「Application Load Balancer の URL リライトの紹介」というバナーが表示されていますね。これのことみたいだ。

EC81AA4F-6486-4FF3-AE66-17DCA4BF720A.png

で、設定方法なのですが、ALB のリスナールール上で今回のアップデート機能が利用できます。注意点としてデフォルトルールではトランスフォームを追加することができないので、カスタムルールの追加が必要になります。

3A08FD20-7264-49E6-A238-FB2617BCC1DE.png

ルール編集時に以下からトランスフォームが設定できるようになっています。

D38280D8-CCD5-4477-9609-A992FD8ACAF2.png

本日時点でトランスフォームで設定できるのは「ホストヘッダー」と「URLパス」の2つです。

EAA6E107-14F6-415B-B4C2-6817EB85FD91_4_5005_c.jpeg

ホストヘッダーははリクエスト内のホストヘッダーを書き換えてターゲットに転送するおちうものです。正規表現を使ってホストヘッダーのパターンを照合して、そこから置換を行うというもの。
URLパスは同じように正規表現で URL パスの置換を行います。パス構成を帰ることもできますし、クエリ文字列の編集に介入することもできます。
よくクエリ文字列をパスに変換することとかあると思うのですが、あれが ALB だけでできちゃいますね。
URLパスではプロトコルやポートまでは変更できないので注意してください。

D305BDAC-DEDA-45AE-8052-394581B5B375.png

このあたりのトランスフォームの詳細は以下の公式ドキュメントに情報が記載されているのでこちらもご確認ください。

https://docs.aws.amazon.com/elasticloadbalancing/latest/application/rule-transforms.html

転送先サーバーのバーチャルホスト設定にあわせてホストヘッダーを変換する

ということで試してみましょう。
色々なシナリオ考えられると思いますが、今回は EC2 にセットアップされたアプリケーションでバーチャルホストが構成されていて、それを ALB が許可するホストヘッダーと EC2 が期待するホストヘッダーで異なる場合に、このトランスフォームを使って変換してみたいと思います。

本題から逸れますが事前に以下の VPC + ALB + EC2 の CloudFormation スタックをデプロイ済みです。Amazon Q Developer ちゃんに作ってもらいました。

			
			AWSTemplateFormatVersion: '2010-09-09'
Description: 'ALB with EC2 backend and Apache virtual hosts'

Resources:
  # VPC
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: ALB-VPC

  # Internet Gateway
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: ALB-IGW

  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  # Public Subnets
  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: ap-northeast-1a
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: Public-Subnet-1

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.2.0/24
      AvailabilityZone: ap-northeast-1c
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: Public-Subnet-2

  # Route Table
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: Public-Route-Table

  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PublicSubnetRouteTableAssociation1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable

  PublicSubnetRouteTableAssociation2:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet2
      RouteTableId: !Ref PublicRouteTable

  # Security Groups
  ALBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for ALB
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: ALB-SecurityGroup

  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for EC2
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourceSecurityGroupId: !Ref ALBSecurityGroup
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: EC2-SecurityGroup

  # IAM Role for EC2 SSM access
  EC2Role:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      Tags:
        - Key: Name
          Value: EC2-SSM-Role

  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
        - !Ref EC2Role

  # EC2 Instance
  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-070e0d4707168fc07  # Amazon Linux 2023 AMI ID for ap-northeast-1
      InstanceType: t3.micro
      SubnetId: !Ref PublicSubnet1
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      IamInstanceProfile: !Ref EC2InstanceProfile
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          yum update -y
          yum install -y httpd
          systemctl start httpd
          systemctl enable httpd
          
          # Create document roots
          mkdir -p /var/www/hoge
          mkdir -p /var/www/fuga
          
          # Create content for hoge.example.com
          cat > /var/www/hoge/pages/index.html << 'EOF'
          <!DOCTYPE html>
          <html>
          <head>
              <title>Hoge Site</title>
          </head>
          <body>
              <h1>Welcome to Hoge Site</h1>
              <p>This is the content for hoge.example.com</p>
          </body>
          </html>
          EOF
          
          # Create content for fuga.example.com
          cat > /var/www/fuga/index.html << 'EOF'
          <!DOCTYPE html>
          <html>
          <head>
              <title>Fuga Site</title>
          </head>
          <body>
              <h1>Welcome to Fuga Site</h1>
              <p>This is the content for fuga.example.com</p>
          </body>
          </html>
          EOF
          
          # Configure virtual hosts
          cat > /etc/httpd/conf.d/virtual-hosts.conf << 'EOF'
          <VirtualHost *:80>
              ServerName hoge.example.com
              DocumentRoot /var/www/hoge
              ErrorLog logs/hoge_error.log
              CustomLog logs/hoge_access.log combined
          </VirtualHost>
          
          <VirtualHost *:80>
              ServerName fuga.example.com
              DocumentRoot /var/www/fuga
              ErrorLog logs/fuga_error.log
              CustomLog logs/fuga_access.log combined
          </VirtualHost>
          EOF
          
          # Restart Apache to apply configuration
          systemctl restart httpd
      Tags:
        - Key: Name
          Value: Web-Server

  # Application Load Balancer
  ApplicationLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: WebServer-ALB
      Scheme: internet-facing
      Type: application
      Subnets:
        - !Ref PublicSubnet1
        - !Ref PublicSubnet2
      SecurityGroups:
        - !Ref ALBSecurityGroup
      Tags:
        - Key: Name
          Value: WebServer-ALB

  # Target Group
  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: WebServer-TG
      Port: 80
      Protocol: HTTP
      VpcId: !Ref VPC
      HealthCheckPath: /
      HealthCheckProtocol: HTTP
      HealthCheckIntervalSeconds: 30
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 2
      UnhealthyThresholdCount: 3
      Targets:
        - Id: !Ref EC2Instance
          Port: 80

  # Listener
  Listener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref TargetGroup
      LoadBalancerArn: !Ref ApplicationLoadBalancer
      Port: 80
      Protocol: HTTP

Outputs:
  LoadBalancerDNS:
    Description: DNS name of the load balancer
    Value: !GetAtt ApplicationLoadBalancer.DNSName
    Export:
      Name: !Sub "${AWS::StackName}-LoadBalancerDNS"
  
  VPCId:
    Description: VPC ID
    Value: !Ref VPC
    Export:
      Name: !Sub "${AWS::StackName}-VPC"

		

上記を東京リージョンにデプロイすると Amazon Linux 2023 上で Web ページがホスティングされるのですが、バーチャルホストを構成しているのでホストヘッダーの内容によってレスポンスが変わります。

			
			% curl http://13.231.188.58/
<html><body><h1>It works!</h1></body></html>
% curl http://13.231.188.58/ -H "Host:hoge.example.com"
<html><body><h1>It works!</h1></body></html>
% curl http://13.231.188.58/ -H "Host:fuga.example.com"
<!DOCTYPE html>
<html>
<head>
    <title>Fuga Site</title>
</head>
<body>
    <h1>Welcome to Fuga Site</h1>
    <p>This is the content for fuga.example.com</p>
</body>
</html>

		

良いですね。
つづいて、ALB のターゲットに EC2 を設定しているのでこちらでも試してみます。
ALB ではexample.comホストヘッダー形式でのリクエストを想定しています。

			
			% curl http://WebServer-ALB-2001862097.ap-northeast-1.elb.amazonaws.com/ -H "Host:hoge.com"
<html><body><h1>It works!</h1></body></html>
% curl http://WebServer-ALB-2001862097.ap-northeast-1.elb.amazonaws.com/ -H "Host:fuga.com"
<html><body><h1>It works!</h1></body></html>

		

デプロイされたロードバランサーに新しいリスナールールを追加します。
その中でトランスフォームの設定をするのですが、今回は次のようにトランスフォームを1件追加し、ホストヘッダー正規表現と置換後の値を設定しました。

5C7ACEAE-F33C-4803-9E80-96C0130FA09C.png

設定箇所の右側の矢印を選択すると変換のテストを行うことができますので試してみましょう。
hoge.comを入力するとhoge.example.comに変換されました。

C2B9F860-4F4A-4694-B1AE-3D8937218FEF.png

期待した変換の挙動をしていそうですね。
設定後はリスナールール一覧からは次のように確認ができます。
なお、ひとつのルールのトランスフォームに対して複数のホストヘッダー書き換えルールを設定することは出来ませんのでうまく正規表現一本で行う必要があります。

82896E0E-E068-4204-A0D3-1BEEBF013906.png

設定後、また cURL でアクセスしてみましょう。ホストヘッダーを指定します。

			
			% curl http://WebServer-ALB-2001862097.ap-northeast-1.elb.amazonaws.com/ -H "Host:hoge.com"
<html><body><h1>It works!</h1></body></html>
% curl http://WebServer-ALB-2001862097.ap-northeast-1.elb.amazonaws.com/ -H "Host:fuga.com"
<!DOCTYPE html>
<html>
<head>
    <title>Fuga Site</title>
</head>
<body>
    <h1>Welcome to Fuga Site</h1>
    <p>This is the content for fuga.example.com</p>
</body>
</html>

		

ALB 経由でホストヘッダーがリライトされターゲットに転送されていることが確認出来ましたね。

さいごに

本日は Application Load Balancer のリスナールールでトランスフォームを構成し、ターゲットにルーティングする前にホストヘッダーや URL パスを書き換えれるようになったので試してみました。

パス、クエリ文字列、ホストヘッダーの変更などを ALB にオフロードできるようになりました。
これまで細かい調整が必要でアプリケーションコードの実装やリバースプロキシの追加導入をしていた場合は今回の機能のみで今後は対応できるようになりそうですね。

この記事をシェアする

FacebookHatena blogX

関連記事