Установка SurrealDB на VPS: Docker, TLS, persistent storage и автоматические бэкапы
TL;DR
В этом руководстве мы развернём SurrealDB 2.x на Ubuntu Server 24.04 через Docker Compose, подключим постоянное хранилище, закроем базу за Caddy с автоматическим TLS, настроим firewall и ежедневные бэкапы в S3 с помощью Restic.
- SurrealDB будет работать в отдельном контейнере с фиксированной версией образа.
- Данные будут храниться на диске VPS, а не внутри эфемерного Docker-контейнера.
- Публичным останется только HTTPS-порт 443; порт SurrealDB 8000 будет доступен лишь локально.
- Caddy автоматически получит и продлит TLS-сертификат Let’s Encrypt.
- Ежедневно будут создаваться логический экспорт базы и резервная копия конфигурации.
- Перед обновлением можно выполнить проверку, ручной экспорт и откат контейнера на предыдущую версию.
1. TL;DR
Этот раздел уже содержит краткий план развертывания. Если вы впервые работаете с VPS, выполняйте команды последовательно: сначала подготовьте операционную систему, затем установите Docker, создайте каталог проекта, настройте переменные окружения, запустите контейнеры и только после проверки подключайте DNS к серверу.
2. Содержание
Статья рассчитана на владельца VPS, который хочет самостоятельно запустить SurrealDB для SaaS-приложения, внутреннего сервиса, прототипа или небольшого production-проекта. Конфигурация не привязана к конкретному фреймворку: к базе можно подключаться через HTTP API, WebSocket или официальный SDK.
Для production важно понимать границы примера. Один VPS с одной копией базы не является отказоустойчивым кластером. TLS, firewall и бэкапы защищают от распространённых операционных ошибок, но не заменяют резервный сервер, мониторинг и регулярную проверку восстановления данных.
3. Что мы настраиваем и зачем
Что такое SurrealDB
SurrealDB — мультимодельная база данных с поддержкой документного, графового и реляционного подходов. Она предоставляет собственный SQL-подобный язык SurrealQL, HTTP API, WebSocket-подключения и механизм аутентификации. Это удобно, когда приложению нужны документы, связи между сущностями и запросы к нескольким моделям данных без отдельного набора специализированных сервисов.
В руководстве используется ветка SurrealDB 2.x. Конкретный тег образа нужно фиксировать, а не использовать latest. Непредсказуемое обновление может изменить синтаксис запросов, формат экспорта или поведение транзакций в момент перезапуска контейнера.
Архитектура итоговой установки
На сервере будут работать два контейнера Docker Compose:
surrealdb— сервер базы данных, слушающий HTTP и WebSocket на внутреннем адресе Docker-сети;caddy— reverse proxy, принимающий HTTPS-запросы и передающий их в SurrealDB.
Порт 8000 не будет опубликован во внешний интернет. Caddy подключится к SurrealDB по имени сервиса surrealdb:8000. Данные базы будут размещены в каталоге /srv/surrealdb/data, который монтируется в контейнер. Конфигурация Compose, файл .env, Caddyfile и экспорт базы будут находиться отдельно от Docker-слоёв.
Что получится после выполнения инструкции
После настройки у вас будет адрес вида https://db.example.com. Через него приложение сможет выполнять API-запросы к SurrealDB. Сервер получит TLS-сертификат автоматически, а Caddy будет продлевать его без ручного запуска Certbot.
Также появится команда для ручной проверки:
curl -fsS https://db.example.com/health
При исправной работе SurrealDB ответит успешным HTTP-статусом. Для административных операций нужно использовать отдельные учётные данные и не передавать пароль в URL, shell history или исходный код приложения.
Self-hosted или managed-сервис
| Критерий | SurrealDB на собственном VPS | Managed-сервис |
|---|---|---|
| Контроль | Полный контроль над ОС, сетью, версиями и размещением данных | Часть инфраструктуры скрыта и управляется провайдером |
| Стоимость | Фиксированная стоимость VPS и отдельного хранилища бэкапов | Оплата зависит от тарифа, операций, трафика и объёма данных |
| Обслуживание | Обновления, мониторинг и восстановление выполняются самостоятельно | Часть задач выполняет оператор сервиса |
| Гибкость | Можно менять сетевые правила, прокси и файловую структуру | Доступны только предусмотренные API и настройки |
Self-hosted вариант разумен, если данные должны находиться на выбранной площадке, нужен предсказуемый бюджет или требуется полный контроль над окружением. Managed-решение может быть лучше для команды без опыта администрирования, для критичных систем с требованием высокой доступности или когда нет времени самостоятельно тестировать восстановление.
Ограничения одиночного сервера
Один VPS имеет единую точку отказа: проблема с диском, гипервизором, сетевой связностью или ошибочная команда администратора может временно сделать базу недоступной. Бэкап в том же каталоге не спасает от потери всего сервера, поэтому резервные копии должны отправляться во внешнее S3-совместимое хранилище или на отдельный сервер.
Не публикуйте SurrealDB напрямую в интернет без TLS и сетевых ограничений. Даже при наличии встроенной аутентификации открытый порт увеличивает поверхность атаки и усложняет контроль доступа.
4. Какой VPS-конфиг нужен под эту задачу
Минимальная конфигурация
Для разработки, тестирования и небольшой базы подойдёт VPS с двумя виртуальными CPU, 4 ГБ RAM и быстрым SSD-диском объёмом от 40 ГБ. Для production нужно оставить запас под файловый кэш, Docker, reverse proxy, бэкапы и фоновые процессы приложения.
| Сценарий | CPU | RAM | Диск | Сеть |
|---|---|---|---|---|
| Локальная разработка и демо | 2 vCPU | 2–4 ГБ | 40 ГБ NVMe SSD | 100 Мбит/с |
| Небольшой production | 2–4 vCPU | 4–8 ГБ | 80–160 ГБ NVMe SSD | 100–1000 Мбит/с |
| Средняя нагрузка | 4–8 vCPU | 16–32 ГБ | 200+ ГБ NVMe SSD | 1 Гбит/с |
В качестве практичного стартового варианта можно взять VPS с 4 vCPU, 8 ГБ RAM, NVMe SSD от 100 ГБ, публичным IPv4-адресом и портом 1 Гбит/с. Такой запас позволит запустить саму базу, Caddy, небольшой backend и сервис мониторинга, не доводя память до предела.
Как оценить диск
Размер диска должен включать не только текущий объём данных. Оставьте минимум 30–40 процентов свободного пространства для временных файлов, фрагментации, обновлений и экспорта. Например, если база занимает 35 ГБ, диск на 40 ГБ слишком мал: экспорт, лог и новые записи могут быстро заполнить файловую систему.
Логический экспорт может временно занимать размер, сопоставимый с базой. Если планируется хранить несколько локальных копий, размер диска нужно увеличить либо отправлять каждую копию сразу во внешнее хранилище.
Когда нужен dedicated
Выделенный сервер имеет смысл, если база постоянно использует много CPU или RAM, работает с десятками и сотнями гигабайт данных, обслуживает высокий поток запросов или должна иметь предсказуемую производительность без влияния соседних виртуальных машин. Dedicated также удобен для крупной ноды, аналитики и нескольких сервисов, которые нельзя разделить по разным VPS.
Для одной небольшой SurrealDB dedicated обычно избыточен. Сначала измерьте фактическую нагрузку: среднее и пиковое использование CPU, задержку диска, количество соединений, размер базы и частоту запросов. Переход на dedicated без метрик часто только увеличивает расходы, но не устраняет неправильные индексы или медленные запросы.
Выбор локации
Размещайте VPS ближе к пользователям и приложению. Если backend и SurrealDB находятся в одной локации, задержка между ними будет ниже, чем при подключении через несколько регионов. Для персональных данных дополнительно учитывайте требования законодательства, договоры с заказчиками и правила хранения данных.
Проверьте, выдаёт ли провайдер публичный IPv4 или только IPv6. Для автоматического TLS домен должен разрешаться на сервер, а входящие TCP-порты 80 и 443 должны быть доступны из интернета. Если используется только IPv6, убедитесь, что клиенты действительно поддерживают такой маршрут.
5. Подготовка сервера
Исходные условия
Пример рассчитан на свежую Ubuntu Server 24.04 LTS с пользователем, имеющим временный доступ через SSH. Работайте под обычным пользователем с sudo, а не под root. Замените admin, IP-адрес и домен на свои значения.
С локального компьютера создайте ключ, если его ещё нет:
ssh-keygen -t ed25519 -C "admin@vps"
Передайте публичный ключ на сервер:
ssh-copy-id admin@SERVER_IP
Проверьте вход по ключу в новом терминале. Не закрывайте текущую SSH-сессию, пока не убедитесь, что новый способ входа работает.
Обновление и базовые пакеты
Подключитесь к серверу и обновите индекс пакетов:
sudo apt update
sudo apt full-upgrade -y
Установите утилиты для диагностики, firewall, защиты SSH и работы с репозиториями:
sudo apt install -y \
ca-certificates \
curl \
gnupg \
lsb-release \
git \
jq \
unzip \
htop \
ncdu \
ufw \
fail2ban \
restic
Перезагрузите сервер, если обновлялось ядро:
sudo reboot
Пользователь и sudo
Если пользователь ещё не создан, выполните команду под root или существующим администратором:
sudo adduser deploy
sudo usermod -aG sudo deploy
sudo install -d -m 700 -o deploy -g deploy /home/deploy/.ssh
sudo cp /home/admin/.ssh/authorized_keys /home/deploy/.ssh/authorized_keys
sudo chown deploy:deploy /home/deploy/.ssh/authorized_keys
sudo chmod 600 /home/deploy/.ssh/authorized_keys
Проверьте вход:
ssh deploy@SERVER_IP
Настройка SSH
Создайте отдельный drop-in-файл SSH, чтобы не изменять основной конфиг:
sudo tee /etc/ssh/sshd_config.d/ hardening.conf >/dev/null <<'EOF'
В имени пути выше не должно быть пробела. Используйте корректную команду:
sudo tee /etc/ssh/sshd_config.d/hardening.conf >/dev/null <<'EOF'
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
EOF
sudo sshd -t
sudo systemctl reload ssh
До отключения паролей убедитесь, что ключевой вход уже проверен. Если потерять единственный рабочий ключ и отключить пароль, потребуется консоль провайдера или rescue-режим.
Firewall UFW
Оставьте SSH, HTTP и HTTPS. Порт 8000 не открывайте: он понадобится только внутри Docker-сети.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose
Если SSH работает на нестандартном порту, замените правило 22/tcp на фактический порт. При использовании IPv6 проверьте, что правила UFW применяются и к IPv6.
Fail2ban
Создайте локальную настройку jail для SSH:
sudo tee /etc/fail2ban/jail.d/sshd.local >/dev/null <<'EOF'
[sshd]
enabled = true
port = 22
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1h
EOF
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
Fail2ban не заменяет ключи, firewall и обновления. Он лишь временно блокирует IP-адреса, с которых наблюдаются повторяющиеся неудачные попытки входа.
6. Установка ПО — пошагово
Шаг 1. Установка Docker Engine и Compose Plugin
Для Ubuntu можно использовать официальный установочный скрипт Docker. В production предпочтительно подключить официальный apt-репозиторий и зафиксировать версии пакетов, но для первого развёртывания скрипт сокращает количество ручных действий.
curl -fsSL https://get.docker.com -o /tmp/get-docker.sh
sudo sh /tmp/get-docker.sh
rm /tmp/get-docker.sh
Добавьте текущего пользователя в группу Docker:
sudo usermod -aG docker "$USER"
newgrp docker
Проверьте версии:
docker --version
docker compose version
docker run --rm hello-world
В 2026 году используйте актуальный Docker Engine и Compose v2, но для воспроизводимости фиксируйте версию образа SurrealDB в Compose-файле. Группа Docker фактически даёт права, близкие к root, поэтому не добавляйте в неё лишних пользователей.
Шаг 2. Создание структуры каталогов
Создайте отдельный каталог приложения, каталог данных и директорию для локальных экспортов:
sudo mkdir -p /srv/surrealdb/{data,backups,caddy/data,caddy/config}
sudo chown -R "$USER":"$USER" /srv/surrealdb
cd /srv/surrealdb
Не удаляйте каталог data при переустановке контейнеров. Именно там находятся постоянные данные SurrealDB.
Шаг 3. Создание файла секретов
Файл .env будет прочитан Docker Compose. Пароль должен быть длинным, случайным и уникальным для этой базы. Не добавляйте файл в Git.
DB_ROOT_PASSWORD="$(openssl rand -base64 32 | tr -dc 'A-Za-z0-9_@%+=' | head -c 32)"
printf 'SURREAL_ROOT_USER=root\nSURREAL_ROOT_PASSWORD=%s\n' "$DB_ROOT_PASSWORD" > /srv/surrealdb/.env
chmod 600 /srv/surrealdb/.env
cat /srv/surrealdb/.env
Сохраните пароль в менеджере секретов. Команда cat показана только для первичной проверки и не должна выполняться при записи терминала или демонстрации экрана.
Шаг 4. Создание Docker Compose
Ниже используется пример образа surrealdb/surrealdb:v2.6.0. Перед установкой проверьте доступность нужного стабильного тега в реестре и выберите версию, протестированную вашим приложением. Не заменяйте тег на latest.
cat > /srv/surrealdb/compose.yml <<'EOF'
services:
surrealdb:
image: surrealdb/surrealdb:v2.6.0
container_name: surrealdb
restart: unless-stopped
command:
- start
- --log
- info
- --user
- ${SURREAL_ROOT_USER}
- --pass
- ${SURREAL_ROOT_PASSWORD}
- rocksdb:/data/database.db
environment:
TZ: UTC
volumes:
- ./data:/data
expose:
- "8000"
healthcheck:
test: ["CMD", "/surreal", "isready", "--endpoint", "http://127.0.0.1:8000"]
interval: 30s
timeout: 5s
retries: 5
start_period: 20s
networks:
- surrealnet
caddy:
image: caddy:2.10-alpine
container_name: surrealdb-caddy
restart: unless-stopped
depends_on:
surrealdb:
condition: service_healthy
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./caddy/data:/data
- ./caddy/config:/config
networks:
- surrealnet
networks:
surrealnet:
driver: bridge
EOF
Команда start запускает сервер, а путь rocksdb:/data/database.db указывает SurrealDB использовать RocksDB-файл внутри постоянного каталога. Не монтируйте один и тот же файл одновременно в несколько экземпляров базы.
Шаг 5. Запуск и проверка контейнеров
Перед запуском проверьте итоговую интерполяцию переменных и синтаксис Compose:
cd /srv/surrealdb
docker compose --env-file .env config
Запустите сервисы в фоне:
docker compose --env-file .env up -d surrealdb
Посмотрите состояние и логи:
docker compose ps
docker compose logs --tail=100 surrealdb
На этом этапе Caddy ещё не настроен, поэтому сначала проверьте внутренний endpoint:
curl -fsS http://127.0.0.1:8000/health || true
docker inspect --format='{{json .State.Health}}' surrealdb | jq
Если контейнер завершился, не запускайте его бесконечно в цикле. Сначала изучите логи: чаще всего причиной являются неправильная переменная окружения, занятый порт, повреждённый каталог данных или ошибка в параметрах запуска.
Шаг 6. Проверка версии образа
Убедитесь, что контейнер работает на ожидаемом образе:
docker inspect --format='{{.Config.Image}}' surrealdb
docker exec surrealdb /surreal version
В production запишите выбранный тег в журнал изменений проекта. Если приложение зависит от конкретных возможностей SurrealQL, создайте тестовый сценарий миграции и запросов до обновления.
7. Конфигурация
DNS и доменное имя
Пусть база будет доступна по адресу db.example.com. Создайте DNS-запись типа A, указывающую на IPv4-адрес VPS. Если используете IPv6, добавьте AAAA-запись только после проверки маршрутизации и firewall.
Проверить DNS можно с самого сервера:
getent hosts db.example.com
dig +short A db.example.com
dig +short AAAA db.example.com
Не запускайте автоматический TLS до того, как DNS начнёт возвращать правильный адрес. Let’s Encrypt должен иметь возможность подключиться к порту 80 или 443 снаружи.
Caddyfile для TLS и reverse proxy
Создайте файл /srv/surrealdb/Caddyfile. Замените домен и контактный email на свои значения:
cat > /srv/surrealdb/Caddyfile <<'EOF'
{
email [email protected]
}
db.example.com {
encode zstd gzip
reverse_proxy surrealdb:8000 {
health_uri /health
health_interval 30s
health_timeout 5s
}
log {
output file /data/access.log
format json
}
header {
Strict-Transport-Security "max-age=31536000"
X-Content-Type-Options "nosniff"
Referrer-Policy "no-referrer"
}
}
EOF
chmod 644 /srv/surrealdb/Caddyfile
Caddy получает сертификат, хранит его в каталоге caddy/data и автоматически продлевает. Этот каталог также нужно включать в резервные копии: без него Caddy сможет получить сертификат заново, но будут потеряны локальные данные о состоянии ACME и история конфигурации.
Запуск Caddy
После настройки DNS запустите reverse proxy:
cd /srv/surrealdb
docker compose --env-file .env up -d
docker compose ps
docker compose logs --tail=100 caddy
В логах должно быть сообщение об успешной выдаче сертификата или о том, что сертификат уже существует. Если Caddy не может получить сертификат, проверьте DNS, UFW, security group у провайдера и наличие другого процесса на портах 80 или 443.
Проверка HTTPS
Проверьте TLS и health endpoint:
curl -I https://db.example.com
curl -fsS https://db.example.com/health
openssl s_client -connect db.example.com:443 -servername db.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates
Ожидайте HTTP-ответ без ошибки сертификата и даты действия сертификата, соответствующие текущему периоду. Проверку выполняйте с внешнего компьютера, а не только с самого VPS: локальная проверка может не заметить проблемы с маршрутизацией или DNS.
Проверка аутентификации
Для административного API используйте пароль из локального файла секретов. Не передавайте его в командной строке, если это приводит к попаданию в history или список процессов. Конкретный endpoint и формат запроса зависят от версии SurrealDB и используемого SDK, поэтому сверяйте пример с документацией установленного релиза.
Минимальная проверка доступности сервера выполняется без передачи секрета:
curl -fsS https://db.example.com/health
Затем выполните тестовый запрос из временного скрипта приложения или официального CLI, передав учётные данные через переменные окружения. После проверки удалите тестовые записи либо используйте отдельную базу и namespace.
Проверка persistent storage
Убедитесь, что каталог данных смонтирован:
docker inspect surrealdb --format '{{range .Mounts}}{{println .Source " -> " .Destination}}{{end}}'
sudo du -sh /srv/surrealdb/data
sudo find /srv/surrealdb/data -maxdepth 2 -type f -ls | head
Для проверки переживания перезапуска создайте тестовую запись, перезапустите контейнер и прочитайте её снова. Делайте это в тестовом namespace, если база уже используется приложением.
docker compose restart surrealdb
docker compose ps
docker compose logs --tail=50 surrealdb
Настройка ограничений ресурсов
Если на VPS работают другие сервисы, задайте контейнеру разумные ограничения. Не ставьте лимит памяти ниже фактического рабочего набора: при нехватке памяти процесс может быть завершён OOM-killer.
services:
surrealdb:
deploy:
resources:
limits:
cpus: "4.0"
memory: 6G
reservations:
cpus: "1.0"
memory: 2G
В обычном Docker Compose поле deploy поддерживается не всеми режимами одинаково. Перед применением проверьте результат командой docker inspect. Важнее всего оставить операционной системе минимум 1–2 ГБ RAM и следить за swap, latency диска и OOM-событиями.
8. Бэкапы и обслуживание
Что необходимо сохранять
Резервная копия должна включать данные базы, конфигурацию Compose, Caddyfile, каталог Caddy с ACME-состоянием и файл переменных окружения. Пароль из .env нельзя публиковать в открытом виде, поэтому репозиторий Restic должен быть зашифрованным, а пароль Restic — храниться отдельно.
/srv/surrealdb/data— постоянные файлы базы;/srv/surrealdb/compose.yml— описание контейнеров;/srv/surrealdb/Caddyfile— reverse proxy и TLS-настройки;/srv/surrealdb/caddy/dataиcaddy/config— состояние Caddy;- логический экспорт SurrealDB — независимый от файлового формата слой восстановления.
Не полагайтесь только на копирование живого каталога базы. Для файловой базы важно учитывать согласованность данных. Логический экспорт, выполненный самим сервером, обычно проще переносить между версиями и хранилищами.
Подготовка S3 и Restic
Создайте отдельный S3-бакет с ограниченными правами: только запись и чтение объектов резервной копии, без доступа к другим бакетам. Для Restic задайте переменные в файле, доступном только root:
sudo install -m 600 /dev/null /root/restic.env
sudo tee /root/restic.env >/dev/null <<'EOF'
export AWS_ACCESS_KEY_ID='REPLACE_ME'
export AWS_SECRET_ACCESS_KEY='REPLACE_ME'
export RESTIC_REPOSITORY='s3:https://s3.example.net/my-surrealdb-backups'
export RESTIC_PASSWORD='REPLACE_WITH_LONG_RESTIC_PASSWORD'
EOF
Не храните этот файл в публичном Git-репозитории. При наличии штатного secret manager лучше загружать ключи оттуда во время выполнения задания cron.
Скрипт ежедневного бэкапа
Создайте каталог для временных экспортов и скрипт:
sudo mkdir -p /var/lib/surrealdb-backup
sudo tee /usr/local/sbin/backup-surrealdb >/dev/null <<'EOF'
#!/usr/bin/env bash
set -Eeuo pipefail
PROJECT_DIR="/srv/surrealdb"
BACKUP_DIR="/var/lib/surrealdb-backup"
STAMP="$(date -u +%Y-%m-%dT%H-%M-%SZ)"
EXPORT_FILE="${BACKUP_DIR}/surrealdb-${STAMP}.surql"
source /root/restic.env
mkdir -p "$BACKUP_DIR"
cd "$PROJECT_DIR"
docker compose --env-file .env ps --status running surrealdb | grep -q surrealdb
docker exec surrealdb /surreal export \
--endpoint http://127.0.0.1:8000 \
--user "$SURREAL_ROOT_USER" \
--pass "$SURREAL_ROOT_PASSWORD" \
"$EXPORT_FILE"
restic backup \
"$EXPORT_FILE" \
"$PROJECT_DIR/compose.yml" \
"$PROJECT_DIR/Caddyfile" \
"$PROJECT_DIR/.env" \
"$PROJECT_DIR/caddy"
restic forget \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
--prune
rm -f "$EXPORT_FILE"
echo "Backup completed: $STAMP"
EOF
sudo chmod 700 /usr/local/sbin/backup-surrealdb
В некоторых версиях CLI параметры экспорта могут отличаться. Выполните docker exec surrealdb /surreal export --help и адаптируйте команду под установленный релиз. Если CLI не может записать файл в путь внутри контейнера, используйте временный каталог с отдельным volume или вывод экспорта в stdout с перенаправлением на хост.
Инициализация репозитория и тестовый запуск
Инициализируйте зашифрованный репозиторий Restic:
sudo bash -c 'source /root/restic.env && restic init'
sudo /usr/local/sbin/backup-surrealdb
Проверьте список снимков:
sudo bash -c 'source /root/restic.env && restic snapshots'
sudo bash -c 'source /root/restic.env && restic check'
Команда restic check проверяет структуру репозитория, но не доказывает, что приложение сможет восстановить базу. Минимум раз в месяц выполняйте полное тестовое восстановление в отдельном временном каталоге или на тестовом VPS.
Планировщик cron
Создайте ежедневное задание с запуском, например, в 03:15 UTC:
sudo tee /etc/cron.d/surrealdb-backup >/dev/null <<'EOF'
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
15 3 root /usr/local/sbin/backup-surrealdb >> /var/log/surrealdb-backup.log 2>&1
EOF
sudo chmod 644 /etc/cron.d/surrealdb-backup
sudo systemctl restart cron
Настройте уведомление о сбое. Простой вариант — отправлять статус в внешний healthcheck-сервис в конце скрипта; более надёжный — использовать мониторинг, который проверяет время появления последнего снимка Restic и размер репозитория.
Восстановление экспорта
Сначала скачайте нужный snapshot в отдельный каталог:
sudo mkdir -p /var/lib/surrealdb-restore
sudo bash -c 'source /root/restic.env && restic restore latest --target /var/lib/surrealdb-restore'
sudo find /var/lib/surrealdb-restore -type f -name '.surql' -ls
Не импортируйте данные поверх единственной production-базы без окна обслуживания и проверенного плана. Поднимите временный контейнер на отдельном каталоге, импортируйте экспорт, проверьте количество записей и основные запросы приложения. Только после этого планируйте восстановление production.
Обновление SurrealDB
Обновление должно выполняться в maintenance window:
- проверить release notes и совместимость SurrealQL;
- создать ручной экспорт;
- проверить наличие свежего Restic snapshot;
- изменить только тег образа в
compose.yml; - запустить контейнер и проверить health endpoint;
- выполнить smoke-тесты приложения.
cd /srv/surrealdb
sudo /usr/local/sbin/backup-surrealdb
docker compose pull surrealdb
docker compose up -d surrealdb
docker compose ps
docker compose logs --tail=100 surrealdb
curl -fsS https://db.example.com/health
Для базы с одним экземпляром это не rolling update: на короткое время будет перерыв. Rolling-схема требует совместимых версий, отдельного экземпляра, продуманной репликации и проверки поведения клиентов. Не пытайтесь получить бесшовное обновление простым запуском второго контейнера на том же каталоге данных.
Мониторинг
Контролируйте свободное место, память, перезапуски контейнера, ошибки в логах и задержку диска:
df -h
free -h
docker stats --no-stream
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
sudo journalctl -u docker --since "1 hour ago"
sudo dmesg -T | grep -i -E 'oom|killed process|ext4|nvme' || true
Алерт по диску стоит включать уже при 70–80 процентах заполнения, а не ждать 100 процентов. При полном диске база может перестать записывать транзакции, а Caddy и Docker — создавать логи и временные файлы.
9. Troubleshooting и FAQ
Почему контейнер SurrealDB сразу завершается?
Сначала выполните docker compose logs --tail=200 surrealdb и проверьте итоговую конфигурацию командой docker compose config. Частые причины — неправильное имя переменной, ошибка в параметрах start, недоступный каталог данных или несовместимый тег образа. Проверьте также docker exec surrealdb /surreal version, если контейнер успевает запуститься. Не удаляйте каталог data до выяснения причины.
Почему Caddy не получает TLS-сертификат?
Проверьте, что DNS-запись домена указывает на этот VPS, а порты 80 и 443 разрешены и в UFW, и во внешней security group. Выполните curl -I http://db.example.com с другой сети и посмотрите docker compose logs caddy. Если на порту уже работает Nginx или Apache, остановите его либо перенесите сервис. Также проверьте корректность email и отсутствие временного rate limit ACME.
Получаю timeout при подключении к базе
Убедитесь, что контейнер здоров: docker compose ps и docker inspect surrealdb. Затем проверьте доступность Caddy через curl -v https://db.example.com/health. Порт 8000 намеренно не опубликован наружу, поэтому подключение напрямую к SERVER_IP:8000 не должно работать. Если запросы из Caddy не проходят, проверьте имя сервиса surrealdb и общую Docker-сеть в Compose.
Какой VPS-конфиг минимально подойдёт?
Для разработки достаточно 2 vCPU, 2–4 ГБ RAM и SSD от 40 ГБ. Для небольшой production-системы безопаснее начать с 2–4 vCPU, 8 ГБ RAM и NVMe от 80–100 ГБ. Оценку нужно делать по размеру базы, числу одновременных клиентов, сложности запросов и объёму приложения на том же сервере. Оставляйте не менее 30 процентов диска свободным и не размещайте единственный бэкап на том же VPS.
Что выбрать — VPS или dedicated для этой задачи?
VPS подходит для большинства небольших и средних установок: он дешевле, быстро масштабируется и предоставляет достаточно CPU, RAM и SSD. Dedicated оправдан при постоянной высокой нагрузке, больших объёмах данных, требовании к стабильной производительности или когда на сервере будут работать несколько ресурсоёмких сервисов. Решение принимайте по метрикам, а не по предполагаемому престижу оборудования: сначала измерьте CPU, RAM, I/O и задержки запросов.
Данные исчезли после пересоздания контейнера. Что сделано неправильно?
Вероятнее всего, контейнер запускался без bind mount или volume, либо был удалён каталог /srv/surrealdb/data. Проверьте раздел volumes в Compose и вывод docker inspect surrealdb. Команда docker compose down -v может удалить именованные volumes, поэтому не используйте её без понимания последствий. Если данные действительно потеряны, восстановите последний логический экспорт или snapshot Restic на тестовый экземпляр.
Как изменить пароль root?
Не редактируйте пароль в одном только .env, пока не понимаете, как именно текущая версия SurrealDB применяет параметры запуска. Сначала создайте свежий бэкап и изучите поддерживаемую процедуру изменения учётной записи для вашей версии. После смены секрета обновите .env, перезапустите контейнер и проверьте подключение приложения. Старый пароль удалите из shell history, временных файлов и систем мониторинга.
Можно ли открыть порт 8000 для подключения из приложения?
Если приложение находится на том же VPS, подключайте его к Docker-сети по адресу http://surrealdb:8000. Если backend работает на другом сервере, безопаснее использовать HTTPS через Caddy, private network или VPN, а не открывать 8000 всему интернету. При необходимости ограничьте firewall конкретным IP-адресом приложения и всё равно используйте аутентификацию. Публичный endpoint должен иметь TLS и мониторинг попыток входа.
Почему резервная копия не создаётся?
Запустите скрипт вручную и смотрите полный вывод. Проверьте доступ к S3, правильность endpoint, наличие переменных из /root/restic.env и свободное место в /var/lib/surrealdb-backup. Затем выполните restic snapshots и restic check. Отдельно проверьте команду экспорта через docker exec: изменение CLI между версиями может потребовать другой порядок или названия аргументов. В cron всегда указывайте абсолютные пути.
10. Выводы и следующие шаги
В результате SurrealDB работает в Docker на VPS с постоянным диском, HTTPS через Caddy, закрытым внутренним портом и ежедневным шифрованным бэкапом в S3. Конфигурация остаётся воспроизводимой: её можно перенести на новый сервер, восстановить данные и зафиксировать версию образа.
Дальше стоит добавить внешнее наблюдение за health endpoint и свежестью бэкапов, регулярно тестировать восстановление и оптимизировать индексы по реальным запросам. При росте нагрузки разделите приложение, базу и систему бэкапов по отдельным ресурсам, а перед переходом к нескольким экземплярам сначала проверьте совместимость репликации и процедуру миграции.