Оригинал: Arkeep — Централизованный Backup-сервер с агентами, на базе Restic и Rclone — Иван Чёрный, 23 июня 2026. Лицензия CC BY-NC-SA 4.0 . Публикуется с сохранением авторства и лицензии.
Предисловие
Arkeep — open-source система централизованного резервного копирования на основе Restic и Rclone. Проект решает проблему отсутствия полноценно централизованного инструмента бэкапа в экосистеме Open Source.
Архитектура построена по принципу сервер-агент: администратор разворачивает сервер Arkeep, ставит агенты на нужные хосты и управляет резервным копированием из единой панели. В качестве хранилища поддерживаются все решения, совместимые с Restic и Rclone (40+ провайдеров).
На момент написания проект активно развивается, возможны изменения в конфигурации и баги.
Схема резервного копирования
Настраиваем бэкап серверов на Debian 13 с помощью Arkeep в S3-хранилище RustFS. Доступ ко всем ресурсам — через обратный прокси Angie с автоматическими TLS-сертификатами Let’s Encrypt.
Важно: Web GUI работает по HTTP/HTTPS, агенты подключаются отдельно по gRPC. Взаимодействие агентов и сервера настраивается через проксирование gRPC (grpc_pass).
Вводные данные
| ПО | Версия |
|---|---|
| Debian | 13 |
| Docker Engine | 28 |
| Angie | 1.9.1 |
| Arkeep | 0.4.5 |
| RustFS | 1.0.0-beta.8 |
Доменная схема:
arkeep.r4ven.me— Web GUI сервера Arkeep;arkeep-grpc.r4ven.me— gRPC endpoint для агентов;rustfs.r4ven.me— Web GUI хранилища S3;rustfs-s3.r4ven.me— S3 endpoint для сохранения бэкапов.
Установка бэкап-сервера Arkeep
Подключаемся по SSH и переходим на root:
ssh ivan@arkeep.r4ven.me
sudo -iСоздаём Docker-сеть:
docker network create --opt com.docker.network.bridge.name=br-arkeep --opt com.docker.network.enable_ipv6=false --driver bridge --subnet 172.20.20.0/24 --gateway 172.20.20.1 arkeep_netСоздаём директорию проекта:
install -m 700 -d /etc/compose
mkdir -vp /etc/compose/arkeep && cd /etc/compose/arkeepcompose.yaml:
---
# https://github.com/arkeep-io/arkeep/tree/main/deploy/docker
networks:
arkeep_net:
external: true
volumes:
arkeep_server:
name: arkeep_server
arkeep_agent:
name: arkeep_agent
services:
arkeep_server:
image: ghcr.io/arkeep-io/arkeep-server:v0.4.5
container_name: arkeep-server
restart: unless-stopped
stop_grace_period: 1m
cpus: 1
mem_limit: 1G
hostname: arkeep-server
env_file: ./.env
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/health/ready"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
expose:
- "8080" # REST API + GUI
- "9090" # gRPC (agents)
volumes:
- arkeep_server:/var/lib/arkeep/
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
networks:
- arkeep_net
arkeep_agent:
image: ghcr.io/arkeep-io/arkeep-agent:v0.4.5
depends_on:
arkeep_server:
condition: service_healthy
container_name: arkeep-agent
restart: unless-stopped
stop_grace_period: 1m
cpus: 1
mem_limit: 1G
hostname: arkeep-agent
environment:
TZ: "${TZ:-Europe/Moscow}"
ARKEEP_SERVER_ADDR: "arkeep-server:9090"
ARKEEP_AGENT_SECRET: "${ARKEEP_AGENT_SECRET}"
ARKEEP_STATE_DIR: "/var/lib/arkeep-agent"
ARKEEP_LOG_LEVEL: "${ARKEEP_LOG_LEVEL:-info}"
ARKEEP_GRPC_INSECURE: "${ARKEEP_GRPC_INSECURE:-false}"
volumes:
- arkeep_agent:/var/lib/arkeep-agent/
- /:/hostfs/:ro # :ro for backup-only; change to :rw to also restore to local paths
- /var/run/docker.sock:/var/run/docker.sock:ro
- /var/lib/docker/volumes/:/var/lib/docker/volumes/:ro
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
networks:
- arkeep_netМонтирование корня ФС /:/hostfs/:ro в режиме только для чтения позволяет делать бэкапы. Для восстановления нужно поменять :ro на :rw.
.env:
# https://github.com/arkeep-io/arkeep/tree/main/deploy/docker
TZ=Europe/Moscow
ARKEEP_SECRET_KEY=
ARKEEP_AGENT_SECRET=
ARKEEP_DATA_DIR=/var/lib/arkeep/data
ARKEEP_DB_DRIVER=sqlite
ARKEEP_DB_DSN=/var/lib/arkeep/arkeep.db
ARKEEP_LOG_LEVEL=info
ARKEEP_SERVER_ADDR=arkeep-grpc.r4ven.me:443
ARKEEP_SERVER_HTTP_ADDR=https://arkeep.r4ven.me
ARKEEP_GRPC_INSECURE=true
ARKEEP_TELEMETRY=trueПараметры:
TZ— таймзона контейнера;ARKEEP_SECRET_KEY— ключ подписи JWT-токенов;ARKEEP_AGENT_SECRET— общий секрет сервера и агентов;ARKEEP_DATA_DIR— директория данных внутри контейнера;ARKEEP_DB_DRIVER— тип БД (sqliteилиpostgres);ARKEEP_DB_DSN— путь к файлу БД;ARKEEP_LOG_LEVEL— уровень логирования;ARKEEP_SERVER_ADDR— адрес для подключения агентов по gRPC (без http/https);ARKEEP_SERVER_HTTP_ADDR— внешний HTTPS-адрес Web GUI;ARKEEP_GRPC_INSECURE=true— отключён TLS-режим (за TLS отвечает Angie);ARKEEP_TELEMETRY— отправка анонимной статистики.
ARKEEP_AGENT_SECRETдолжен совпадать на сервере и всех агентах.
Генерируем секреты:
sed -iE "s/^ARKEEP_SECRET_KEY=.*/ARKEEP_SECRET_KEY=$(openssl rand -hex 32)/" ./.env
sed -iE "s/^ARKEEP_AGENT_SECRET=.*/ARKEEP_AGENT_SECRET=$(openssl rand -hex 24)/" ./.envЗапускаем стек и настраиваем автозапуск:
docker compose up -d && docker compose logs -fcat > ./arkeep.service << EOF
[Unit]
Description=Arkeep service
Requires=docker.service
After=docker.service
[Service]
Restart=always
RestartSec=5
User=root
Group=root
WorkingDirectory=$(realpath ./)
ExecStart=/usr/bin/docker compose up --remove-orphans
ExecStop=/usr/bin/docker compose down
[Install]
WantedBy=multi-user.target
EOF
chmod 600 ./arkeep.service
ln -s $(realpath ./arkeep.service) /etc/systemd/system
systemctl daemon-reload
systemctl enable --now arkeep
systemctl status arkeepУстановка S3-хранилища RustFS
Подробно установка и настройка RustFS разобрана в отдельной статье. Здесь — вариант для этой инсталляции (в общей сети
arkeep_net).
mkdir -vp /etc/compose/rustfs && cd /etc/compose/rustfscompose.yaml:
---
# https://github.com/rustfs/rustfs
networks:
arkeep_net:
external: true
volumes:
rustfs:
name: rustfs
services:
rustfs:
image: rustfs/rustfs:1.0.0-beta.8
container_name: rustfs
restart: unless-stopped
stop_grace_period: 30s
cpus: 1
mem_limit: 1G
hostname: rustfs
env_file: ./.env
healthcheck:
test:
["CMD", "sh", "-c", "curl -f http://127.0.0.1:9000/health && curl -f http://127.0.0.1:9001/rustfs/console/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
expose:
- "9000" # S3 API port
- "9001" # Console port
volumes:
- rustfs:/data/
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
networks:
- arkeep_net.env:
# https://docs.rustfs.com/installation/docker/#complete-parameter-configuration-example
TZ=Europe/Moscow
# RUSTFS_VOLUMES=/data/rustfs{0..3} # Define 4 storage volumes
RUSTFS_ADDRESS=0.0.0.0:9000
RUSTFS_CONSOLE_ENABLE=true
RUSTFS_CONSOLE_ADDRESS=0.0.0.0:9001
RUSTFS_CORS_ALLOWED_ORIGINS=https://rustfs.r4ven.me
RUSTFS_CONSOLE_CORS_ALLOWED_ORIGINS=https://rustfs.r4ven.me
RUSTFS_ACCESS_KEY=
RUSTFS_SECRET_KEY=
RUSTFS_OBS_LOGGER_LEVEL=infoУстанавливаем учётные данные, запускаем и настраиваем автозапуск (аналогично серверу Arkeep):
sed -iE "s/^RUSTFS_ACCESS_KEY=.*/RUSTFS_ACCESS_KEY=ivan/" ./.env
sed -iE "s/^RUSTFS_SECRET_KEY=.*/RUSTFS_SECRET_KEY=$(openssl rand -hex 32)/" ./.env
docker compose up -d && docker compose logs -fcat > ./rustfs.service << EOF
[Unit]
Description=RustFS S3 service
Requires=docker.service
After=docker.service
[Service]
Restart=always
RestartSec=5
User=root
Group=root
WorkingDirectory=$(realpath ./)
ExecStart=/usr/bin/docker compose up --remove-orphans
ExecStop=/usr/bin/docker compose down
[Install]
WantedBy=multi-user.target
EOF
chmod 600 ./rustfs.service
ln -s $(realpath ./rustfs.service) /etc/systemd/system
systemctl daemon-reload
systemctl enable --now rustfs
systemctl status rustfsУстановка обратного прокси Angie
mkdir -vp /etc/compose/angie && cd /etc/compose/angiecompose.yaml:
---
# https://angie.software/angie/docs/installation/docker/
networks:
arkeep_net:
external: true
services:
angie:
image: docker.angie.software/angie:1.9.1-alpine
container_name: angie
restart: unless-stopped
stop_grace_period: 1m
cpus: 1
mem_limit: 1G
hostname: angie
environment:
TZ: Europe/Moscow
volumes:
- ./config/angie.conf:/etc/angie/angie.conf:ro
- ./config/http.d/:/etc/angie/http.d/:ro
- ./certs/:/var/lib/angie/acme/
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "80:80/tcp"
- "443:443/tcp"
- "443:443/udp"
networks:
- arkeep_netСоздаём директорию конфигов и основной конфиг config/angie.conf:
mkdir -vp ./configuser angie;
worker_processes auto;
worker_rlimit_nofile 65536;
error_log /var/log/angie/error.log notice;
pid /run/angie/angie.pid;
events {
worker_connections 65536;
}
http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
include /etc/angie/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/angie/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 20;
keepalive_requests 1000;
server_tokens off;
# DNS resolver for ACME.
resolver 8.8.8.8 8.8.4.4 ipv6=off valid=300s;
acme_client le https://acme-v02.api.letsencrypt.org/directory
email=kar-kar@r4ven.me
key_type=ecdsa
renew_before_expiry=30d
;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
upstream arkeep_server {
server arkeep-server:9090;
}
upstream arkeep_console {
server arkeep-server:8080;
}
upstream rustfs_server {
server rustfs:9000;
}
upstream rustfs_console {
server rustfs:9001;
}
server {
listen 80;
server_name
arkeep-grpc.r4ven.me
arkeep.r4ven.me
rustfs-s3.r4ven.me
rustfs.r4ven.me
;
location /.well-known/acme-challenge/ {
root /usr/share/angie/html/;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
http2 on;
http3 on;
server_name arkeep-grpc.r4ven.me;
acme le;
ssl_certificate $acme_cert_le;
ssl_certificate_key $acme_cert_key_le;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
location / {
grpc_pass grpc://arkeep_server;
grpc_set_header Host $host;
grpc_set_header X-Real-IP $remote_addr;
grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
grpc_connect_timeout 10s;
grpc_send_timeout 1h;
grpc_read_timeout 1h;
grpc_socket_keepalive on;
}
}
server {
listen 443 ssl;
http2 on;
http3 on;
server_name arkeep.r4ven.me;
acme le;
ssl_certificate $acme_cert_le;
ssl_certificate_key $acme_cert_key_le;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
client_max_body_size 0;
location / {
proxy_pass http://arkeep_console;
proxy_http_version 1.1;
proxy_request_buffering off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_connect_timeout 10s;
proxy_send_timeout 1h;
proxy_read_timeout 1h;
}
}
server {
listen 443 ssl;
http2 on;
http3 on;
server_name rustfs-s3.r4ven.me;
acme le;
ssl_certificate $acme_cert_le;
ssl_certificate_key $acme_cert_key_le;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
client_max_body_size 0;
location / {
proxy_pass http://rustfs_server;
proxy_http_version 1.1;
proxy_request_buffering off;
proxy_buffering off;
proxy_cache off;
proxy_max_temp_file_size 0;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header X-Forwarded-Ssl on;
proxy_connect_timeout 10s;
proxy_send_timeout 1h;
proxy_read_timeout 1h;
}
}
server {
listen 443 ssl;
http2 on;
http3 on;
server_name rustfs.r4ven.me;
acme le;
ssl_certificate $acme_cert_le;
ssl_certificate_key $acme_cert_key_le;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://rustfs_console;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
include /etc/angie/http.d/*.conf;
}Обязательно замените
email=и значенияserver_nameпод свои домены.
Запускаем и настраиваем автозапуск:
docker compose up -d && docker compose logs -fcat > ./angie.service << EOF
[Unit]
Description=Angie proxy service
Requires=docker.service
After=docker.service
[Service]
Restart=always
RestartSec=5
User=root
Group=root
WorkingDirectory=$(realpath ./)
ExecStart=/usr/bin/docker compose up --remove-orphans
ExecStop=/usr/bin/docker compose down
[Install]
WantedBy=multi-user.target
EOF
chmod 600 ./angie.service
ln -s $(realpath ./angie.service) /etc/systemd/system
systemctl daemon-reload
systemctl enable --now angie
systemctl status angieУстановка агентов Arkeep на app-серверах
Переходим на хосты для бэкапа (app1.r4ven.me, app2.r4ven.me, …).
install -m 700 -d /etc/compose
mkdir -vp /etc/compose/arkeep_agent && cd /etc/compose/arkeep_agentcompose.yaml:
---
# https://github.com/arkeep-io/arkeep/tree/main/deploy/docker
volumes:
arkeep_agent:
name: arkeep_agent
services:
arkeep_agent:
image: ghcr.io/arkeep-io/arkeep-agent:v0.4.5
container_name: arkeep-agent-app1
restart: unless-stopped
stop_grace_period: 1m
cpus: 1
mem_limit: 1G
hostname: arkeep-agent-app1
env_file: ./.env
volumes:
- arkeep_agent:/var/lib/arkeep-agent/
- /:/hostfs/:ro # :ro for backup-only; change to :rw to also restore to local paths
- /var/run/docker.sock:/var/run/docker.sock:ro
- /var/lib/docker/volumes/:/var/lib/docker/volumes/:ro
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:roBind mount
/hostfsдаёт агенту доступ к ФС хоста. Режимroдостаточен для бэкапов; для восстановления нуженrw.
.env:
# https://github.com/arkeep-io/arkeep/tree/main/deploy/docker
TZ=Europe/Moscow
ARKEEP_SERVER_ADDR=arkeep-grpc.r4ven.me:443
ARKEEP_SERVER_HTTP_ADDR=https://arkeep.r4ven.me
ARKEEP_AGENT_SECRET=
ARKEEP_STATE_DIR=/var/lib/arkeep-agent
ARKEEP_LOG_LEVEL=info
ARKEEP_GRPC_INSECURE=false
ARKEEP_AGENT_SECRETдолжен совпадать со значением на сервере.ARKEEP_GRPC_INSECURE=false— TLS до Angie, затем без шифрования.
Запускаем:
docker compose up -d && docker compose logs -fПри успешном подключении в логах:
arkeep-agent-app1 | {"level":"info", ... "msg":"registered with server","agent_id":"019ebc8e-...","agent_name":"arkeep-agent-app1"}
arkeep-agent-app1 | {"level":"info", ... "msg":"job stream open","agent_id":"019ebc8e-..."}Автозапуск — по той же схеме, что и для сервера (arkeep-agent.service).
Настройка Arkeep
Destination — S3
Web GUI на https://arkeep.r4ven.me → «Destinations» → «New Destination» → тип «S3/Object Storage». Указываем имя бакета и реквизиты (endpoint = rustfs-s3.r4ven.me, access_key_id, secret_access_key для бакета с политикой readwrite).
Помимо S3 бэкапы можно сохранять в локальную директорию, по SFTP, в REST Server или в любое удалённое хранилище через Rclone (40+ провайдеров). Для Rclone в контейнер нужно доустановить rclone и примонтировать конфиг:
cat > ./rclone.conf << EOF
[webdav-backup]
type = webdav
url = https://cloud.example.com/remote.php/dav/files/USER
vendor = nextcloud
user = USER
pass = OBSCURED_PASSWORD
EOF---
services:
arkeep_agent:
image: ghcr.io/arkeep-io/arkeep-agent:v0.4.5
container_name: arkeep-agent-rclone
restart: unless-stopped
hostname: arkeep-agent-rclone
env_file: ./.env
command: sh -c 'apk add rclone; exec arkeep-agent'
volumes:
- ./data/:/var/lib/arkeep-agent/
- /:/hostfs/:rw
- /var/run/docker.sock:/var/run/docker.sock:ro
- /var/lib/docker/volumes/:/var/lib/docker/volumes/:ro
- ./rclone.conf:/root/.config/rclone/rclone.conf:roPolicy
«Policies» → «New Policy». Указываем имя задания, агента, пароль для шифрования, источники бэкапа (например, /etc и Docker volumes), расписание в формате crontab и время хранения. Выбираем S3-destination и, при необходимости, исключения.
Для расчёта расписания удобен crontab.guru .
Запуск и восстановление
Проверка — кнопка «Run» в Web GUI. Успешный бэкап появится в «Snapshots», а в S3 — файлы репозитория Restic.
Для восстановления по умолчанию ФС хоста монтируется :ro. Меняем на :rw в compose.yaml и перезапускаем агента:
systemctl restart arkeep-agentДалее «Snapshots» → выбираем бэкап → «Restore». Доступны режимы:
- Custom path — восстановление всего или отдельных файлов в заданную директорию хоста (без
hostfs); - Original path — восстановление по исходному пути (может перезаписать изменённые после бэкапа файлы).
Возможные проблемы
read only filesystem — директория назначения недоступна для записи. Смените :ro → :rw.
enrollment failed (server returned 405 Method Not Allowed) — при ARKEEP_GRPC_INSECURE=true механизм enrollment не используется; ошибку можно игнорировать, если агент подключается по gRPC (registered with server, job stream open).
failed to verify certificate (x509: certificate signed by unknown authority) — не указан ARKEEP_SERVER_HTTP_ADDR, агент идёт не на тот hostname, самоподписанный сертификат, либо TLS включён/выключен только на одной стороне.
certificate is valid for arkeep-grpc, not arkeep.r4ven.me — остановите сервер, удалите Docker volume с данными, перезапустите — сертификаты переиздадутся.
Про телеметрию
Arkeep раз в день собирает анонимную телеметрию (ID инстанса, версия, ОС, число агентов и политик). Личные данные, содержимое бэкапов и учётные данные не передаются. Отключается через ARKEEP_TELEMETRY=false. Статистика — на telemetry.arkeep.io/stats
.
Послесловие
Arkeep — удобный инструмент резервного копирования с большим потенциалом. Идея использования Restic и Rclone проста и эффективна. По ходу написания оригинала автор завёл два issue (#158 , #159 ) — разработчик оперативно исправил оба бага в 0.4.5.