5

I'm trying to solve a problem with renaming files over WebDav. Our stack consists of a single machine, serving content through Nginx, Varnish and Apache. When you try to rename a file, the operation fails with the stack that we're currently using.

To connect to WebDav, a client program must:

  1. Connect over https://host:443 to NginX
  2. NginX unwraps and forwards the request to a Varnish server on http://localhost:81
  3. Varnish forwards the request to Apache on http://localhost:82, which offers a session via mod_dav

Here's an example of a failed rename:

$ cadaver https://webdav.domain/
Authentication required for Webdav on server `webdav.domain':
Username: user
Password:

dav:/> cd sandbox
dav:/sandbox/> mkdir test
Creating `test': succeeded.

dav:/sandbox/> ls
Listing collection `/sandbox/': succeeded.
Coll:   test                                   0  Mar 12 16:00

dav:/sandbox/> move test newtest
Moving `/sandbox/test' to `/sandbox/newtest':  redirect to http://webdav.domain/sandbox/test/

dav:/sandbox/> ls
Listing collection `/sandbox/': succeeded.
Coll:   test                                   0  Mar 12 16:00

For more feedback, the WebDrive windows client logged an error 502 (Bad Gateway) and 303 (?) on the rename operation. The extended logs gave this information:

Destination URI refers to different scheme or port (https://hostname:443) (want: http://hostname:82).

Some other Restrictions: Investigations into NginX's Webdav modules show that it doesn't really fit our needs, and forwarding webdav traffic to Apache isn't an option because we don't want to enable Apache SSL.

Are there any ways to trick mod_dav to forward to another host? I'm open to ideas :).

2 Answers 2

7

(Back to the days when I used Subversion) I had similar problem with proxying to Apache SVN from Nginx SSL frontend. Suppose Nginx SSL frontend is https ://host and we'd like to proxy connections to the internal Apache SVN server http ://svn

The problem occurs when you try to copy a resource is with Destination header:

COPY /path HTTP/1.1
Host: host
Destination: https://host/another_path

As you can see Destination header still contains https schema. The fix is pretty evident --

location / {
    # to avoid 502 Bad Gateway:
    # http://vanderwijk.info/Members/ivo/articles/ComplexSVNSetupFix
    set $destination $http_destination;

    if ($destination ~* ^https(.+)$) {
         set $destination http$1;
    }

    proxy_set_header Destination $destination;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $remote_addr;

    proxy_pass http://svn;
}
2
  • Lifesaver. For anyone else trying to do the same thing, my regex actually looked like this: ^https(.+)([:443]?)(.*)$
    – heymatthew
    Mar 15, 2010 at 22:19
  • 1
    This won't work if there are special characters in the original Destination header, because after the search and replacement the Destination would be double-urlencoded by nginx. Example: Destination: https://server/%.bin -> Destination: http://server/%25.bin. Any thought on that?
    – Cnly
    Jun 7, 2018 at 7:46
1

As @Cnly said, using set directive won't work if there are special characters in both the original Destination header and url. (I have no idea why)

I used map directive to resolve the issue.

http {
    map $http_destination $http_destination_webdav {
        ~*https://(.+) http://$1;
        default $http_destination;
    }

    server {
        # ...server settings...

        location / {
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_set_header Destination $http_destination_webdav;

            proxy_pass http://svn;
        }
    }
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .