Forum: NGINX Exchange / Outlook - RPC Method and Error 405

Posted by gmor (Guest)
on 2013-02-28 09:33
(Received via mailing list)
Hi all,

I've tried to do some research on this already, but without much luck. 
So
I'm hoping others may be able to assist.

I'm trying to use Nginx as a Reverse Proxy back to an Exchange 2007
environment.

- Nginx is terminating to HTTPS / SSL connection for the Client
- Nginx is then proxying to the Exchange environment over HTTP

As other have found, this appears to be working find for all Exchange
Services, with the exception of 'Outlook Anywhere', which is also known 
as
Outlook RCP/HTTP(S).

To better define the problem, an Exchange Client Access Server hosts the
following Virtual Directories (or services) is IIS7:

/Autodiscover   - For devices to automatically configure their 
connection
setting
/owa                - "Outlook Web Access" - Basically webmail
/OAB              - "Offline Address Book" - Where clients can download
copies off the offline address book
/EWS              - "Exchange Web Services" - Good question as to what 
this
is!
/Public             - "Public Folders" - Conenction point for Public 
Folder
access
/Microsoft-Server-ActiveSync  - Used with devices for ActiveSync
/Rpc                - "Outlook Anywhere" - Outlook connecting using
RPC/HTTP(S) - This is the problematic one.
(plus a few legacy and admin services)

So, I have everything working through Nginx, with the exception
RPC/HTTP(S).

Initially I was seeing this error:

10.110.2.15 - username [27/Feb/2013:17:24:31 +0000] "RPC_IN_DATA
/rpc/rpcproxy.dll?EX-SERVER-2008.servers.null.org:6002 HTTP/1.1" 413 198 
"-"
"MSRPC" "-"

After a bit of reading, this was resolved with the following directive:

http {
 client_max_body_size 0;
}

(Yes, I know 0=unlimited and that may not be appropriate, but I'm still
testing!)

So now all that I'm left with is trying to resolve this error:

10.110.2.15 - username [28/Feb/2013:07:39:27 +0000] "RPC_OUT_DATA
/rpc/rpcproxy.dll?EX-SERVER-2008.servers.null.or:6004 HTTP/1.1" 405 172 
"-"
"MSRPC" "-"
10.110.2.15 - username [28/Feb/2013:07:39:27 +0000] "RPC_IN_DATA
/rpc/rpcproxy.dll?EX-SERVER-2008.servers.null.org:6004 HTTP/1.1" 405 172 
"-"
"MSRPC" "-"

With my very limited knowledge Error 405 is "Method Not Allowed".

I've seen various solutions which suggest changing the 'error_page 405'
directive to different things. Such as:

location / {
error_page 405 = @app;
try_files $uri @app;
}

location @app {
proxy_pass http://app_servers;
}

But these don't seem to solve the issue.

So my questions are:

1. How can I allow this Method, if that is the issue?
2. If what I'm doing is fundamentally not possible, please just let me
know!

For Reference:

I'm running Nginx v1.2.7 from the nginx Repo on Centos 6.3

My main Nginx Config looks like this (Some of the names and IPs have 
been
changed to protect the innocent):

upstream exchange_all {
 ip_hash;
 server 10.1.1.1 max_fails=1 fail_timeout=10s;
 server 10.1.1.2 max_fails=1 fail_timeout=10s;

 # Do NOT Remove - this is needed for auth to work
 keepalive 32;
}

server {
 listen 10.2.1.1;

 return 301 https://webmail.null.com$request_uri;

}

server {
 listen 10.2.1.1:443 ;

 ssl on;
 ssl_certificate /etc/ssl/webmail.aeltc.com.crt;
 ssl_certificate_key /etc/ssl/ae-lb02-key.pem;
 ssl_session_cache shared:SSL:60m;
 ssl_session_timeout 60m;

 ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
 ssl_ciphers RC4:HIGH:!aNULL:!MD5;

 proxy_redirect off;
 proxy_buffering off;

 proxy_read_timeout 3600;

 proxy_pass_header Date;
 proxy_pass_header Server;

 proxy_set_header Connection "";
 proxy_set_header Accept-Encoding "";
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_set_header X-Forwarded-Proto off;

 add_header Front-End-Https on;

 proxy_http_version 1.1;

  location ~*/Autodiscover {
   proxy_pass http://exchange_all;
  }

  location ~*/owa {
   proxy_pass http://exchange_all;
  }

  location ~*/OAB {
   proxy_pass http://exchange_all;
  }

#  location ~*/rpc/ {
  location ~*/rpc/rpcproxy\.dll\? {
   proxy_pass http://exchange_all;
  }

  location ~*/EWS {
   proxy_pass http://exchange_all;
  }

  location ~*/Public {
   proxy_pass http://exchange_all;
  }

  location ~*/Microsoft-Server-ActiveSync {
   proxy_pass http://exchange_all;
  }

  location ~*/$ {
    return 301 https://webmail.null.com/owa;
  }

}

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?2,236709,236709#msg-236709
Posted by Maxim Dounin (Guest)
on 2013-02-28 13:26
(Received via mailing list)
Hello!

On Thu, Feb 28, 2013 at 03:33:06AM -0500, gmor wrote:

[...]

> 1. How can I allow this Method, if that is the issue?
> 2. If what I'm doing is fundamentally not possible, please just let me
> know!

The 405 error, at least if returned by nginx, means that module
which used to handle the request doesn't understand the request
method used.  E.g. static module will only handle GET and HEAD,
and will return 405 to anything else as it doesn't know how to
handle other methods.  Proxy module, in contrast, just proxies the
request and don't care which method was used.

So first of all I would suggest you to make sure requests are
handled in a location with proxy_pass properly configured.  A
simple way to do this would be to just throw away all funny
regexp locations you wrote in your config, and start with a simple

    location / {
        proxy_pass http://backend;
    }

to handle all requests.  Using debug log might be also helpful,
see http://nginx.org/en/debugging_log.html.

(Note: I'm not sure this will work at all, I've never tried.  I
would rather suppose it won't work, as RPC likely tries to
establish in/out data streams.  I wouldn't expect a stream from
a client to a backend to work as nginx will insist on reading a
request body before it will be passed to the backend.)

[...]

> upstream exchange_all {
>  ip_hash;
>  server 10.1.1.1 max_fails=1 fail_timeout=10s;
>  server 10.1.1.2 max_fails=1 fail_timeout=10s;
>
>  # Do NOT Remove - this is needed for auth to work
>  keepalive 32;

Just a side note:

This is wrong - there is no guarantee that the same upstream server
connection will used for requests from a particular client.  While with
keepalive Integrated Windows Authentication might appear to work,
it in fact doesn't.  You should switch to Basic authentication
instead.

See http://en.wikipedia.org/wiki/Integrated_Windows_Au...
for more details.

[...]

--
Maxim Dounin
http://nginx.org/en/donation.html
Posted by gmor (Guest)
on 2013-02-28 15:16
(Received via mailing list)
Hi,

Thanks for the quick response. I've done what you suggested with the
following results:

>A
>simple way to do this would be to just throw away all funny
>regexp locations you wrote in your config, and start with a simple

>location / {
>proxy_pass http://backend;
>}

Absolutely happy to.

Now I'm seeing slightly different behaviour. No more 405 errors, the 
Outlook
client just hangs now, eventually reporting 'Server not Available'

In the debug log, I'm now seeing the following:

2013/02/28 13:56:55 [info] 3150#0: *1 client prematurely closed 
connection,
client: 10.110.2.15, server: , request: "RPC_IN_DATA
/rpc/rpcproxy.dll?EX-SERVER-2008.servers.null.org:6002 HTTP/1.1", host:
"webmail.null.com"
2013/02/28 13:56:55 [info] 3150#0: *2 client prematurely closed 
connection,
so upstream connection is closed too (104: Connection reset by peer) 
while
reading upstream, client: 10.110.2.15, server: , request: "RPC_OUT_DATA
/rpc/rpcproxy.dll?EX-SERVER-2008.servers.null.org:6002 HTTP/1.1", 
upstream:
"http://10.1.1.2:80/rpc/rpcproxy.dll?EX-MBX-2008.se...,
host: "webmail.null.com"

Which is me eventually cancelling the Outlook connection. This is 
evident
from tailing the debug log - Nothing during the connection; but these 
events
which the connection attempt is cancelled.

So...

Good news, Error 405 doesn't seem to be the cause of my issues, it would
appear that my location directives were wrong in some way.

Bad news, Outlook Anywhere still isn't working.

If anyone has any other suggestions, please let me know.

Thanks,

Graham.

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?2,236709,236722#msg-236722
Posted by Maxim Dounin (Guest)
on 2013-02-28 16:20
(Received via mailing list)
Hello!

On Thu, Feb 28, 2013 at 09:15:52AM -0500, gmor wrote:

> >proxy_pass http://backend;
> client: 10.110.2.15, server: , request: "RPC_IN_DATA
> from tailing the debug log - Nothing during the connection; but these events
> which the connection attempt is cancelled.

This what I've talked about - RPC client tries to establish data
stream, presumably by faking big request body, but fails because
nginx actually waits for the body before passing the request to an
upstream server.

--
Maxim Dounin
http://nginx.org/en/donation.html
Posted by gmor (Guest)
on 2013-03-04 10:06
(Received via mailing list)
Hi,

Thanks for the explanation. It absolutely makes sense now that you've
clarified how Nginx works.

Following on from this, I've now chosen to use HAProxy for this 
particular
Exchange / Outlook Anywhere use-case.

This supports the 'streaming' model of Outlook Anywhere, by simply 
passing
the data to the backend, without waiting for the complete body (with the
'option http-no-delay' directive -
http://cbonte.github.com/haproxy-dconv/configurati...).

I hope to be able to find a case for using Nginx in the future as it 
still
looks like a great product.

Thanks again for the support,

Graham

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?2,236709,236892#msg-236892
Posted by akam (Guest)
on 2013-04-18 12:53
(Received via mailing list)
So, anyone know, will be this feature in future betas or releases?

(I tryed to use haproxy, but it don't work :( can you please share your
config? )

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?2,236709,238473#msg-238473
Posted by gmor (Guest)
on 2013-04-18 13:08
(Received via mailing list)
Hi,

Happy to share my config. This is based on HAProxy Version 1.5-Dev17.

It's by no means perfect, but's working for us at the moment:

global

  # Default Maximum Number of Connections. Used to set ulimit -n
  maxconn 20000

  # Run as a Daemon Service in the Background
  daemon

  # Define the Number of Processor Cores - Not Essential
  #nbproc 2

  # Allows Turning Off of Kernel TCP Splicing - Not Essential
  #nosplice

  # Logging Setting. Local to Local Syslog and Control from There
  log 127.0.0.1 daemon
  log-send-hostname
  log-tag haproxy

  # Define a UNIX Socket so that you can Admin the Service interactively
  stats socket /usr/local/sbin/haproxy-socket level admin


defaults

  # Do Not Log Connections with No Requests
  option dontlognull

  # Force Clients to try and Reconnect to an Alternative Server if one 
is
Down
  option redispatch

  # Ensure that Streaming HTTP Works Correctly - Vital for Outlook 
Anywhere
  option http-no-delay

  # Enable Continuous Stats for Long Running Connections
  option contstats

  # Log All HTTP Date
  option httplog

  # Log Request and Responses as Fast as Possible
  option logasap

  # Set Logging to the Setting in Global
  log global

  # Define the Method of Load Balancing - source = Source IP Hash
  balance source

  # Client Inactivity Timeout
  #timeout client 900s
  timeout client 3600s

  # Server Inactivity Timeout
  #timeout server 900s
  timeout server 3600s

  # Maximum Time a Request is Queued on the Load Balancer
  timeout queue 30s

  # Other Timeouts - Need Investigating
  timeout connect 5s
  timeout http-keep-alive 1s
  timeout http-request 15s
  timeout tarpit 1m

  # Define the Default Server Checking Behaviour - 10 seconds, 3 Missed
Checks is Failure, 2 Successful Check Brings Server Back
  default-server inter 10s fall 3 rise 2


userlist stats-auth

  # User / Password for Admin Access to Stats Page
  group stats-admin users admin
  user admin password [Remvoed]

  # User / Password for Monitor Access to Stats Page
  group stats-readonly users monitor
  user monitor password [Removed]


listen stats

  # Define the Mode
  mode http

  # Bind to an IP Address/Port
  bind 10.2.1.1:8080

  # Define ACLs to be Used in the Stats Authentication Process
  acl AUTH-readonly http_auth_group(stats-auth) stats-readonly
  acl AUTH-admin http_auth_group(stats-auth) stats-admin
  acl net-allowed src 10.3.1.8/29 10.4.1.8/29

  # Enable Various Stats Features
  stats enable
  stats show-desc Load Balancer for Exchange
  stats uri /
  stats refresh 10s

  # Enable Stats Auth
  stats http-request auth unless AUTH-admin OR AUTH-readonly
  stats admin if AUTH-admin

  # Block Access Unless in the Allow Network Range
  block unless net-allowed


frontend ft_exchange

  # Define the Mode
  mode http

  # Define the Maximum Number of Connections for the Frontend
  maxconn 8000

  # Bind to an IP Address/Port, Select SSL and specific the Certificate
  # The Ciphers option for SSL can be Added: ciphers
  bind 10.2.1.1:443 ssl crt /etc/ssl/crt.domain.com.pem ciphers
TLSv1+SSLv3+HIGH:!aNULL:!eNULL

  # Define a List of Accepted ACLs for Future use
  acl all-exchange path_beg -i /autodiscover /owa /oab /ews /public
/microsoft-server-activesync /rpc
  acl root url_len 1
  acl autodiscover path_beg -i /autodiscover
  acl owa path_beg -i /owa
  acl oab path_beg -i /oab
  acl ews path_beg -i /ews
  acl public path_beg -i /public
  acl activesync path_beg -i /microsoft-server-activesync
  acl outlook-anywhere path_beg -i /rpc

  # Block All Request Except Those to Exchange Virtual Directories
  block unless all-exchange OR root

  # Redirect is the URL is a Single Character, which can only mean /
  redirect location /owa if root

  # Capture the User-Agent Header, so that it is Added to the Log
  capture request header User-Agent len 50
  capture request header Content-Length len 120
  capture response header Content-Length len 120


  # Define Which Set of Backend Servers to Use
  default_backend bk_exchange_all


backend bk_exchange_all

  # Define the Mode
  mode http

  # Define the Overal Maximum Number of Connections for the Backend
  fullconn 8000

  # Define the Backend Servers
  server exchange01 10.1.1.1:80 check
  server exchange02 10.1.1.2:80 check

(IP addresses and names have been changed to protect to innocent).

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?2,236709,238474#msg-238474
Posted by akam (Guest)
on 2013-04-18 13:47
(Received via mailing list)
Thank you, I'll try to modify it, because don't work for me too :)
Apr 18 15:39:21 localhost haproxy[32134]: 217.118.93.107:25372
[18/Apr/2013:15:39:21.100] ft_exchange~ ft_exchange/<NOSRV>
129/-1/-1/-1/+129 302 +101 - - PR-- 0/0/0/0/0 0/0"GET / HTTP/1.1"

By the way, are you use haproxy only for exchange? your backends use 
http?
not https?


gmor Wrote:
-------------------------------------------------------
> Hi,
>

>   bind 10.2.1.1:443 ssl crt /etc/ssl/crt.domain.com.pem ciphers
> TLSv1+SSLv3+HIGH:!aNULL:!eNULL
>

> backend bk_exchange_all
>

>   # Define the Backend Servers
>   server exchange01 10.1.1.1:80 check
>   server exchange02 10.1.1.2:80 check
>

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?2,236709,238475#msg-238475
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.