Об HTTP-серверах для трансфера файлов в Linux
Последнее время часто сталкивался с необходимостью обмена файлами между Linux-машинами. В этом посте опишу 3 удобных способа, как можно быстро и легко развернуть тривиальный HTTP-сервер для трансфера файлов.
Local – 10.10.10.1, remote – 10.10.10.2.
Python
Питон может выручить практически в любой ситуации, и наш случай не исключение.
Всем известны эти замечательные команды для запуска HTTP-серверов для второй версии питона:
local@server:~$ python -m SimpleHTTPServer [port]
И ее аналог для Python 3:
local@server:~$ python3 -m http.server [-h] [--cgi] [--bind ADDRESS] [port]
Таким способом можно только выдергивать файлы оттуда, где подняли сервер, т. к. единственные методы, который он понимает “из коробки”, это HEAD
и GET
. Однако никто не запрещает нам немного модифицировать дефолтное поведение, добавив, к примеру, обработку POST
(выводим содержимое в консоль для примера) и PUT
-запросов.
Простой скрипт:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Usage: python3 SimpleHTTPServer+.py [-h] [--bind ADDRESS] [port]
import http.server
import os
from argparse import ArgumentParser
class HTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_POST(self):
content_length = int(self.headers['Content-Length'])
post_data = self.rfile.read(content_length)
self._set_headers()
self.wfile.write(b'<html><body><h1>POST!</h1></body></html>')
print(post_data.decode('utf-8'))
def do_PUT(self):
path = self.translate_path(self.path)
if path.endswith('/'):
self.send_response(405, 'Method Not Allowed')
self.wfile.write(b'PUT not allowed on a directory\n')
return
else:
try:
os.makedirs(os.path.dirname(path))
except FileExistsError: pass
length = int(self.headers['Content-Length'])
with open(path, 'wb') as f:
f.write(self.rfile.read(length))
self.send_response(201, 'Created')
self.end_headers()
def cli_options():
parser = ArgumentParser()
parser.add_argument(
'--bind',
'-b',
default='',
metavar='ADDRESS',
help='Specify alternate bind address [default: all interfaces]'
)
parser.add_argument(
'port',
action='store',
default=8000,
type=int,
nargs='?',
help='Specify alternate port [default: 8000]'
)
return parser.parse_args()
if __name__ == '__main__':
args = cli_options()
http.server.test(HandlerClass=HTTPRequestHandler, port=args.port, bind=args.bind)
Позволяет успешно как выгружать файлы с:
local@server:~$ wget 10.10.10.2:8881/message
--2018-10-11 10:51:35-- http://10.10.10.2:8881/message
Connecting to 10.10.10.2:8881... connected.
HTTP request sent, awaiting response... 200 OK
Length: 10 [application/octet-stream]
Saving to: ‘message’
message 100%[===================>] 10 --.-KB/s in 0s
2018-10-11 10:51:35 (2.40 MB/s) - ‘message’ saved [10/10]
local@server:~$ cat message
Hi there!
remote@server:~$ python3 SimpleHTTPServer+.py 8881
Serving HTTP on 0.0.0.0 port 8881 (http://0.0.0.0:8881/) ...
10.10.10.1 - - [11/Oct/2018 11:04:37] "GET /message HTTP/1.1" 200 -
Так и загружать на Linux-машину:
local@server:~$ curl --upload-file message 10.10.10.2:8881
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 10 0 0 100 10 0 9 0:00:01 0:00:01 --:--:-- 9
local@server:~$ curl -d @message -X POST 10.10.10.2:8881
<html><body><h1>POST!</h1></body></html>
remote@server:~$ python3 SimpleHTTPServer+.py 8881
Serving HTTP on 0.0.0.0 port 8881 (http://0.0.0.0:8881/) ...
10.10.10.1 - - [11/Oct/2018 10:52:10] "PUT /message HTTP/1.1" 201 -
10.10.10.1 - - [11/Oct/2018 10:52:18] "POST / HTTP/1.1" 200 -
Hi there!
remote@server:~$ cat message
Hi there!
Доступные методы: GET
, POST
, PUT
.
PHP
Неудивительно, что двухстрочный скрипт на PHP может решить все наши проблемы — “препроцессор гипертекста” как-никак
Итак, для тривиального PHP-сервера нам понадобится такой код:
<?php
$fname = basename($_REQUEST['filename']);
file_put_contents('uploads/' . $fname, file_get_contents('php://input'));
?>
На скриншоте ниже (кликабельно) можно видеть всю процедуру запуска сервера: предварительная настройка на панели слева, тесты — справа.
Несколько слов о том, что здесь происходит:
- Создаем необходимые директории и скрипт с содержимым выше.
- Создаем пользователя, от которого будет крутиться сервер. Новый пользователь нужен для того, чтобы недруги не смогли выполнить код, который сами загрузят. Поэтому командой
umask 555
задаем настройку прав доступа, выдаваемых всем новым файлам, которые будет создавать наш юзер.555
это777 XOR 222
, следовательно дефолтные биты будут выставлены, как если бы мы каждому новому файлу вручную задавалиchmod 222
(разрешена только запись). - Запускаем сервер и тестируем.
- ???????
- PROFIT
Доступные методы: GET
, POST
, PUT
.
Nginx
Ну и куда же без the High-Performance Web Server and Reverse Proxy? Благо, на большинстве Linux-дистрибутивах Nginx предустановлен, поэтому настроить и развернуть его можно в считанные минуты.
Опять же на скриншоте ниже можно видеть всю процедуру запуска: предварительная настройка на панели сверху, тесты — снизу.
Что происходит здесь:
- Создаем необходимые директории и конфигурацию сервера по образцу из
default
‘а (содержимое конфига есть ниже). - Делаем конфиг активным (симлинк в
/etc/nginx/sites-enabled/
) - Перезапускаем службу
nginx
, проверяем ее активность и тестируем сервер. - ???????
- PROFIT
Файл с конфигом:
root@kali:~# cat /etc/nginx/sites-available/file_upload
server {
listen 8881 default_server;
server_name snovvcrash.top;
location / {
root /var/www/uploads;
dav_methods PUT;
create_full_put_path on;
dav_access group:rw all:r;
}
}
Как напользовались, не забываем остановить сервер:
root@kali:~# systemctl stop nginx
Доступные методы: GET
, PUT
.