I'm trying to enable HTTP Basic Authentication for all URLs except a few, but no matter what I try, I either get auth for all non-static URLs or no auth for all.
My config:
server {
listen 80;
server_name dev.website.com *.dev.website.com;
return 301 https://dev.website.com;
}
server {
listen 443 ssl;
include snippets/fastcgi-php-controller.conf;
server_name dev.website.com;
root /var/www/website/web/;
ssl_certificate /etc/ssl/localcerts/website/dev/website.crt;
ssl_certificate_key /etc/ssl/localcerts/website/dev/website.key;
auth_basic_user_file /var/www/website/web/.htpasswd;
auth_basic "Restricted Access!";
location /just_a_simple.html {
try_files /static$uri =404;
}
location / {
rewrite ^ /index.php;
}
location /static {
try_files $uri =404;
}
location ~ ^/en/(url1|url2) {
auth_basic off;
rewrite ^ /index.php;
}
}
I'm trying to:
- have the just_a_simple.html file served as static, unprotected and it works
- have everything in /static served as static, unprotected and it works
- have /en/url1 and /en/url2 passed off to FPM, interpreted as PHP, unprotected and it doesn't work, it's protected
- have all other URLs passed off to FPM, interpreted as PHP, protected and it works
How can I make point 3 above work and achieve all 4 requirements?
snippets/fastcgi-php-controller.conf
location ~ \.php$ {
fastcgi_split_path_info ^(. \.php)(/. )$;
try_files $uri /index.php;
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
CodePudding user response:
Have you tried adding this to the location blocks you want to allow?
auth_basic off;
allow all;
For example:
location /just_a_simple.html {
auth_basic off;
allow all; # Allow all to see content
try_files /static$uri =404;
}
CodePudding user response:
You are right about request processing phases (described in the development guide). Your rewrite
directive will be executed at the NGX_HTTP_REWRITE_PHASE
while basic_auth
one register its handler at the later NGX_HTTP_ACCESS_PHASE
. If you'd need to do an opposite thing, protect the /en/url1
and /en/url2
URIs leaving all the others unprotected, you'd have an option to use a try_files
directive to jump to the PHP handler location at the even more later NGX_HTTP_PRECONTENT_PHASE
:
location ~ ^/en/(url1|url2) {
auth_basic "Restricted Access!";
auth_basic_user_file /var/www/website/web/.htpasswd;
try_files "" /index.php$is_args$args;
}
However this is not an option for your particular case. What you can do instead is to rely on the $request_uri
built-in nginx variable, which is always contains an original non-normalized request URI and does not get changed during internal URI rewrites (in is the normalized $uri
one that does). Usually you have at least two options:
- use an
if
block to conditionally set theauth_basic
directive parameter:
location ~ \.php$ {
set $realm "Restricted Access!";
if ($request_uri ~ ^/en/(url1|url2)) {
set $realm off;
}
auth_basic $realm;
auth_basic_user_file /var/www/website/web/.htpasswd;
...
}
However since you have a customized try_files
directive inside your PHP handler location, it won't be an option here since try_files
does not get inherited into the virtual nested locations created by if
directive when used in the location
context. Do you remember that if
is evil? So we can go straight to the second option:
- use a
map
block to evaluate theauth_basic
directive parameter:
map $request_uri $realm {
~^/en/(url1|url2) off;
default "Restricted Access!";
}
server {
...
location ~ \.php$ {
auth_basic $realm;
auth_basic_user_file /var/www/website/web/.htpasswd;
...
}
}
P.S. Dealing with PATH_INFO
inside your PHP handler makes no sense; you can read here why is it.