Назад | Перейти на главную страницу

Nginx - базовая http-аутентификация на PHP-скрипте

Я добавил PHP-скрипт, который служит «cgi-bin»,
Конфигурация:

location ~^/cgi-bin/.*\.(cgi|pl|py|rb) {
    gzip  off;
    fastcgi_pass  127.0.0.1:9000;
    fastcgi_index cgi-bin.php;
    fastcgi_param SCRIPT_FILENAME    /etc/nginx/cgi-bin.php;
    fastcgi_param SCRIPT_NAME        /cgi-bin/cgi-bin.php;
    fastcgi_param X_SCRIPT_FILENAME  /usr/lib/$fastcgi_script_name;
    fastcgi_param X_SCRIPT_NAME      $fastcgi_script_name;
    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 GATEWAY_INTERFACE  CGI/1.1;
    fastcgi_param SERVER_SOFTWARE    nginx;
    fastcgi_param REQUEST_URI        $request_uri;
    fastcgi_param DOCUMENT_URI       $document_uri;
    fastcgi_param DOCUMENT_ROOT      $document_root;
    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 REMOTE_USER        $remote_user;
}

PHP-скрипт:

<?php

$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
   2 => array("pipe", "w")   // stderr is a file to write to
);

$newenv = $_SERVER;
$newenv["SCRIPT_FILENAME"] = $_SERVER["X_SCRIPT_FILENAME"];
$newenv["SCRIPT_NAME"] = $_SERVER["X_SCRIPT_NAME"];

if (is_executable($_SERVER["X_SCRIPT_FILENAME"])) {
  $process = proc_open($_SERVER["X_SCRIPT_FILENAME"], $descriptorspec, $pipes, NULL, $newenv);
  if (is_resource($process)) {
    fclose($pipes[0]);
    $head = fgets($pipes[1]);
    while (strcmp($head, "\n")) {
      header($head);
      $head = fgets($pipes[1]);
    }
    fpassthru($pipes[1]);
    fclose($pipes[1]);
    fclose($pipes[2]);
    $return_value = proc_close($process);
  }
  else {
    header("Status: 500 Internal Server Error");
    echo("Internal Server Error");
  }
}
else {
  header("Status: 404 Page Not Found");
  echo("Page Not Found");
}
?>

Проблема с ним в том, что я не могу добавить базовую аутентификацию.
Как только я включу его для location ~/cgi-bin это дает мне ошибку 404, когда я пытаюсь ее найти.

Как я могу это решить?

Я думал об ограничении доступа только ко второму серверу, на котором я затем добавляю базовую аутентификацию через прокси, но должно быть более простое решение.

Простите за плохое название, я не мог придумать лучшего.

Редактировать: Мое решение, благодаря WerkkreWs ответ, в итоге выглядит так:

cgi-bin.conf:

location ~^/.*\.(cgi|pl|p<|rb) {
    [...]
}

vhost.conf:

server {
    [...]
    location ~^/cgi-bin {
        auth_basic "Restricted";
        auth_basic_user_file htusers;
        include cgi-bin.conf;
    }
    [...]
}

Это может быть небезопасно, поскольку cgi-bin.conf может быть случайно включен в серверный тег (и, таким образом, позволяет каждому клиенту выполнять сценарии в любом месте), но, поскольку я использую его только один раз, я буду придерживаться этого решения.

Я считаю, что на ваш вопрос уже есть ответ Вот, но я постараюсь описать, в чем, по моему мнению, проблема.

Прежде всего, в стороне, вам следует рассмотреть возможность помещения всех ваших параметров fastcgi в файл конфигурации, доступный для nginx для простоты использования (например, /etc/nginx/conf.d/fastcgi_params).

Во-вторых, в зависимости от того, как вы настроили блок местоположения для раздела auth и php, вам, вероятно, потребуется проинструктировать nginx о том, как работать с файлами php во второй раз в защищенном месте, или убедитесь, что директивы auth_basic находятся в тот же блок местоположения, что и тот, который вы вставили выше, например (взято из вышеупомянутого сообщения):

server {
  listen 80;
  server_name my-awesome-php.site;
  root /path/to/root;

  # Normal files (blank location is OK, just means serve from root)
  location / {  }  

  # PHP for normal stuff
  location ~ \.php$ {
    include fastcgi.conf;
    fastcgi_pass  127.0.0.1:9000;
  } 

  # The protected location
  location /protected {
    auth_basic "Give me codes.";
    auth_basic_user_file /path/to/.htpasswd;
    location ~ \.php$ {
      include fastcgi.conf;
      fastcgi_pass  127.0.0.1:9000;
    }
  }
}

В моей личной установке nginx я использую php-fpm, и мои сценарии php не ограничиваются cgi-bin, поэтому моя конфигурация сильно отличается, но она может предложить вам некоторые дополнительные идеи. У меня базовая аутентификация работает так, как я предполагаю, вы этого ожидаете, хотя в приведенном ниже примере весь vhost находится под базовой аутентификацией, а не только в папке:

fastcgi_params

fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
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_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;
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;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

Пример аутентификации на основе сервера / хоста (нерелевантные разделы удалены)

server {
        server_name dev.foo.com;

        error_log /app/www/dev.foo.com/logs/error.log error;

        root /app/www/dev.foo.com/htdocs;
        index index.php index.html;

        auth_basic "Secret Files";
        auth_basic_user_file /app/www/dev.foo.com/conf/htpasswd;

        location ~ \.php$ {
                include       /etc/nginx/fastcgi_params;
                fastcgi_index index.php;
                fastcgi_split_path_info ^(.+\.php)(.*)$;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_pass  unix:/var/run/foo.com.sock;
        }


        location ~ /\.ht {
                deny all;
        }
}

Пример аутентификации на основе местоположения (нерелевантные разделы удалены)

server {
        server_name foo.com;

        error_log /app/www/foo.com/logs/error.log error;

        root /app/www/foo.com/htdocs;
        index index.php index.html;

        location /protected {            
            auth_basic "Secret Files";
            auth_basic_user_file /app/www/foo.com/conf/htpasswd;

            location ~ \.php$ {
                include       /etc/nginx/fastcgi_params;
                fastcgi_index index.php;
                fastcgi_split_path_info ^(.+\.php)(.*)$;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_pass  unix:/var/run/foo.com.sock;
            }
        }

        location ~ \.php$ {
            include       /etc/nginx/fastcgi_params;
            fastcgi_index index.php;
            fastcgi_split_path_info ^(.+\.php)(.*)$;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_pass  unix:/var/run/foo.com.sock;
        }

        location ~ /\.ht {
            deny all;
        }
}