0

I have specific needs for an Nginx proxy

  • I have a brand new JS app (+ nginx) under the main url new.example.com, and an old app running on a different url old.example.com
  • I need to handle prerendering for search engines for my new app (I'm using prerender nginx official script as a base). The old app doesn't need prerendering (and actully it acts as my prerenderer for now)
  • When the user types www.example.com he hits my nginx proxy that needs
    • To proxy /adminto old.example.com/admin
    • To proxy all bot requests to a prerenderer
    • To proxy by default to new.example.com

To make things simpler, I have @location blocks representing each app (but maybe this is incompatible with the rest please tell me)

location @newapp { proxy_pass http://new.example.com:8080; } location @oldapp { proxy_pass http://old.example.com:8080; }

Now, as my new app is under develpment, I'd like the /admin URLs to redirect to my old app. I found somewhere online a trick using the try_files with a maintenance.html file

location /admin { try_files /maintenance.html @oldapp; }

Now things also get serious as - My new app needs prerendering - My old app does not need prerendering and is used as a fallback for when metas are needed - For now I don't have a prerenderer app (I will install/setup prerenderer.io later) so I am using my old app as a prerenderer for bot engines

location @prerenderer {
    try_files /maintenance.html @oldapp # will later be changes to prerenderer.io
}

# in the core nginx server block
server {
  ...
  set $prerender 0;
  # [all bot/img logic that may set prerender to 1][1]
}

Also I had to edit my @newapp to force switching to @prerenderer

location @newapp {
    if ($prerender = 1) {
        try_files /maintenance.html @prerenderer;
    }
    if ($prerender = 0) {
        try_files /maintenance.html @newapp;
    }
}

But with this I'm getting several nginx errors and I'm not sure what I am or not allowed to do

nginx: [emerg] "try_files" directive is not allowed here in

It seems that nginx doesn't like try_files in an if block.

How would you write the nginx conf file ?

My full nginx config file looks like

server {
    listen 80;
    listen 443 ssl;
    server_name www.example.com;
    access_log /var/log/nginx/www.example.com.log;

    auth_basic "Dev's Area";
    auth_basic_user_file /etc/nginx/.htpasswd;

    # https://gist.github.com/thoop/8165802
    set $prerender 0;
    if ($http_user_agent ~* "baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator") {
        set $prerender 1;
    }
    if ($args ~ "_escaped_fragment_") {
        set $prerender 1;
    }
    if ($http_user_agent ~ "Prerender") {
        set $prerender 0;
    }
    if ($uri ~* "\.(js|css|xml|less|png|jpg|jpeg|gif|pdf|doc|txt|ico|rss|zip|mp3|rar|exe|wmv|doc|avi|ppt|mpg|mpeg|tif|wav|mov|psd|ai|xls|mp4|m4a|swf|dat|dmg|iso|flv|m4v|torrent|ttf|woff|svg|eot)") {
        set $prerender 0;
    }

    #resolve using Google's DNS server to force DNS resolution and prevent caching of IPs
    resolver 8.8.8.8;

    # Defaults map to new APP EXCEPT if prerendering needed
    location / {
        if ($prerender = 1) {
            try_files /maintenance.html @prerenderer;
        }
        if ($prerender = 0) {
            try_files /maintenance.html @oldapp;
        }
    }

    # Many Static pages not available => mapped to old app
    location ~ /(privacy|faq|about_us|terms|press|legal) {
        try_files /maintenance.html @oldapp;
    }

    # Admin stuff => old app
    location /company/admin/ {
        try_files /maintenance.html @oldapp;
    }

    location @prerenderer {
        # For now old app, will use prerenderer.io later
        try_files /maintenance.html @oldapp
    }

    location @newapp {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;

        if ($prerender = 1) {
            try_files /maintenance.html @prerenderer;
        }
        if ($prerender = 0) {
            proxy_pass http://new.example.com:8080;
        }
    }

    location @oldapp {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_pass https://old.example.com;
        proxy_redirect off;
    }

    #ssl stuff here

    client_max_body_size 4G;
    keepalive_timeout 10;
 }

1 Answers1

0

The error occurs because try_files is not allowed inside an if block.

I would try to implement the selection of backend with the map directive:

map $http_user_agent $render {
    default $argcheck;
    "~* (baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator)" old.example.com;
}

map $args $argcheck {
    default oldapp;
    ~_escaped_fragment_ prerender;
}

With these two maps, you will get a variable $render, which will contain oldapp, when none of the specified rules match, or prerender when either user agent matches or the query arguments contains the defined string.

I am not 100% sure about this part, but then you can use the variable like this:

location / {
    try_files /maintenance.html @$render;
}

This way you can avoid the if statements, which are evil.

Tero Kilkanen
  • 36,796
  • 3
  • 41
  • 63