2

Got a bit stuck here. I'd like a nice simple Nginx "include"able snippet that requires HTTP AUTH for the location it is include-ed in, AND forces a redirect to HTTPS if not already.

I came up with this:

# /etc/nginx/snippets/requirelogin-staff.conf
if ($https != "on") {
    return 301 https://$server_name$request_uri;
}
auth_ldap "Login Required";
auth_ldap_servers staff;

and used it like this (silly example for brevity, real world we have django serving / and /static/ as a resource files shortcut):

location / {
    include snippets/requirelogin-staff.conf;

    try_files $uri $uri/index.html $uri.html =404;

    location /static {
        alias /var/www/webroot/liv/static;
    }
}

It works great for anything handled by location /

wget -S shows it is first issuing a 301 redirect to the same URL but with the https protocol. Then it comes back with a 401 correctly.

Problem is for URLs under /static

The auth kicks in by directive inheritance.

But it seems the "if ($https != "on")..." is not being inherited into the nested location block.

So a wget -S goes directly to the 401, inviting the user to log in using an insecure connection, which of course is a Bad Thing.

I can sort of see why the "if" is having problems (try_files does not inherit either).

But it leaves me rather stuck.

Can any kind soul suggest perhaps a cleaner approach? The one rule is (ideally) that I'd like the AUTH to be required in one or more locations by a neat single line "include" to avoid mistakes.

And inheritance would be nice - again to avoid mistakes. Sure, we can run that "include" on every location block, and it does work. But if we guard "/" it would be nice to know that we have guarded the entire site and a developer innocently adding another location block cannot suddenly punch a security hole wide open.

Many thanks,

Tim

1
  • I am going to have a play with LUA seeing as I have the module included in my nginx built - saw someone suggest that somewhere (StackOverflow maybe).
    – Tim Watts
    Nov 9, 2016 at 19:25

2 Answers 2

1

Commands like if, try_files, proxy_pass, and uwsgi_pass are not inherited by nested location blocks. Other settings like auth_ldap are inherited.

https://stackoverflow.com/a/32126596

I can't find any official documentation on what types of configuration syntax are "commands" and which are regular configuration items. The behavior of inheritance for nested locations seems to be undocumented.

Cleaner approach

Don't use nested locations because the inheritance behavior is undocumented and nobody will feel confident making changes in the future. Simply repeat yourself, but repeat yourself with includes. Perhaps you could create another include of "standard-behavior.conf" and put things like try_files in there.

location /static {
    include snippets/requirelogin-staff.conf;
    try_files $uri $uri/index.html $uri.html =404;

    alias /var/www/webroot/liv/static;
}

location / {
    include snippets/requirelogin-staff.conf;
    try_files $uri $uri/index.html $uri.html =404;
}
1
  • Thank you - that is a useful summary. In fact I had better check the uwsgi side of things too, in case that is effectively getting squashed out.
    – Tim Watts
    Nov 9, 2016 at 10:14
0

301 Redirects can force your ENTIRE site to use https, if this is intended, then you should not be serving anything except 301 redirects over port 80,

{ # Http Redirect
   listen 80 default_server;
   listen [::]:80 default_server;
   server_name _;
   return 301 https://$server_name$request_uri;
}

Just remember that EVERYTHING has to be HTTPS if you use that 301 directive, and every subdomain will have to be HTTPS as well - not a bad thing. Also double check that server_name is defined before you use it within the site definition - i didn't see that in your example configs.

2
  • A good point. I'll tell you why I tried it the way I did: During development, we tend to guard the whole site with an AUTH requirement. After that, we tend to remove that and rely on django logins from /admin. So the sites are set up using a common include definition, that's included from both :80 and :443 server blocks. If this were a permanent setup, I see that your suggestion would be clearer and better.
    – Tim Watts
    Nov 9, 2016 at 10:14
  • However, what I'm trying to do is to have a couple of include snippets that can be dropped in and commented out in a fairly fluid manner without rewriting the whole config (and thus risking new errors). When the site is live, we use the other snippet that requires HTTPS in certain sub locations (generally those where the user logs in, such as /admin or /wp-admin etc. I guess it's not too onerous to replicate the "http auth" snippet down into every sub location. I just wondered if there was a better way?
    – Tim Watts
    Nov 9, 2016 at 10:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .