I’m beginning to suspect you are right.
NTLM appears to violate HTTP’s convention of “stateless” by using HTTP requests to authenticate underlying connections. So, once a connection is authenticated, all requests using that connection have to be aware that the underlying connection is authenticated and set headers accordingly: authentication takes multiple round-trips as well, so Go’s connection pooling doesn’t guarantee that requests to finish authentication happen on the same connection. (Keep-Alive is also required.)
NGINX does not guarantee this either, but it probably does connection pooling very differently in a way that happens to work for you. Based on the comments and what I am reading about nginx’s additional ntlm
directive, it sounds like your current config is just working by sheer luck!
Docs for proxying NTLM are sparse, but the best help I have found is from nginx’s docs:
Allows proxying requests with NTLM Authentication. The upstream connection is bound to the client connection once the client sends a request with the “Authorization” header field value starting with “
Negotiate
” or “NTLM
”. Further client requests will be proxied through the same upstream connection, keeping the authentication context.In order for NTLM authentication to work, it is necessary to enable keepalive connections to upstream servers. The proxy_http_version directive should be set to “
1.1
” and the “Connection” header field should be cleared.
So, we basically need to implement this behavior into Caddy’s proxy, along with a config property to enable it.