ctrllife.ru/ctrllife

Как настроить сервер резервных копий в Proxmox LXC через HTTPS PUT без SSH

Как настроить сервер резервных копий в Proxmox LXC через HTTPS PUT без SSH
Содержание16 разделов

Централизованный сервер резервных копий можно развернуть в LXC-контейнере Proxmox VE без Proxmox Backup Server, SFTP и выдачи SSH-доступа каждому источнику. Если приложения уже создают готовые архивы .tar.gz, .zip или дампы баз данных, достаточно принимать их по HTTPS методом HTTP PUT.

В инструкции используется Debian 13, Nginx, индивидуальные HTTP-учётные записи и отдельный том для хранения файлов. Получится простой приёмник бэкапов для Linux-серверов, Windows и других систем, способных отправлять HTTP PUT-запросы.

Как работает схема резервного копирования

Linux / Windows / приложение
        |
        | HTTPS PUT :443 + индивидуальный пароль
        v
Proxmox VE → LXC Debian 13 → Nginx
                            |
                            +-- /srv/backups/server1/
                            +-- /srv/backups/server2/
                            +-- /srv/backups/.tmp/
                            |
                       отдельный том / ZFS

Каждому источнику назначаются собственный URL и пароль. Сервер server1 загружает архивы в https://backup.example.com/server1/, а server2 — в /server2/. SSH на стороне отправителей не используется.

Решение подходит именно для готовых файлов. Nginx не выполняет инкрементальное копирование, дедупликацию, создание архивов и восстановление систем: эти задачи остаются за программами резервного копирования.

Что потребуется

  • Proxmox VE с возможностью создать непривилегированный LXC-контейнер на Debian 13.
  • Отдельный том для архивов, желательно на ZFS или другом хранилище со снапшотами.
  • Домен, например backup.example.com, направленный на внешний IP сервера или маршрутизатора.
  • Доступ извне к TCP 443. Для выпуска и продления сертификата Let’s Encrypt методом HTTP-01 также потребуется TCP 80.
  • Программы-отправители, которые создают архивы и могут выполнить curl или аналогичный HTTP PUT-запрос.

Все IP-адреса, домены и имена серверов ниже приведены как примеры. При работе за NAT нужно настроить переадресацию портов на IP контейнера. Если приём доступен только через VPN, сертификат можно выпускать через DNS-01, не открывая порт 80 в интернет.

Шаг 1. Создание LXC-контейнера в Proxmox

В веб-интерфейсе Proxmox VE выбрать Create CT и указать следующие параметры:

Параметр |

Рекомендуемое значение |

Hostname |

backup-server |

Template |

Debian 13 |

Unprivileged container |

Включено |

CPU |

1 vCPU |

RAM |

512 МБ – 1 ГБ |

Root Disk |

8 ГБ |

Network |

Статический IP в локальной сети |

После создания контейнера открыть CT → Resources → Add → Mount Point, выбрать нужное хранилище и подключить отдельный том по пути /srv/backups. Размер зависит от объёма и срока хранения архивов. Для большого хранилища не следует использовать маленький корневой диск LXC.

Если создаётся управляемый Proxmox mount point, параметр Backup определяет, попадёт ли его содержимое в vzdump. Для большого архива часто удобнее отключить включение в бэкап контейнера и настроить резервирование данных отдельно. Bind mount имеет другую семантику: его данные в vzdump не включаются.

Запустить контейнер, открыть его консоль и убедиться, что хранилище действительно подключено:

findmnt /srv/backups
df -h /srv/backups

Если findmnt не показывает отдельный mount point, сначала исправить подключение тома. Иначе архивы могут незаметно заполнить корневой диск контейнера.

Шаг 2. Установка Nginx и необходимых пакетов

Все последующие команды выполняются от root внутри LXC через консоль Proxmox:

apt update && apt upgrade -y
apt install -y nginx apache2-utils certbot python3-certbot-nginx curl

Для приёма HTTP PUT нужен модуль ngx_http_dav_module. Проверить поддержку в установленной сборке Nginx:

nginx -V 2>&1 | grep -- '--with-http_dav_module'

Если строка --with-http_dav_module отсутствует, требуется сборка Nginx с этим модулем. Штатный DAV-модуль обрабатывает PUT, DELETE, MKCOL, COPY и MOVE, но сам по себе не является полноценным WebDAV-сервером для клиентов, которым нужны PROPFIND и другие методы.

Шаг 3. Подготовка каталогов для резервных копий

Создать директории для двух источников и временных файлов загрузки:

install -d -o root -g www-data -m 0750 /srv/backups
install -d -o www-data -g www-data -m 0700 \
  /srv/backups/server1 \
  /srv/backups/server2 \
  /srv/backups/.tmp

Структура каталогов:

/srv/backups/
├── .tmp/
├── server1/
└── server2/

Каталог .tmp должен находиться на той же файловой системе, что и конечные файлы: Nginx сначала пишет тело PUT-запроса во временный файл, после чего перемещает его в целевой каталог. На разных файловых системах вместо быстрого переименования потребуется копирование.

Пример рассчитан на стандартного пользователя процесса Nginx в Debian — www-data. При использовании bind mount в непривилегированном LXC могут понадобиться дополнительные настройки UID/GID на хосте Proxmox.

Шаг 4. Создание отдельных учётных записей

Для авторизации используется HTTP Basic Authentication через HTTPS. Пользователи существуют только в файлах .htpasswd; системные аккаунты Linux и доступ по SSH не создаются.

install -d -o root -g www-data -m 0750 /etc/nginx/backup-auth

htpasswd -cB /etc/nginx/backup-auth/server1.htpasswd server1
htpasswd -cB /etc/nginx/backup-auth/server2.htpasswd server2

chown root:www-data /etc/nginx/backup-auth/*.htpasswd
chmod 0640 /etc/nginx/backup-auth/*.htpasswd

Каждая команда htpasswd запросит пароль. Для каждого источника используется отдельный файл — поэтому параметр -c здесь безопасен. При добавлении нового пользователя в уже существующий файл -c использовать нельзя: он перезаписывает файл.

Благодаря разделению файлов аутентификации пароль server1 не подходит к URL /server2/. Учётные данные передаются только через действительный HTTPS-сеанс; без TLS HTTP Basic использовать нельзя.

Шаг 5. Настройка домена и сертификата Let’s Encrypt

Убедиться, что домен backup.example.com указывает на доступный контейнер, а TCP 80 и 443 корректно перенаправлены. На новом LXC можно отключить стандартный сайт Nginx:

rm -f /etc/nginx/sites-enabled/default

Создать временную конфигурацию виртуального хоста:

cat > /etc/nginx/sites-available/backup-upload <<'EOF'
server {
    listen 80;
    server_name backup.example.com;

    location / {
        return 404;
    }
}
EOF
ln -s /etc/nginx/sites-available/backup-upload \
  /etc/nginx/sites-enabled/backup-upload

nginx -t && systemctl reload nginx

Выпустить TLS-сертификат:

certbot certonly --nginx -d backup.example.com

Certbot запросит необходимые данные для регистрации и выполнит проверку владения доменом. Сертификат будет сохранён в /etc/letsencrypt/live/backup.example.com/. Если порт 80 недоступен из интернета, проверка HTTP-01 не пройдёт.

Шаг 6. Конфигурация Nginx для загрузки только через PUT

Заменить содержимое /etc/nginx/sites-available/backup-upload конфигурацией ниже. В ней предусмотрены два независимых URL, два файла авторизации и разрешён только метод PUT.

server {
    listen 80;
    server_name backup.example.com;

    # Порт 80 используется для проверки Let's Encrypt.
    location / {
        return 404;
    }
}

server {
    listen 443 ssl;
    server_name backup.example.com;

    ssl_certificate /etc/letsencrypt/live/backup.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/backup.example.com/privkey.pem;

    server_tokens off;
    client_max_body_size 20G;
    client_body_timeout 600s;
    client_body_temp_path /srv/backups/.tmp 1 2;

    # Все остальные URL закрыты.
    location / {
        return 404;
    }

    # Загружать можно только файлы с безопасными именами
    # непосредственно в каталог server1.
    location ~ ^/server1/[A-Za-z0-9][A-Za-z0-9._-]*$ {
        root /srv/backups;
        auth_basic "Backup Server 1";
        auth_basic_user_file /etc/nginx/backup-auth/server1.htpasswd;

        dav_methods PUT;
        create_full_put_path off;

        limit_except PUT {
            deny all;
        }
    }

    # Отдельная авторизация для server2.
    location ~ ^/server2/[A-Za-z0-9][A-Za-z0-9._-]*$ {
        root /srv/backups;
        auth_basic "Backup Server 2";
        auth_basic_user_file /etc/nginx/backup-auth/server2.htpasswd;

        dav_methods PUT;
        create_full_put_path off;

        limit_except PUT {
            deny all;
        }
    }
}

Особенности конфигурации:

  • dav_methods PUT включает загрузку файлов, но не включает DELETE или MOVE.
  • limit_except PUT отклоняет GET, HEAD, POST и другие методы.
  • Регулярное выражение ограничивает имя файла латинскими буквами, цифрами, точками, дефисами и подчёркиваниями. Вложенные каталоги через URL создавать нельзя.
  • client_max_body_size 20G задаёт максимально допустимый размер одного файла. Для больших архивов значение увеличивается.
  • client_body_temp_path размещает временные файлы на том же разделе, что и архивы.
  • auth_basic_user_file привязывает отдельный пароль к каждому источнику.

Проверить и применить конфигурацию:

nginx -t && systemctl reload nginx

Шаг 7. Проверка загрузки и прав доступа

На первом сервере создать небольшой тестовый файл:

printf 'Backup test\n' > /tmp/backup-test.txt

Отправить его через HTTPS. Команда curl запросит пароль пользователя server1:

curl --fail --show-error \
  --user server1 \
  --upload-file /tmp/backup-test.txt \
  --write-out '\nHTTP %{http_code}\n' \
  https://backup.example.com/server1/backup-test.txt

При успешном создании нового файла ожидается HTTP 201 Created. Код 204 No Content при повторной загрузке может означать, что существующий файл был перезаписан.

Проверить наличие архива из консоли LXC:

ls -lh /srv/backups/server1/

Убедиться, что удаление запрещено:

curl --user server1 -o /dev/null -sS -w 'HTTP %{http_code}\n' \
  -X DELETE \
  https://backup.example.com/server1/backup-test.txt

В этой конфигурации ожидается HTTP 403 Forbidden. Аналогично GET и HEAD должны быть запрещены. Для проверки изоляции источников повторить PUT на URL /server2/ с паролем server1: ожидается HTTP 401 Unauthorized.

После тестирования удалить backup-test.txt из консоли контейнера, а не через публичный интерфейс.

Шаг 8. Автоматическая отправка готовых архивов

Пароль не рекомендуется помещать прямо в параметры командной строки или в cron. На отправляющем Linux-сервере создать файл /root/.backup-netrc:

machine backup.example.com
login server1
password REPLACE_WITH_STRONG_PASSWORD

Ограничить права доступа:

chmod 600 /root/.backup-netrc

Пример отправки уже существующего архива:

FILE="/var/backups/backup-2026-11-03.tar.gz"
NAME="$(basename "$FILE")"

curl --fail --show-error --silent --retry 3 \
  --netrc-file /root/.backup-netrc \
  --upload-file "$FILE" \
  "https://backup.example.com/server1/$NAME"

Название архива должно соответствовать ограничению в Nginx и быть уникальным, например с датой, временем и идентификатором задания. Команду загрузки следует запускать после успешного завершения создания архива, а не параллельно с ним. Проверять нужно и код завершения curl, и результат самого задания бэкапа.

Для автоматизации можно использовать cron, systemd timer или механизм резервного копирования приложения. Внешние программы, которые требуют полноценный WebDAV с PROPFIND, с этой минимальной схемой могут быть несовместимы.

Шаг 9. Продление сертификата, мониторинг и очистка

Автоматическое продление сертификата

Чтобы Nginx перечитывал обновлённые сертификаты, создать deploy hook:

install -d /etc/letsencrypt/renewal-hooks/deploy

cat > /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh <<'EOF'
#!/bin/sh
set -eu
/usr/sbin/nginx -t
/usr/bin/systemctl reload nginx
EOF

chmod 755 /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
certbot renew --dry-run

Проверить, что в системе активирован штатный механизм автоматического продления Certbot, и не закрывать TCP 80, если используется проверка HTTP-01.

Свободное место и логи

Проверять заполнение тома и журнал ошибок Nginx:

df -h /srv/backups
journalctl -u nginx --since '1 day ago'
tail -n 100 /var/log/nginx/error.log

Контролировать следует не только общее свободное место, но и состояние ZFS-пула, свободную ёмкость с учётом снапшотов, ошибки отправки и факт поступления свежих архивов от каждого источника.

Очистка старых архивов

Для просмотра файлов старше 30 суток:

find /srv/backups/server1 \
  -maxdepth 1 -type f -mtime +30 -print

Удаление лучше выполнять отдельной задачей на принимающем сервере после определения политики хранения: например, ежедневные копии за 14 дней, недельные за 8 недель и месячные за 6 месяцев. Простое удаление всех файлов старше 30 дней подходит не для каждого сценария и может оставить систему без пригодной точки восстановления.

Безопасность: что ещё обязательно учесть

  • Не публиковать SSH для отправителей. Для администрирования достаточно консоли Proxmox или отдельного защищённого канала.
  • Ограничить источники по IP или принимать загрузки через WireGuard, если это позволяет инфраструктура.
  • Не использовать одни учётные данные для всех клиентов. Отдельные пароли упрощают отзыв доступа.
  • Неизменяемость не обеспечивается Nginx DAV. При компрометации пароля злоумышленник может перезаписывать файлы в каталоге отправителя.
  • Настроить снапшоты и независимую копию. Снапшот на том же диске не защищает от отказа самого диска, хоста или потери всего пула.
  • Периодически проверять восстановление. Успешный HTTP 201 подтверждает загрузку файла, но не пригодность самого архива.

Если требуется действительно create-only/write-once хранилище, штатный Nginx PUT без дополнительного серверного обработчика не подходит. Для строгой неизменяемости стоит использовать специально реализованный upload API с атомарной проверкой создания или S3-совместимое хранилище с политиками и Object Lock. Это отдельная задача, не решаемая одним запретом DELETE.

Частые ошибки

Симптом |

Вероятная причина |

401 Unauthorized |

Неверный логин/пароль или отправка в чужой каталог. |

403 Forbidden |

Запрещён HTTP-метод, недостаточны права или файл недоступен. |

404 Not Found |

Неправильный URL или имя файла не подходит под разрешённый шаблон. |

413 Content Too Large |

Файл больше client_max_body_size. |

500 Internal Server Error |

Проверить error.log, права на .tmp и свободное место. |

Не выпускается сертификат |

DNS, NAT или порт 80 недоступен для проверки HTTP-01. |

Документация

Частые вопросы

Можно ли заменить Proxmox Backup Server таким решением?

Только если нужно принимать готовые архивы. Nginx через HTTP PUT не поддерживает функции PBS: дедупликацию, специализированное резервное копирование виртуальных машин и управление точками восстановления.

Можно ли отправлять резервные копии с Windows?

Да. Подойдёт любой клиент Windows, способный отправлять HTTPS PUT с HTTP Basic Authentication, например curl.exe. Программа должна сначала создать архив, а затем отправить его.

Защищает ли запрет DELETE от удаления и перезаписи архивов?

Удаление через HTTP DELETE запрещено, но существующий файл можно перезаписать методом PUT. Для защиты нужны снапшоты, отдельные копии или хранилище с настоящей неизменяемостью.

Можно ли использовать обычный WebDAV-клиент?

Не всегда. Штатный модуль Nginx DAV не поддерживает PROPFIND, необходимый многим WebDAV-клиентам. Для этой схемы нужен клиент, отправляющий обычный HTTP PUT без дополнительных WebDAV-запросов.

Нужно ли открывать SSH для серверов-отправителей?

Нет. Отправителям достаточно HTTPS-доступа к соответствующему URL и отдельной HTTP-учётной записи. Администрирование самого контейнера выполняется независимо от сервиса загрузки.

Заключение

Debian LXC + Nginx + HTTPS PUT — простой способ построить центральное хранилище готовых резервных копий в Proxmox без SSH-доступа для клиентов. Отправители получают отдельные HTTP-учётные записи и каталоги, а загрузка сводится к одной команде curl. Для рабочей эксплуатации необходимо дополнить приём архивов контролем доставки, политикой хранения, снапшотами и второй независимой копией. Важно помнить, что это сервис приёма файлов, а не полнофункциональная система неизменяемого резервного копирования.

Оцените запись