6

I have an nginx reverse proxy, and I'm trying to get an IIS website with login to work behind it. I've found this question asked several times, but each answer appears to be different, and some of the problems deviate a bit from the problem I'm having.

With my current config, I am able to get to the login, but I'm getting a 401 error, and it keeps asking for credentials.

My current config:

/etc/nginx/sites-available/default

server {
    listen 80 default;
    server_name _;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name server2.mydomain.com;

    ssl_certificate /usr/local/nginx/conf/mydomain.com.crt;
    ssl_certificate_key /usr/local/nginx/conf/mydomain.com.key;
    ssl_session_cache shared:SSL:10m;

    ssl_session_timeout 5m;

    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
    ssl_prefer_server_ciphers on;

    location / {
        proxy_pass http://192.168.0.20:80;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_redirect http:// $scheme://;

    }
}

My question is, what is the correct way that this is supposed to work?

Here's what I've researched so far:

This link, says it isn't possible.

This link, says I should use keepalive on upstream. That may be the answer, but whenever I add an upstream server2.mydomain.com with any configuration in it, nginx fails to restart. I'm sure I have some syntax incorrect, but I've tried several things. I'd post everything I've tried, but I'm not even certain this is the correct approach, and I've tried so many things, I figured it would be easier just to ask the general population how this is done.

This link, says you can just add a proxy_pass_request_headers on; line, and it will somehow work...but it doesn't for me.

This link, seemed the most likely to work, but after trying to figure out how to encode to base64 using this link, I was getting nowhere.

Any help is greatly appreciated. Here's a previous question I've asked, that are related to this, but are different questions.


EDIT1

I apologize for this being so late, was gone for a bit.

Here are my access logs for the nginx reverse proxy server. 192.168.0.5 is my client FYI.

These logs are from me accessing the site, getting a login prompt, trying the login once (without success), and exiting the login prompt.

/var/log/nginx/access.log

192.168.0.5 - - [09/Feb/2016:14:04:14 -0600] "GET / HTTP/1.1" 401 1293 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0"
192.168.0.5 - - [09/Feb/2016:14:04:31 -0600] "GET / HTTP/1.1" 401 341 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0"
192.168.0.5 - - [09/Feb/2016:14:04:31 -0600] "GET / HTTP/1.1" 401 1293 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0"
192.168.0.5 - - [09/Feb/2016:14:04:34 -0600] "GET /favicon.ico HTTP/1.1" 401 1293 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0"

/var/log/nginx/error.log

This file is empty

IIS Logs

2016-02-11 19:39:22 192.168.0.20 GET /login - 80 - 192.168.0.10 Mozilla/5.0+(X11;+Linux+x86_64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Ubuntu+Chromium/45.0.2454.101+Chrome/45.0.2454.101+Safari/537.36 401 2 5 125
2016-02-11 19:39:28 192.168.0.20 GET /login - 80 - 192.168.0.10 Mozilla/5.0+(X11;+Linux+x86_64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Ubuntu+Chromium/45.0.2454.101+Chrome/45.0.2454.101+Safari/537.36 401 1 21480424 0
2016-02-11 19:39:36 192.168.0.20 GET /login - 80 - 192.168.0.10 Mozilla/5.0+(X11;+Linux+x86_64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Ubuntu+Chromium/45.0.2454.101+Chrome/45.0.2454.101+Safari/537.36 401 1 21480724 0
2016-02-11 19:40:16 192.168.0.20 GET /login - 80 - 192.168.0.10 Mozilla/5.0+(X11;+Linux+x86_64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Ubuntu+Chromium/45.0.2454.101+Chrome/45.0.2454.101+Safari/537.36 401 1 21407424 15
2016-02-11 19:40:22 192.168.0.20 GET /login - 80 - 192.168.0.10 Mozilla/5.0+(X11;+Linux+x86_64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Ubuntu+Chromium/45.0.2454.101+Chrome/45.0.2454.101+Safari/537.36 401 1 21480742 0

There are no security errors for logins, so it's never actually submitting the login to the system I guess. It simply gives me the login popup again every time I hit "login".

Live HTTP Headers plugin output

https://server2.mydomain.com/

GET / HTTP/1.1
Host: server2.mydomain.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive

HTTP/1.1 401 Unauthorized
Server: nginx/1.4.6 (Ubuntu)
Date: Tue, 09 Feb 2016 19:21:04 GMT
Content-Type: text/html
Content-Length: 1293
Connection: keep-alive
WWW-Authenticate: NTLM
WWW-Authenticate: Negotiate
X-Powered-By: ASP.NET
----------------------------------------------------------
https://server2.mydomain.com/

GET / HTTP/1.1
Host: server2.mydomain.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Authorization: NTLM TlRNTVMTUAAAB4IIAAAAAAAAAAAAACDAFGAAAAAAAAAAAAAAAAA=

HTTP/1.1 401 Unauthorized
Server: nginx/1.4.6 (Ubuntu)
Date: Tue, 09 Feb 2016 19:22:00 GMT
Content-Type: text/html; charset=us-ascii
Content-Length: 341
Connection: keep-alive
WWW-Authenticate: NTLM TlRMTVNTUAACAAAAGgAaADgAAuzKir6ADucAAAAAAAAAAL4A&%$DSDADvgBSAAAABgGxHQAAAA9HAEUARQBLAFMAQQBOAEQATgBFAFIARABTAAIAGgBHRQBLAFMAQQBOAEQATgBFDFAFIARABTAAEADABLAEUATABWAEkATgAEACIAZwBlAGUAawBzAGEAbgBkAG4AZQByAGQAcwAuAGMAbwBtAAMAMABLAEUATABWAEkATgAuAGcAZQBlAGsAcwBhAG4AZABuAGUAcgBkAHMALgBjAG8AbQAFACIAZwBlAGUAawBzAGEAbgBkAG4AZQByAGQAcwAuAGMAbwBtAAcACAABRuM1b2PRAQAAAAA=
----------------------------------------------------------
https://server2.mydomain.com/

GET / HTTP/1.1
Host: server2.mydomain.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Authorization: NTLM TlRMTVNTUAADAAAAGAAYAHAAAADqAOoAiAAAAAAAAAAGgAaAEAAAAAWABYAWgAAAAAAAAAAAAAABYIIAGEAbQBhAG4AZABhAC4AYgBsAG8AdQBuAHQAVwBPAFIASwBTAFQAQQBUAEkATwBOAHorEf/j46zta4wONTUAADAA-98uH//ZL0Am16vGzdWutoAAAAGAAYAHQAAAAAAAACFdzVEB9QHmLWLCuQQAAAAAAgAaAEcARQBFAEsAUwBBAE4ARABOAEUAUgBEAFMAAQAMAEsARQBMAFYASQBOAAQAIgBnAGUAZQBrAHMAYQBuAGQAbgBlAHIAZABzAC4AYwBvAG0AAwAwAEsARQBMAFYASQBOAC4AZwBlAGUAawBzAGEAbgBkAG4AZQByAGQAcwAuAGMAbwBtAAUAIgBnAGUAZQBrAHMAYQBuAGQAbgBlAHIAZABzAC4AYwBvAG0ABwAIAAFG4zVvY9EBAAAAAA==

HTTP/1.1 401 Unauthorized
Server: nginx/1.4.6 (Ubuntu)
Date: Tue, 09 Feb 2016 19:22:00 GMT
Content-Type: text/html
Content-Length: 1293
Connection: keep-alive
WWW-Authenticate: NTLM
WWW-Authenticate: Negotiate
X-Powered-By: ASP.NET
----------------------------------------------------------

EDIT2 - For clarity, here is the setup by IP.


Client machine

192.168.0.5

Ubuntu 14.04 desktop


Reverse proxy server

192.168.0.10

nginx 1.4.6

Ubuntu 14.04 server


Server 2

192.168.0.20

server2.mydomain.com

apache2

Ubuntu 14.04 server


EDIT3 - Maybe this works and I'm doing it wrong,....maybe not

From this post, the answer written by Fizz.

I tried this below

/etc/nginx/sites-available/default

server {
    listen 80 default;
    server_name _;
    return 301 https://$host$request_uri;
}

upstream server2.mydomain.com {
        server 192.168.0.20:80
keepalive 16;
}

server {
    listen 443 ssl;
    server_name server2.mydomain.com;

    ssl_certificate /usr/local/nginx/conf/mydomain.com.crt;
    ssl_certificate_key /usr/local/nginx/conf/mydomain.com.key;
    ssl_session_cache shared:SSL:10m;

    ssl_session_timeout 5m;

    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
    ssl_prefer_server_ciphers on;

    location / {
        proxy_pass http://192.168.0.20:80;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_redirect http:// $scheme://;

    }
}

Same results. Based on the other answers....maybe apache2 is the better way to go?


EDIT4 - Edit based on answer from Maxim Dounin

I'm trying to use Nginx 1.9.9 now, and the stream proxy method mentioned in Maxim Dounin's answer.

I compiled from source, so my file locations are different now.

/opt/nginx/nginx.conf

worker_processes 1;
events {
    worker_connections 1024;
}

stream {
    upstream backend {
       hash $remote_addr consistent;

       server server2.mydomain.com:80 weight=5;
       server 192.168.0.20:80            max_fails=3 fail_timeout=30s;

    }

    server {
        listen 443 ssl;        #Line 27
        server_name server2.mydomain.com;

        ssl_certificate /usr/local/nginx/conf/mydomain.com.crt;
        ssl_certificate_key /usr/local/nginx/conf/mydomain.com.key;
        ssl_session_cache shared:SSL:10m;

        ssl_session_timeout 5m;

        proxy_connect_timeout 1s;
        proxy_timeout 3s;
        proxy_pass backend;
    }

#    server {
#        listen [::1]:12345;
#        proxy_pass unix:/tmp/stream.socket;
#    }
}

I commented out the last recommended server line, because I had no idea what to do with that, but my config file doesn't get there anyway due to other errors. Right now my /opt/nginx/logs/error.log is having problems with line 27

the "ssl" parameter requires ngx_stream_ssl_module in /opt/nginx/nginx.conf:27

I definitely compiled with the ngx_stream_ssl_module because when I do a nginx -V I get configure arguments: --with-stream

Hopefully I'm on the right track.

  • Please post a) Access & error logs for nginx b) Access and error logs for IIS c) Headers for the request and response (Firefox + Live HTTP Headers plugin) – Tim Feb 5 '16 at 23:10
  • Thanks for telling me what information I would need to resolve this issue. I've made some updates under EDIT1, and I'll add more later. Thanks again. – trueCamelType Feb 9 '16 at 20:19
12
+50

The problem is NTLM authentication (note WWW-Authenticate: NTLM ...), AKA Windows Authentication.

NTLM authentication authenticates connections instead of requests, and this is somewhat contradicts HTTP protocol, which is expected to be stateless. As a result it doesn't generally work through proxies, including nginx.

Simplest solution would be to change authentication to "Basic" on IIS side. If this not an option for some reason, other possibilities include:

  • Use stream proxy as available in nginx 1.9.x. This will map connections from clients to upstream server, and thus NTLM authentication will work.

  • Use ntlm feature as available in commercial nginx version.

Note that there are some recommendations to use upstream with keepalive for NTLM authentication to work. These recommendations are incorrect and harmful - unless you are using the proxy for just one user. And the worst thing is that it may appear to work correctly. The problem is that keepalive connections to upstream server are kept in a common cache, and these connections can be used for all clients. So if there is an authenticated connection in the cache, an unrelated client who happens to use this connection will be able to bypass authentication.

  • Thank you for clarifying what is happening during the upstream/keepalive examples for nginx. That had been confusing me. I'm going to go through the ntml features. The first thing I'll look into is to see if there is a cost associated with commercial nginx versions. Thanks, I'll review all of this, and get back with you. – trueCamelType Feb 16 '16 at 18:52
  • Would you mind looking at my EDIT4, and tell me if I'm heading in the right direction? – trueCamelType Feb 16 '16 at 21:14
  • 1
    @trueCamelType, you need --with-stream_ssl_module to use SSL in stream module, see ./configure --help. – Maxim Dounin Feb 17 '16 at 15:28
  • I appreciate the help, I'm going to mark this as the correct answer, but I'm having one more problem. Is it possible to specify a URI inside the nginx.conf file? No matter where I try to add a location / directive, it errors out. Any idea how to add that? I'm not having much luck finding that, other than adding a sites-available directory with slink to sites-enabled, which also hasn't worked. I'd prefer just doing it in nginx.conf if possible, if not i don't mind adding an include for those. – trueCamelType Feb 17 '16 at 19:58
  • 1
    @trueCamelType, the location directive is only allowed in server{} blocks inside the http{} block. Note that you can't use location with stream proxy - as it proxies connections, not HTTP requests. – Maxim Dounin Feb 18 '16 at 15:45
1

I've experienced a similar error when configuring a YouTrack server with a reverse proxy.

You may want to try adding this line:

proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;

And from the below link:

If Nginx is going to terminate SSL/TLS connections before forwarding them to YouTrack, then the following header is also necessary:

proxy_set_header        X-Forwarded-Proto https;

This is the link that helped me find a solution: https://confluence.jetbrains.com/display/YTD6/YouTrack+JAR+in+Nginx+Web+Server#

  • I tried adding those lines, and actually had tried that before and didn't mention it. I get the exact same errors. I'll read through that link more thoroughly though. – trueCamelType Feb 11 '16 at 20:40

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.