0

I have a partial NGINX config file that gets pulled into a main NGINX config file automatically by AWS Elastic Beanstalk. I have two instances running, one EC2 web server running PHP and another that's an SQS worker.

I had set up my config file to force HTTPS using:

location / {
    try_files $uri $uri/ /index.php?$query_string;
    gzip_static on;

    return 301 https://$host$request_uri;
}

This worked great for forcing HTTPS, but I was running into issues with both the ELB health monitor failing due to a 301 (expected 200), and the SQS queue also failing due to returning a 301 -- the queue is triggered by a POST from a configured cron job, which seemed to not work with the 301 redirect:

version: 1
cron:
 - name: "schedule"
   url: "/worker/schedule"
   schedule: "* * * * *"

This is using a package that listens for the POST request to that URL and then kicks off jobs.

To fix those issues, I tried this to check for the appropriate headers and turn off the redirect:

location / {
    try_files $uri $uri/ /index.php?$query_string;
    gzip_static on;

    set $redirect_to_https 0;
    if ($http_x_forwarded_proto != 'https') {
        set $redirect_to_https 1;
    }

    if ($http_user_agent ~* '^ELB-HealthChecker\/.*$') {
        access_log off;
        set $redirect_to_https 0;
    }

    if ($http_user_agent ~* '^aws-sqsd\/.*$') {
        set $redirect_to_https 0;
    }

    if ($redirect_to_https = 1) {
        return 301 https://$host$request_uri;
    }
}

This worked for the ELB health check (200), but the SQS worker is still failing, but now with a 404.

The only config that has working correctly on the SQS worker is a stripped down version (which I'm deploying manually right now specifically to the worker):

location / {
    try_files $uri $uri/ /index.php?$query_string;
    gzip_static on;
}

Here is a screenshot of the successful POST request using the above config:

enter image description here

So the question is, how do I set up my config file to ignore the HTTPS 301 redirect for both the ELB health check and the SQS queue without having to deploy separate NGINX config files?

2
  • 1
    Look here. "If" is evil and should be avoided, because it disrupt normal nginx behavior. Try map instead.
    – kab00m
    Oct 26, 2020 at 16:45
  • How would I use that in my case? It seems like I would end up with if's regardless of where I check for the UA.
    – Samsquanch
    Oct 26, 2020 at 17:19

2 Answers 2

0

This is a classic instance of the "If is evil" NGINX scenario. There's a whole page dedicated to explaining how and why using if directives inside the location block can be problematic/give completely unexpected results.

I would recommend using NGINX map for UA routing. Or if you must use the if inside location, at least replace return 301 with rewrite as the latter is much more stable inside location blocks. Best of luck!

2
  • Thanks for the reply. I did previously have rewrite ^ https://$host$request_uri? permanent; instead of the 301, but various sites/articles said basically the opposite that you did about rewrite, so I changed it to the return. As for the map functionality, how would I use that in my case? It seems like I would end up with if's regardless of where I check for the UA.
    – Samsquanch
    Oct 26, 2020 at 17:18
  • Why do you consider rewrite safe in this case? Nginx page tells that only 100% safe things are return and rewrite ... last. In this case, rewrite ... last is not an option since 301 redirect is desired. Oct 27, 2020 at 22:57
0

One could use map as follows:

map $http_x_forwarded_proto $proto {
    default 1;
    "~^https$" 0;
}

map $http_user_agent $agent {
    default 1;
    "~*^ELB-HealthChecker\/.*$" 0;
    "~*^aws-sqsd\/.*$" 0;
}

The maps need to be defined in http level in configuration.

Then, in the location, one would have:

if ($proto$agent = "11") {
    return 301 https://$host$request_uri permanent;
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .