Search code examples
amazon-web-serviceshttpsload-balancingamazon-elbhttp-redirect

How to redirect to https://example.com/ instead of https://example.com:443/ on AWS ALB?


I have configured the following redirect rule to my AWS Application Load Balancer to redirect all HTTP traffic to HTTPS:

redirect rule

The issue is that when I now curl (or visit the domain in the browser), I will get this ugly and redundant Location response (domain changed to example.com):

~ $ curl -I http://www.example.com
HTTP/1.1 301 Moved Permanently
Server: awselb/2.0
Date: Mon, 14 Sep 2020 18:28:48 GMT
Content-Type: text/html
Content-Length: 150
Connection: keep-alive
Location: https://www.example.com:443/

I know that https://www.example.com:443/ is in practice just fine, and I know that it will not be shown in the end user's browser's URL field. But still, it will be shown in the browser's network tab's 'Response headers', and to me it just looks unprofessional compared to a redirect without the port, e.g.:

~ $ curl -I http://www.apple.com
HTTP/1.1 301 Moved Permanently
Server: AkamaiGHost
Content-Length: 0
Location: https://www.apple.com/
Cache-Control: max-age=0
Expires: Mon, 14 Sep 2020 18:33:23 GMT
Date: Mon, 14 Sep 2020 18:33:23 GMT
Connection: keep-alive
strict-transport-security: max-age=31536000
Set-Cookie: geo=FI; path=/; domain=.apple.com
Set-Cookie: ccl=izHQtSPVGso4jrdTGqyAkA==; path=/; domain=.apple.com

It would seem like a logical thing to just drop the port from the URL, but unfortunately it's a required field:

port field

Also the 'Switch to full URL' option doesn't seem to really help, even though the port can be cleared there:

edit full url

it still appears back after saving:

saved full url

Is there any way to make this work?

Edit:
My domain is managed through AWS Route 53.


Solution

  • UPDATE: maybe it's worth mentioning this is nice as an exercise and show capabilities. However between a Lambda redirection and just a pure Load Balancer redirection, I'd still suggest you go with the ALB-native. It's more performatic (no cold-start, no extra hop), less error-prone (no coding required), for the cost of just aesthetics on a network trace or developer tools. End users would never notice that (you probably browse in lot of these sites everyday and you don't even know). So if you ask me, I'd suggest against going to production with something like this.

    If you want something very simple as a redirect, you could just create a Target Group pointing to a Lambda function that returns a redirect. It doesn't require the overhead of managing a CloudFront distribution or trying to make it work behind a load balancer, as that would require changes in your DNS as well, since you cannot just place CloudFront behind a load balancer (not that I know of, at least).

    For your case, I created a Lambda function (Python 3.8) with the following code:

    def lambda_handler(event, context):
        response = {}
        
        if event.get('headers', {}).get('x-forwarded-proto', '') == 'http':
            print(event)
            response["statusCode"]=302
            response["headers"] = {"Location": f"https://{event['headers']['host']}{event['path']}"}
            response["body"]=""
            
        return response
    

    Then I created a new Target Group with that Lambda function as backend: Create new Target Group as Lambda function Select the Lambda created previously

    Finally, I configured my Listener on port 80 to the redirect Target Group: Configure your Listener on port 80 to the new Target Group

    With this implementation, your 302 redirect will show up as you expected: location without port