Exchange / Outlook - RPC Method and Error 405

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:

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 Integrated Windows Authentication - Wikipedia
for more details.

[…]


Maxim D.
http://nginx.org/en/donation.html

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.servers.aeltc.org:6002”,
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:

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/configuration-1.5.html#4-option%20http-no-delay).

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:

So, anyone know, will be this feature in future betas or releases?

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

Posted at Nginx Forum:

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 D.
http://nginx.org/en/donation.html

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:

Thank you, I’ll try to modify it, because don’t work for me too :slight_smile:
Apr 18 15:39:21 localhost haproxy[32134]: 217.118.93.107:25372
[18/Apr/2013:15:39:21.100] ft_exchange~ ft_exchange/
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: