Иногда возникает необходимость заливать файлики на второй сервер и отдавать их оттуда же по http(s). Ну навскидку — отдельные серверы с картинками для вашего проекта. Или с архивами. Да с чем угодно, мне-то какая разница =)
Поднимать ради этого ftp и городить работы с ftp в коде сайта? гм… SFTP… можно, но где взять разработчика, который умеет sftp из php? Джангисты и рельсовики все умеют, ладно. А если nodejs?
А вот curl/libcurl есть везде, PUT/POST запросы можно сделать из любого ЯП/фреймворка. Поэтому приходят 2 логичных решения — либо написать php-код на принимающей стороне, который будет принимать файлы, либо сделать всё это на голом nginx-e. Окей, решили вторым способом, пришли на тостер, спросили… И получили какой-то бред в ответе — https://toster.ru/q/46578
upload-module? big-upload-module? clientbodyonthefly ещё куда ни шло, это всё же штатная фича..
Да к черту. Открываем доку (окей, в моём случае — задаём вопрос в воздух и получаем ответ от соседа-админа) по nginx и листаем до пункта «http webdav module». Всё, можно заливать файлы (ладно-ладно, конфиг я вам покажу). И решаем сразу все проблемы: нужен только дефолтный nginx из репозиториев debian/ubuntu, размер файла ограничен только стабильностью соединения (13 гиговый файл? да легко!), конфиг писать легко (копипастинг работает, да), авторизация рулится через привычный htpasswd.. В общем — быть. Погнали
Допустим nginx у нас уже есть и что-то по http куда-то отвечает. Нам нужно на images.example.com настроить upload файлов через webdav (и научиться заливать файлы курлом) с авторизацией и научиться показывать эти файлы по http без авторизации. Создаём каталог, где будем всё это хранить, например:
Nginx из коробки работает от пользователя www-data (я про деб, в других дистрах это может быть www), от него же он будет и файлы писать, так что пофиксим права:
Теперь пишем конфиг (например, в /etc/nginx/sites-available/00-images.example.com):
listen 80;
server_name images.example.com;
# описываем upload-секцию:
location /upload{
# максимальный размер файла, который можно залить.
client_max_body_size 15g;
# каталог, куда заливать
root /home/user/data/www/images.example.com;
# chmod для залитых файлов - здесь 777, чтобы user тоже мог удалять файлы
dav_access user:rw group:rw all:rw;
# разрешаем методы webdav-a. Для примера я перечислил все, для аплоада файлов хватит PUT и MKCOL
dav_methods PUT DELETE MKCOL COPY MOVE;
# nginx будет создавать весь путь при аплоаде файлов (можно будет не создавать предварительно вложенные каталоги)
create_full_put_path on;
# включаем autoindex в каталоге upload (чтобы на самом images.example.com листинг не включать).
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
charset utf-8;
# включаем авторизацию в /upload:
auth_basic "Upload directory";
auth_basic_user_file /etc/nginx/htpasswd;
}
# теперь описываем раздачу файлов по http из "корня" сайта:
location / {
root /home/user/data/www/images.example.com;
}
}
Создадим htpasswd-файл:
Сгенерим пользователя (если у вас нет утилиты htpasswd, то поставьте пакет apache2-utils — apache2 этот пакет не ставит, если что =)) — команду повторите нужное количество раз, заменяя username, при запуске она запросит пароль для пользователя:
Рестартим nginx, если ещё нет и приступаем к заливанию файлов. Я покажу это на примере консольного curl, с libcurl, думаю, разберетесь сами, если уже дочитали до сюда.
Например, у нас есть файл /tmp/bigfile. Нам его нужно будет показывать по адресу http://images.example.com/archives/bigfile.zip
Запускаем curl с хитрыми параметрами:
Имейте в виду, что пока файл льётся, он льётся в каталог /var/lib/nginx/body/. Когда upload закончится, файл будет перемещен в docroot через mv — так что если у вас /var и каталог для upload на разных файловых системах, то операция будет не атомарной. Если же на одной файловой системе — то файл появится в docroot мнгновенно и целиком (то есть не будет такого, что вы заливаете файл, а в это время его кусок могут скачать другие).
В некоторых местах вы можете услышать мнение, что передавать логин/пароль так, как это сделал я выше небезопасно и нужно обязательно передавать basic-авторизацию через http-заголовок Authorization, потому что так безопаснее. Так вот — не слушайте потом больше никогда этого человека. Заголовок Authorization это всего-лишь base64 (хоть и немного нестандартный) и декодится по первой же ссылке в гугле — https://webnet77.net/cgi-bin/helpers/base-64.pl
Намного лучше будет настроить https (https://debian.pro/581) и настроить ограничение по ip (https://debian.pro/726). Впрочем, если вам удобнее передавать через заголовок — welcome, но не тешьте себя надеждой, что это позволит избежать раскрытие пароля, если к исходникам заливалки получат доступ.
Да, ещё с этим модулем nginx’a не будут работать webdav-клиенты — уж очень он простой (в нём даже нет вебдавного листинга файлов/каталогов). Если вам нужен настоящий webdav — то советую посмотреть в сторону установки OwnCloud.
[quote]В некоторых местах вы можете услышать мнение, что передавать логин/пароль так, как это сделал я выше небезопасно и нужно обязательно передавать basic-авторизацию через http-заголовок Authorization,[/quote]
Это небезапасно только тем, что логин-пароль останутся в history шелла (если таковая есть). Так curl/wget все равно передадут его в виде заголовка Authenticate, в котором будет тот же самый base64.
Да и если я правильно прочитал rfc2617, то basic-авторизация это ВСЕГДА заголовок Authenticate. Просто через url проще для пользователя, а софт уже преобразует в заголовок.
> что логин-пароль останутся в history шелла
«избежать раскрытие пароля, если к исходникам заливалки получат доступ.»
Абзацы целиком дочитывать надо =) Я про хранение логина/пароля в коде.
А в шелле в истории и Auth останется заголовок, так что всё тоже самое.
> то basic-авторизация это ВСЕГДА заголовок Authenticate
Да, именно так. Вопрос в удобстве — в результате один фиг полетит base64, который легко расшифровывается.
а если добавить ко всему этому в nginx LUA-модулей по вкусу…. то возможностей будет слегка побольше чем у однопользовательского хранилища. оно станет более облачным:)))
См. на форуме nginx.org http://forum.nginx.org/read.php?21,259941
Забавно, но вы там же и писали, что сыроват)
Постараюсь посмотреть, если руки дойдут.
так да считаю сыроват…. потому что перфекционист:)
прямой путь к хомяку проекта.
http://ihome.itcod.com/max/projects/itcod-disk/
Нихрена не работает, после запроса curl выводит содержимое передаваемого файла
> Нихрена не работает, после запроса curl выводит содержимое передаваемого файла
Запроса-то какого?
Настроил по образу и подобию на локальной машине. Заменив
server_name img.localhost.localdomain;
в файле hosts
127.0.0.1 localhost localhost.localdomain
Путь на такой
root /home/user/img;
В htpasswd указал пользователя user с паролем pass.
При вызове curl, получаю 500 ошибку.
Пример моего вызова curl —upload-file ./test.png http://user:pass@img.localhost/upload/test.png
кусок из лога /var/log/nginx/access.log
ip — user [дата] «PUT /upload/test.png HTTP/1.1» 500 202 «-» «curl/7.50.3»
поспешил коммент писать. разобрался по логам nginx что ошибка с доступом к файлу /etc/nginx/htpasswd нет прав у nginx.
А если добавить, к многопользовательскому webdav хранилищу на nginx+lua, фронтэнды на java script, то получим легко развиваемый облачный рабочий стол. анонс разработки ITCOD WEB DESKTOP тут: https://masterpro.ws/forum/30-pokazhi-svoj-sajt/4906-itcod-web-desktop