Site Tools


software:nginx:webdav

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
software:nginx:webdav [2015/05/12 16:50]
– [Проблема 3] root
software:nginx:webdav [2022/02/05 04:30] (current)
root
Line 5: Line 5:
 SAMB-у в принципе тоже без VPN можно пробросить, но это из области поиска приключений с последствиями.\\ SAMB-у в принципе тоже без VPN можно пробросить, но это из области поиска приключений с последствиями.\\
  
-Nginx в базовом функционале имеет не полную поддержку WebDav: PUT DELETE MKCOL COPY MOVE.\\ +Nginx в базовом функционале имеет не полную поддержку [[http://nginx.org/ru/docs/http/ngx_http_dav_module.html|Dav]]: PUT DELETE MKCOL COPY MOVE.\\ 
-Расширить его ещё двумя: PROPFIND и OPTIONS можно с помощью плагина<a href="https://github.com/arut/nginx-dav-ext-module">dav-ext</a>\\+Расширить его ещё двумя: PROPFIND и OPTIONS можно с помощью модуля[[https://github.com/arut/nginx-dav-ext-module|dav-ext]]\\
  
  
-Для работы потребуется Nginx собранный с поддержкой WebDav, dav-ext модулем и rewrite.\\+Для работы потребуется Nginx собранный с поддержкой [[http://nginx.org/ru/docs/http/ngx_http_dav_module.html|Dav]][[https://github.com/arut/nginx-dav-ext-module|dav-ext]], [[http://nginx.org/ru/docs/http/ngx_http_rewrite_module.html|rewrite]] и [[http://wiki.nginx.org/HttpHeadersMoreModule|headers_more]].\\
 <code>[x] HTTP_DAV              Enable http_webdav module <code>[x] HTTP_DAV              Enable http_webdav module
 [x] HTTP_DAV_EXT          3rd party webdav_ext module [x] HTTP_DAV_EXT          3rd party webdav_ext module
-[x] HTTP_REWRITE          Enable http_rewrite module</code>+[x] HTTP_REWRITE          Enable http_rewrite module 
 +[x] HEADERS_MORE          3rd party headers_more module</code>
  
  
  
 ===== Проблема 1 - Майкрософт нарушает стандарты и свои обещания ===== ===== Проблема 1 - Майкрософт нарушает стандарты и свои обещания =====
-{{:ru:software:nginx:webdav1.png|}}+{{:software:nginx:webdav1.png|}}
  
-Перед тем как создать файл WebDav клиент проверяет наличие файла посылая запрос:\\+Перед тем как создать файл WebDav клиент проверяет наличие файла посылая запрос:
 <code>PROPFIND /!!!!/test.lnk HTTP/1.1 <code>PROPFIND /!!!!/test.lnk HTTP/1.1
 Connection: Keep-Alive Connection: Keep-Alive
Line 28: Line 29:
 Host: 172.16.0.254:8089</code> Host: 172.16.0.254:8089</code>
  
-В ответ IIS ему выдаёт:\\+В ответ IIS ему выдаёт:
 <code>HTTP/1.1 404 Resource Not Found <code>HTTP/1.1 404 Resource Not Found
 Content-Length: 1635 Content-Length: 1635
Line 40: Line 41:
  
 Только это не правильно, должен быть код 207 и xml в котором описан элемент и код для него, те 404 должно быть в xml.\\ Только это не правильно, должен быть код 207 и xml в котором описан элемент и код для него, те 404 должно быть в xml.\\
-с точки зрения стандартов: http://tools.ietf.org/html/rfc2518#page-24 \\ +с точки зрения стандартов: [[http://tools.ietf.org/html/rfc2518#page-24]] \\ 
-с точки зрения доков мс: http://msdn.microsoft.com/en-us/library/aa142960(v=exchg.65).aspx \\ +с точки зрения доков мс: [[http://msdn.microsoft.com/en-us/library/aa142960(v=exchg.65).aspx]] \\ 
-У яндекса тоже в примерах xml: http://api.yandex.ru/disk/doc/dg/reference/propfind_property-request.xml \\+У яндекса тоже в примерах xml: [[http://api.yandex.ru/disk/doc/dg/reference/propfind_property-request.xml]] \\
  
-Ответ Nginx:\\+Ответ Nginx:
 <code>HTTP/1.1 207 Multi-Status <code>HTTP/1.1 207 Multi-Status
 Server: nginx/1.7.4 Server: nginx/1.7.4
Line 72: Line 73:
 Такой "неожиданный" ответ сносит голову WebDav клиенту винды.\\ Такой "неожиданный" ответ сносит голову WebDav клиенту винды.\\
  
-Фиксим в конфиге (возможно это сведёт с ума остальные, порядочные WebDav клиенты, но лично мне нужен был только один не такой как все):\\ +**Фикс 1**: в конфиге (возможно это сведёт с ума остальные, порядочные WebDav клиенты, но лично мне нужен был только один не такой как все):
-**Фикс 1**:+
 <code>error_page 599 = @propfind_handler; <code>error_page 599 = @propfind_handler;
 if ($request_method = PROPFIND) { if ($request_method = PROPFIND) {
Line 93: Line 93:
  
 ===== Проблема 2 - PROPPATCH отсутствует в nginx ===== ===== Проблема 2 - PROPPATCH отсутствует в nginx =====
-{{:ru:software:nginx:webdav2.png|}} \\+{{:software:nginx:webdav2.png|}} \\
 WebDav от мс очень хочет метод PROPPATCH, которого в Nginx и расширениях нет. Совсем нет.\\ WebDav от мс очень хочет метод PROPPATCH, которого в Nginx и расширениях нет. Совсем нет.\\
 Я рассматривал два варианта решения:\\ Я рассматривал два варианта решения:\\
Line 99: Line 99:
 2. Положится на кривость виндовой реализации WebDav и скормить статический ответ.\\ 2. Положится на кривость виндовой реализации WebDav и скормить статический ответ.\\
  
-Запрос:\\+Запрос:
 <code>PROPPATCH /Family/test.lnk HTTP/1.1 <code>PROPPATCH /Family/test.lnk HTTP/1.1
 Cache-Control: no-cache Cache-Control: no-cache
Line 110: Line 110:
 Host: xxx.xxx.net Host: xxx.xxx.net
  
-<?xml version="1.0" encoding="utf-8" ?><D:propertyupdate xmlns:D="DAV:" xmlns:Z="urn:schemas-microsoft-com:"><D:set><D:prop><Z:Win32CreationTime>Sun, 10 Aug 2014 21:30:21 GMT</Z:Win32CreationTime><Z:Win32LastAccessTime>Sun, 10 Aug 2014 21:30:22 GMT</Z:Win32LastAccessTime><Z:Win32LastModifiedTime>Sun, 10 Aug 2014 21:30:22 GMT</Z:Win32LastModifiedTime><Z:Win32FileAttributes>00000020</Z:Win32FileAttributes></D:prop></D:set></D:propertyupdate></pre></spoiler>+<?xml version="1.0" encoding="utf-8" ?><D:propertyupdate xmlns:D="DAV:" xmlns:Z="urn:schemas-microsoft-com:"><D:set><D:prop><Z:Win32CreationTime>Sun, 10 Aug 2014 21:30:21 GMT</Z:Win32CreationTime><Z:Win32LastAccessTime>Sun, 10 Aug 2014 21:30:22 GMT</Z:Win32LastAccessTime><Z:Win32LastModifiedTime>Sun, 10 Aug 2014 21:30:22 GMT</Z:Win32LastModifiedTime><Z:Win32FileAttributes>00000020</Z:Win32FileAttributes></D:prop></D:set></D:propertyupdate></code>
  
-<spoiler title="Ответ IIS"><pre>HTTP/1.1 207 Multi-Status+Ответ IIS
 +<code>HTTP/1.1 207 Multi-Status
 Date: Sun, 10 Aug 2014 12:24:47 GMT Date: Sun, 10 Aug 2014 12:24:47 GMT
 Server: Microsoft-IIS/6.0 Server: Microsoft-IIS/6.0
Line 124: Line 125:
 И как эти все атрибуты писать в разных ОС и разных ФС?... И как эти все атрибуты писать в разных ОС и разных ФС?...
  
-Так появился второй фикс в конфиге: +**Фикс 2**
-Фикс 2:\\+
 <code>if ($request_method = PROPPATCH) { # Unsupported, allways return OK. <code>if ($request_method = PROPPATCH) { # Unsupported, allways return OK.
  add_header Content-Type 'text/xml';  add_header Content-Type 'text/xml';
Line 137: Line 137:
  
 ===== Проблема 3 - создание папок ===== ===== Проблема 3 - создание папок =====
-{{:ru:software:nginx:webdav3.png|}} \\+{{:software:nginx:webdav3.png|}} \\
 См п1 :) См п1 :)
  
-Приходит запрос:\\+Приходит запрос:
 <code>MKCOL /Family/MR3020 HTTP/1.1 <code>MKCOL /Family/MR3020 HTTP/1.1
 Connection: Keep-Alive Connection: Keep-Alive
Line 148: Line 148:
 Host: xxx.xxx.net</code> Host: xxx.xxx.net</code>
  
-Nginx на него отвечает (немного странно выбирая код, на мой взгляд, но в принципе правильно)\\ +Nginx на него отвечает (немного странно выбирая код, на мой взгляд, но в принципе правильно):\\
-Ответ:\\+
 <code>HTTP/1.1 409 Conflict <code>HTTP/1.1 409 Conflict
 Server: nginx/1.7.4 Server: nginx/1.7.4
Line 169: Line 168:
  
 Как должно быть описано:\\ Как должно быть описано:\\
-У майкрософта: http://msdn.microsoft.com/en-us/library/aa142923(v=exchg.65).aspx \\ +У майкрософта: [[http://msdn.microsoft.com/en-us/library/aa142923(v=exchg.65).aspx]] \\ 
-У яндекса: http://api.yandex.ru/disk/doc/dg/reference/mkcol.xml \\ +У яндекса: [[http://api.yandex.ru/disk/doc/dg/reference/mkcol.xml]] \\ 
-И даже в RFC: http://tools.ietf.org/html/rfc2518#page-33 \\+И даже в RFC: [[http://tools.ietf.org/html/rfc2518#page-33]] \\
  
 Во всех примерах URL оканчивается слешем. \\ Во всех примерах URL оканчивается слешем. \\
Line 177: Line 176:
  
 Вариантов опять было два: \\ Вариантов опять было два: \\
-1. Поправить файл: http://lxr.nginx.org/source/src/http/modules/ngx_http_dav_module.c строчки 484 - 493, там как раз проверка наличия слеша и его отрезание. \\+1. Поправить файл: [[http://lxr.nginx.org/source/src/http/modules/ngx_http_dav_module.c]] строчки 484 - 493, там как раз проверка наличия слеша и его отрезание. \\
 2. Пофиксить через конфиг.\\ 2. Пофиксить через конфиг.\\
  
-Вариант 1 я оставляю на усмотрение програмеров nginx, может по стандарту оно и должно ругаться. Связываться с отсылкой патчей тоже не хотелось.\\+Вариант 1 я оставляю на усмотрение програмеров nginx, может по стандарту оно и должно ругаться.\\
  
-**Фикс 3**:\\+**Фикс 3**:
 <code>if ($request_method = MKCOL) { # Microsoft specific handle: add trailing slash. <code>if ($request_method = MKCOL) { # Microsoft specific handle: add trailing slash.
- rewrite ^(.*[^/])$ $1/;+ rewrite ^(.*[^/])$ $1/ break;
 }</code> }</code>
 Вот для этого пустяка и потребовался REWRITE плагин.\\ Вот для этого пустяка и потребовался REWRITE плагин.\\
Line 191: Line 190:
 ===== Проблема 4 - удаление папок ===== ===== Проблема 4 - удаление папок =====
 Ноги тут те же что и в п3: отсутствие слеша на конце урла.\\ Ноги тут те же что и в п3: отсутствие слеша на конце урла.\\
-Однако я столкнулся с тем, что nginx тоже ведёт себя несколько странно.\\ +Однако я столкнулся с тем, что nginx тоже ведёт себя несколько странно: если слеш на конце отсутствует, то nginx считает что его просят удалить файл, и получает ошибку: 21: Is a directory при попытке удалить.\\ 
-1. Если слеш на конце отсутствует, то nginx считает что его просят удалить файл, и получает ошибку: 21: Is a directory при попытке удалить.\\ +
-2. Если слеш добавить то папку он почему то так и не удаляет. Подозреваю тут где то баг самого nginx.\\+
  
-Фикс в конфиге:\\ 
 **Фикс 4**: **Фикс 4**:
 <code>error_page 598 = @delete_handler; <code>error_page 598 = @delete_handler;
Line 207: Line 204:
  open_file_cache off;  open_file_cache off;
  if (-d $webdav_root/$uri) { # Add trailing slash to dirs.  if (-d $webdav_root/$uri) { # Add trailing slash to dirs.
- rewrite ^(.*[^/])$ $1/;+ rewrite ^(.*[^/])$ $1/ break;
  }  }
  root $webdav_root;  root $webdav_root;
Line 213: Line 210:
 }</code> }</code>
 Если кратко, то переносим обработку DELETE в отдельный локейшин (процедуру), дальше проверяем, если удаляется папка то добавляем слеш.\\ Если кратко, то переносим обработку DELETE в отдельный локейшин (процедуру), дальше проверяем, если удаляется папка то добавляем слеш.\\
 +
 +
 +===== Проблема 5 - копирование и переименование =====
 +Ноги тут те же что и в п4: отсутствие слеша на конце урла и в Destination заголовке.\\
 +Для решения проблемы с добавлением "/" в заголовок Destinaton нам потребуется модуль headers_more.\\
 +
 +**Фикс 6**:
 +<code>error_page 597 = @copy_move_handler;
 +if ($request_method = COPY) {
 + return 597;
 +}
 +if ($request_method = MOVE) {
 + return 597;
 +}
 +
 +location @copy_move_handler {
 + internal;
 +
 + open_file_cache off;
 + if (-d $webdav_root/$uri) { # Add trailing slash to dirs.
 + more_set_input_headers 'Destination: $http_destination/';
 + rewrite ^(.*[^/])$ $1/ break;
 + }
 + root $webdav_root;
 + dav_methods COPY MOVE;
 +}</code>
 +
 +
 +
 +===== Проблема 6 - OPTIONS корня =====
 +Клиент запрашивает опции не у той папки которую мы хотим чтобы он подключил а у корня сервера.\\
 +
 +**Фикс 6**:
 +<code>location / {
 + if ($request_method = OPTIONS) {
 + add_header Allow 'OPTIONS, GET, HEAD, POST, PUT, MKCOL, MOVE, COPY, DELETE, PROPFIND, PROPPATCH';
 + add_header DAV '1, 2';
 + return 200;
 + }
 +}
 +</code>
 +Возвращаем ему статический список.\\
 +Можно было просто разрешить: dav_ext_methods OPTIONS;\\
 +
 +
 +===== Проблема 7 - виндовый клиент не может подключится =====
 +Соединение происходит но в логах nginx ничего нет, а клиент сообщает об ошибке.\\
 +В логах с включённым дебагом ssl видно что рукопожатие не проходит.\\
 +Проблема у меня проявилась не так давно, после обновления OpenSSL.\\
 +При этом IE и другие браузеры могут авторизоваться по этому URL и отобразить листинг директории.\\
 +
 +**Фикс 7**:
 +Заменить OpenSSL на LibreSSL и пересобрать nginx.
 +Возможно OpenSSL уже исправили.
  
  
Line 219: Line 270:
 <code>Content-Type: text/xml</code> <code>Content-Type: text/xml</code>
 и хотя в данном случае это не создаёт проблем, но всё же это не правильно.\\ и хотя в данном случае это не создаёт проблем, но всё же это не правильно.\\
- 
-Это уже третий раз когда гибкость nginx позволила мне получить результат не используя языки программирования, Игорь - молодец!\\ 
-Прошлые разы я сделал кешируюший прокси с фильтрацией по урл и UPnP/DLNA сервер.\\ 
- 
  
  
Line 230: Line 277:
 set $webdav_root "/mnt/WebDav_folder"; set $webdav_root "/mnt/WebDav_folder";
 location ^~ /Family { location ^~ /Family {
 + if ($ssl_protocol = "") { # Block non ssl/tls connections.
 + add_header Strict-Transport-Security 'max-age=600';
 + return 403;
 + }
 + auth_basic "Private site";
 + auth_basic_user_file /usr/local/etc/nginx/secure/authbasic.htpasswd;
  
- root $webdav_root; + root $webdav_root; 
- error_page 599 = @propfind_handler; + error_page 599 = @propfind_handler; 
- error_page 598 = @delete_handler; + error_page 598 = @delete_handler; 
- chunked_transfer_encoding on+ error_page 597 = @copy_move_handler
- open_file_cache off; + open_file_cache off; 
- client_max_body_size 50m+ client_max_body_size 50m;
- add_header Allow 'OPTIONS, GET, HEAD, DELETE, PUT, COPY, MOVE, PROPFIND';+
  
  if ($request_method = PROPFIND) {  if ($request_method = PROPFIND) {
Line 247: Line 299:
  }  }
  if ($request_method = MKCOL) { # Microsoft specific handle: add trailing slash.  if ($request_method = MKCOL) { # Microsoft specific handle: add trailing slash.
- rewrite ^(.*[^/])$ $1/;+ rewrite ^(.*[^/])$ $1/ break;
  }  }
  if ($request_method = DELETE) {  if ($request_method = DELETE) {
  return 598;  return 598;
 + }
 + if ($request_method = COPY) {
 + return 597;
 + }
 + if ($request_method = MOVE) {
 + return 597;
  }  }
  
- dav_methods PUT MKCOL COPY MOVE# + dav_methods PUT MKCOL; 
- dav_ext_methods OPTIONS;+ dav_ext_methods OPTIONS;
  create_full_put_path on;  create_full_put_path on;
  min_delete_depth 0;  min_delete_depth 0;
- dav_access user:rw group:rw all:rw;+ dav_access user:rw group:rw all:rw
 + 
 + autoindex on; 
 + autoindex_exact_size on; 
 + autoindex_localtime on;
 } }
 location @propfind_handler { location @propfind_handler {
  internal;  internal;
 +
 + auth_basic "Private site";
 + auth_basic_user_file /usr/local/etc/nginx/secure/authbasic.htpasswd;
  
  open_file_cache off;  open_file_cache off;
Line 266: Line 331:
  return 404;  return 404;
  }  }
- root $webdav_root; + root $webdav_root; 
- dav_ext_methods PROPFIND;+ dav_ext_methods PROPFIND;
 } }
 location @delete_handler { location @delete_handler {
  internal;  internal;
 +
 + auth_basic "Private site";
 + auth_basic_user_file /usr/local/etc/nginx/secure/authbasic.htpasswd;
  
  open_file_cache off;  open_file_cache off;
- if (-d $webdav_root/$uri) { # Add trailing slash to dirs. + if (-d $webdav_root/$uri) { # Microsoft specific handle: Add trailing slash to dirs. 
- rewrite ^(.*[^/])$ $1/;+ rewrite ^(.*[^/])$ $1/ break;
  }  }
- root $webdav_root; + root $webdav_root; 
- dav_methods DELETE; + dav_methods DELETE; 
-}</code>+
 +location @copy_move_handler { 
 + internal; 
 + 
 + auth_basic "Private site"; 
 + auth_basic_user_file /usr/local/etc/nginx/secure/authbasic.htpasswd; 
 + 
 + open_file_cache off; 
 + if (-d $webdav_root/$uri) { # Microsoft specific handle: Add trailing slash to dirs. 
 + more_set_input_headers 'Destination: $http_destination/'; 
 + rewrite ^(.*[^/])$ $1/ break; 
 +
 + root $webdav_root; 
 + dav_methods COPY MOVE; 
 +
 +location / { 
 + if ($request_method = OPTIONS) { 
 + add_header Allow 'OPTIONS, GET, HEAD, POST, PUT, MKCOL, MOVE, COPY, DELETE, PROPFIND, PROPPATCH'; 
 + add_header DAV '1, 2'; 
 + return 200
 + } 
 +
 +</code>
  
 open_file_cache off; - нужно потому что мы меняем файлы, если кеширование включено то можно будет долго гадать почему не видно файлы которые мы только что закинули на сервер.\\ open_file_cache off; - нужно потому что мы меняем файлы, если кеширование включено то можно будет долго гадать почему не видно файлы которые мы только что закинули на сервер.\\
 +Также в самом начале локейшена есть требование использовать SSL и если SSL используется то запрашивается BASIC авторизация.
 +==== Важно ====
 +  - set $webdav_root "/mnt/WebDav_folder"; - **полный путь** на диске к папке которую мы расшариваем. Папка должна существовать и на неё должны быть выставлены права доступа которые позволят nginx получить доступ к содержимому, читать и записывать файлы.
 +  - в папке "/mnt/WebDav_folder" должна существовать папка Family
 +  - location ^~ **/Family** - означает что клиент должен использовать URL: https://SERVER_ADDRESS**/Family**
 +  - директивы **auth_basic** и **auth_basic_user_file** должны быть в каждом **location** который осуществляет обработку запросов, см [[https://github.com/dgraziotin/docker-nginx-webdav-nononsense/issues/15|DELETE requests work unauthenticated]]
  
  
 ===== Немного о настройке клиента ===== ===== Немного о настройке клиента =====
 Он как капризный ребёнок, из коробки ему подавай SSL и никакой Basic аутентификации, файлы не больше 50 мегабайт, в папках не более 500-1000 файлов.\\ Он как капризный ребёнок, из коробки ему подавай SSL и никакой Basic аутентификации, файлы не больше 50 мегабайт, в папках не более 500-1000 файлов.\\
-Увы, но даже после всего файлы более 4гб передавать не получится. (Скорее всего из за кривой реализации, которая файлы при открытии скачивает в память/на диск чтобы получить более менее стандартный файловый дискриптор, это мои домыслы.)\\+Увы, но даже после всех проделанных настроек файлы более 4гб передавать не получится. (Скорее всего из за кривой реализации, которая файлы при открытии скачивает в память/на диск чтобы получить более менее стандартный файловый дискриптор, это мои домыслы.)\\
  
-Вот здесь собраны все настройки с описанием: http://blogs.msdn.com/b/robert_mcmurray/archive/2008/01/17/webdav-redirector-registry-settings.aspx \\+Вот здесь собраны все настройки с описанием: [[http://blogs.msdn.com/b/robert_mcmurray/archive/2008/01/17/webdav-redirector-registry-settings.aspx]] \\
  
 На данный момент мои настройки WebClient выглядят так:\\ На данный момент мои настройки WebClient выглядят так:\\
Line 307: Line 403:
  
  
 +===== Полезное =====
 +  * Дальнейшая разработка решения происходит тут: [[https://github.com/dgraziotin/docker-nginx-webdav-nononsense|docker-nginx-webdav-nononsense]] - настоятельно рекомендую хотя бы посмотреть все решения которые там применены
 +  * Патч [[https://github.com/arut/nginx-dav-ext-module/pull/56|Fix PROPFIND fail with 500 on simlinks to non exist file/dir.]]
 +
 +
 +
 +{{tag>software howto windows net nginx WebDAV}}
software/nginx/webdav.txt · Last modified: 2022/02/05 04:30 by root