Nginx - basic http authentication on PHP-script
I believe your question might already be answered here, but I will try to describe what I think the problem is.
First of all, as an aside, you should consider putting all of your fastcgi parameters in a configurastion file accessible to nginx for ease of use (e.g. /etc/nginx/conf.d/fastcgi_params).
Second, depending on how you set up the location block for the auth vs the php section, you will likely need to instruct nginx on how to deal with php files a second time in the protected location, or make sure the auth_basic directives are in the same location block as the one you pasted above, for example (taken from the aforementioned post):
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;
}
}
}
On my personal installation of nginx I am using php-fpm and my php scripts are not limited to cgi-bin so my configuration is quite different but it might offer you some additional insights. I have basic authentication working as I imagine you are expecting it to although in the below example an entire vhost is under basic auth and not just a folder:
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;
Example for server/host based auth (irrelevant sections removed)
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;
}
}
Example for location based auth (irrelevant sections removed)
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;
}
}
Comments
-
halfbit almost 2 years
I added a PHP-Script that serves as "cgi-bin",
Configuration: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-Script:
<?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"); } ?>
The problem with it thought is that I cannot add basic authentication.
As soon as I enable it forlocation ~/cgi-bin
it gives me a 404 error when I try to look it up.How can I solve this?
I thought about restricting access to only my second server where I then add basic authentication over a proxy, but there must be a simpler solution.
Sorry for the bad title, I couldn't think of a better one.
Edit: My solution, thanks to WerkkreWs answer, looks like this in the end:
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; } [...] }
This may be insecure since cgi-bin.conf could be accidentally included in the server-tag (and thus enabling every client to execute scripts in every location), but since I only use it once I will stick with this solution.
-
Admin about 12 yearsCan you add a little clarification as to what you are trying to protect? If you use the auth basic documentation on a server or location it should work fine, is your wrapper script throwing the 404 or the server?
-
-
halfbit about 12 yearsPerfect, it works when I nest the locations! Also, I have one config that I simply include if I need PHP, that seemed the best way for me since I only have a couple of sites on that server :)
-
Sergio about 11 yearsYour "Example for server/host based auth" is the only working configuration i've found to password protect a whole site with fastcgi php. Thanks for sharing it, saved my day.