I try to port my previous .htaccess (used with apache) to nginx:

<IfModule rewrite_module>   
        RewriteEngine on
        RewriteCond "%{HTTP_USER_AGENT}" "(Googlebot|bingbot|slackbot|vkShare|W3C_Validator)" [NC]
        RewriteRule .* bot.php [L]
        RewriteBase /
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule .* index.html [L]

Following is, what I currently try:

I have generate a map as List of SearchEngine:

map $http_user_agent $search_engines {
default 0;
"~bingbot.*" 1;
"~BingPreview.*" 1;
"~Googlebot.*" 1;
if ($search_engines = 1){
   rewrite ^/(.*) bot.php?$1 break;

But this creates an invinite Loop.

Here is the full server-block:

server {
    server_name mypage.de www.mypage.de;
    root /home/mypage/public_html;
    index index.html index.htm index.php;
    access_log /var/log/virtualmin/mypage.de_access_log;
    error_log /var/log/virtualmin/mypage.de_error_log;
    fastcgi_param GATEWAY_INTERFACE CGI/1.1;
    fastcgi_param SERVER_SOFTWARE nginx;
    fastcgi_param QUERY_STRING $query_string;
    fastcgi_param REQUEST_METHOD $request_method;
    fastcgi_param CONTENT_TYPE $content_type;
    fastcgi_param CONTENT_LENGTH $content_length;
    fastcgi_param SCRIPT_FILENAME /home/mypage/public_html$fastcgi_script_name;
    fastcgi_param SCRIPT_NAME $fastcgi_script_name;
    fastcgi_param REQUEST_URI $request_uri;
    fastcgi_param DOCUMENT_URI $document_uri;
    fastcgi_param DOCUMENT_ROOT /home/mypage/public_html;
    fastcgi_param SERVER_PROTOCOL $server_protocol;
    fastcgi_param REMOTE_ADDR $remote_addr;
    fastcgi_param REMOTE_PORT $remote_port;
    fastcgi_param SERVER_ADDR $server_addr;
    fastcgi_param SERVER_PORT $server_port;
    fastcgi_param SERVER_NAME $server_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param HTTPS $https;
    location ~ \.php(/|$) {
        try_files $uri =404;
        fastcgi_pass unix:/var/php-nginx/123123123123123123.sock/socket;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    listen ssl;
    ssl_certificate /home/mypage/ssl.combined;
    ssl_certificate_key /home/mypage/ssl.key;
    if ($blocked_bots = 1) {
        return 444; # Connection closed without response
    if ($search_engines = 1){
        rewrite ^/(.*) /bot.php?$1 break;
    if ($scheme = http) {
        rewrite ^/(?!.well-known)(.*) https://mypage/$1 break;
    location / {
        try_files $uri /index.html;
        auth_basic "Administrator’s Area";
        auth_basic_user_file /home/mypage/.htpasswd;
    # Cache-Controll
    include /etc/nginx/conf.d/manuallyInclude/cache-policy.conf;

2nd Question: I have another mapped variarble for social_network bots. Do I really need to add for each mapping an own if-clause like this:

    if ($search_engines = 1){
        rewrite ^/(.*) /bot.php?$1 break;
    if ($social_networks = 1){
        rewrite ^/(.*) /bot.php?$1 break;

or is there an easier way to combine those to one rewrite-rule?

  • 1
    1) Every normalized URI should be prepended with slash, you need to use /bot.php?$1 instead of bot.php?$1. 2) To answer the question what exactly cause the infinite loop, you need to post your full nginx server block (of course you can omit the parts containing private information like server names, certificates paths etc.) Dec 5, 2020 at 10:27
  • Please post the complete server block. Dec 5, 2020 at 14:10
  • K, I've added the Server-Block. But I think what @IvanShatsky suggest... to add the leading slash still solved it. Thanx a lot.
    – suther
    Dec 7, 2020 at 9:07

1 Answer 1


Answering your second question, use an empty string instead of "0" on your map translations (and since the default map value is exactly an empty string, you can omit the default line at all):

map $http_user_agent $search_engines {
    "~bingbot" 1;
    "~BingPreview" 1;
    "~Googlebot" 1;
map $http_user_agent $social_networks {
    "~*facebook" 1;
    "~*twitter" 1;

and use concatenation of variables for the final condition decision:

map $search_engines$social_networks $is_bot {
    ""      "";
    default 1;

server {
    if ($is_bot) {
        rewrite ^/(.*) /bot.php?$1 break;
  • An for other maps which also should redirect to bot.php I only need to add them in the if-brackets, right?!
    – suther
    Dec 7, 2020 at 9:28
  • Yes, condition will be evaluated as true if the result of concatenation will be non-empty string (however strings like 0, 00 etc. will be evaluated as false). Dec 7, 2020 at 9:31
  • My Virtualmin - validation check for the Config-File tells me that only have the variable, or have both as you described above is an error in my config :(
    – suther
    Dec 7, 2020 at 9:33
  • Sorry, you are right, but this one should work :) And your regexes can be optimized as I show in example, there is no need to add the .* part to check if the User-Agent string contains some specific word. Dec 7, 2020 at 9:50
  • does your new Script means, if it's not seo_engine or social_networks, then it is by default 1 ? That would not fit my needb, because general request should be allowed. I have another list with "blocked_bots". So my need is to check for seo and redirect them... but if additional to that, it's not a blocked_bot, it should show the general page (means no redirect)
    – suther
    Dec 7, 2020 at 10:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.