17

I have nginx running multiple domains under a single server directive as

server {
        listen       80;
        server_name  www.domain.com;
        server_name  x.domain.com;
        server_name  y.domain.com;

----
----
----
}

Now, I need to use location directive to match a subdomain and apply basic auth to it. The equivalent of

location x.domain.com {
        auth_basic "Admin Login";
        auth_basic_user_file /etc/nginx/.htpasswd;
}

How do I do this?

15

You can use a regular expression to capture the subdomain and then use it later in your location.

server {
    server_name   ~^(?<sub>\.)?(?<domain>.+)$;

    location / {
        root   /sites/$sub;
    }
}

Alternatively, it might be preferable to move all common configurations to an other file, and then create server blocks per-subdomain and include the external file.

server {
        server_name  www.domain.com;
        include /etc/nginx/sites-enabled/default.inc;

    location / {
        ... 
    } 
}

(repeat for other servers)

  • Am I missing something or is the server name line missing a ? and <> ? I believe it should be server_name ~^(?<sub>\.)?(?<domain>.+)$; – Mohammad AbuShady Sep 30 '13 at 8:36
  • You are quite probably correct - I can't think of any reason for it being the way it was at the moment, so I have changed it to your suggestion. – cyberx86 Sep 30 '13 at 11:25
6

One option is to return an error and send that error to a location that handles the HTTP authentication:

if ($host = x.domain.com) {
    return 550;
}

error_page 550 = @xauth;

location @xauth {
    auth_basic "Admin Login";
    auth_basic_user_file /etc/nginx/.htpasswd;
}
5

You don't need to use the location directive if you use map. This is the most simple solution and equivalent i can think of. You can name the htpasswd files according to your $http_host e.g. x.domain.com.htpasswd.

map $http_host $auth_type {
    default "off";               #This will turn off auth-basic
    x.domain.com "Restricted";   #This or any other string will turn it back on
}

server {
    auth_basic $auth_type;
    auth_basic_user_file /etc/nginx/conf.d/$http_host.htpasswd;
}
  • 1
    Works like a charm. – conradkdotcom Apr 14 '16 at 8:16
  • @Tom Siwik Anyway I can adjust this to enforce IP restrictions with allow/deny in the same way as well? – toast Apr 5 at 6:50
  • Should be possible, you can map over a lot of variables. See: nginx.org/en/docs/varindex.html for a list of variables. You'll probably need $remote_addr instead of $http_host. Not sure about ranges though. – Tom Siwik Apr 6 at 16:55
3

If you have multiple (sub)domains and they do not behave exactly alike then you use multiple server blcoks. Sorry but that's seriously the best way, even though you'll have a larger configuration.

You can do a ghetto hack by using something like if ($http_host ~ foo) but then you'll most likely run afoul of the unpredictable and weird behaviour of if as documented here: http://wiki.nginx.org/IfIsEvil

Don't try to outsmart Nginx, just use the options it gives you and you'll have far less headaches.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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