Копии базы — под замком

Резервная копия базы — это вся компания в одном файле: абоненты, договоры, балансы, паспортные данные. Рядом с ней в облаке лежат счета, акты и записи разговоров. Вопрос, который стоит задать себе раньше, чем его задаст кто-то другой: а кто может это скачать?
В облаке два разных вида файлов
Биллинг складывает в облако то, что нельзя держать на диске сервера. Но файлы там разные по смыслу.
Первый вид — материалы, которые мы сами показываем всем: обложки модулей и тарифов, снимки экранов для документации, ролики, файлы виджетов. Им открытый доступ нужен по определению: страница должна показать картинку любому посетителю.
Второй вид — то, что не предназначено никому, кроме нас и клиента: ночные копии базы, договоры и акты, вложения обращений, записи разговоров, файлы из карточки клиента. Здесь «доступ по ссылке» — это не доступ, а его отсутствие: ссылка живёт в письмах, в истории браузера, в пересланных сообщениях, а имена файлов часто угадываются по дате и номеру документа.
Долгое время оба вида лежали в одном хранилище. Поводом разобраться стала проверка при настройке копий соседнего проекта: оказалось, что хранилище отдаёт файлы по прямой ссылке всем, кто эту ссылку знает. Для обложек это нормально. Для копии базы — нет.
flowchart TB
subgraph R1 ["Было"]
direction LR
A1["Обложки, снимки,<br/>ролики"] --> B1["Одно хранилище<br/>на всё"]
A2["Копии базы, договоры,<br/>записи разговоров"] --> B1
end
subgraph R2 ["Стало"]
direction LR
C1["Обложки, снимки,<br/>ролики"] --> D1["Открытое хранилище"]
C2["Копии базы, договоры,<br/>записи разговоров"] --> D2["Закрытое хранилище:<br/>публичного доступа нет"]
end
R1 --> R2
style R1 fill:none,stroke:none
style R2 fill:none,stroke:noneСсылка, которая никого не спрашивает
Разделить хранилища — половина дела. Вторая половина — ссылки. Раньше в базе биллинга у каждого документа хранился прямой адрес файла в облаке, и он же подставлялся на страницу, в письмо клиенту и в примечание к сделке. Такая ссылка не спрашивает, кто по ней пришёл: она работает у сотрудника, у клиента, у того, кому письмо переслали, и через год тоже работает.
Теперь ссылка ведёт не в облако, а в биллинг. Файл отдаёт сервер — после того, как ответит на вопрос «кому».
flowchart TB
subgraph R1 [" "]
direction LR
U["Сотрудник<br/>открывает документ"] --> S["Биллинг:<br/>вход и права"]
S --> F["Файл из закрытого<br/>хранилища"]
end
subgraph R2 [" "]
direction LR
K["Клиент:<br/>ссылка из письма"] --> T["Подписанный токен<br/>со сроком жизни"]
T --> F2["Файл — или «срок истёк»"]
end
R1 --> R2
style R1 fill:none,stroke:none
style R2 fill:none,stroke:noneСотруднику нужна рабочая сессия: без входа ссылка уводит на страницу входа. Клиенту адрес файла вообще не показывается — он получает ссылку с подписанным токеном, у которого есть срок: счёт из письма открывается год, отчёт бота — три месяца. Токен подписан ключом установки: подменить в нём адрес файла или срок нельзя, испорченная ссылка отвечает «не найдено».
Отдельная причина отдавать файл сервером, а не подписанной ссылкой на облако: у части российских операторов адрес облачного хранилища попросту не открывается. Записи разговоров мы по этой причине отдаём через сервер уже давно — теперь так же работают документы и вложения.
| Кому | Что получает | Сколько живёт |
|---|---|---|
| Сотрудник | Ссылку внутри биллинга, работает по входу | Пока есть доступ к разделу |
| Клиент — счёт или акт в письме | Ссылку с подписанным токеном | Год |
| Клиент — отчёт бота в мессенджере | Ссылку с подписанным токеном | 90 дней, как и сам отчёт |
| Кто-то со старым прямым адресом | Отказ хранилища | — |
Что переехало
Переезжали разделами: копия в закрытое хранилище, сверка каждого файла по контрольной сумме, и только потом удаление из открытого. Пути внутри хранилища сохранены, поэтому ссылки в базе переписывать не пришлось — биллинг сначала ищет файл в закрытом хранилище и лишь затем там, где тот лежал раньше.
| Что | Файлов | Объём |
|---|---|---|
| Записи разговоров по сделкам | 8091 | 3,47 ГБ |
| Записи звонков телефонии | 1024 | 481 МБ |
| Вложения обращений | 373 | 112 МБ |
| Снимки почтовых ящиков | 106 | 37,7 МБ |
| Договоры и акты документооборота | 24 | 17,3 МБ |
| Вложения сделок, отчёты ботов, фото актов брака, вложения чата | 20 | 11,9 МБ |
| Итого | 9638 | ≈4,1 ГБ |
Раньше туда же переехали ночные копии баз, банковские документы, файлы из карточек клиентов и договоры сервера лицензий. В открытом хранилище под биллингом остались только материалы, которые мы и так показываем: снимки документации, обложки, виджеты, лендинги.
Резервные копии: раздел, где это всё начинается
Копии базы — самый чувствительный из этих файлов, поэтому про раздел стоит рассказать отдельно. Он живёт в «Настройках» и выглядит так.
Верхняя строка отвечает на вопрос «всё ли в порядке» без чтения журналов: сколько занято на диске и в облаке, идут ли копии по расписанию, когда была последняя и когда будет следующая, сколько запусков за неделю прошло успешно. Если расписание нарушено или свежей копии нет в облаке, состояние перестаёт быть зелёным.
Ниже — конфигурации. Каждая описывает, что копировать, когда и сколько копий держать:
- База данных — дамп PostgreSQL, обычно ежедневно ночью;
- Файлы — документы, печати, вложения;
- База и файлы — то и другое одним набором;
- Docker-образ — самодостаточный пакет: дамп, код, конфигурация, медиа и скрипт развёртывания. Из такого пакета система поднимается на чистом сервере.
На рабочем сервере включены две: суточная база и еженедельный полный пакет. Копии старше заданного числа удаляются с диска сами.
Каждая копия — строка в журнале с датой, размером и результатом. Отсюда её можно скачать, восстановить или удалить; неудачный запуск виден сразу, а не через месяц.
flowchart TB
subgraph R1 [" "]
direction LR
SCH["Расписание:<br/>ночью по конфигурации"] --> DMP["Дамп базы<br/>и файлы"]
DMP --> ENC["Шифрование<br/>и упаковка"]
end
subgraph R2 [" "]
direction LR
DSK["Диск сервера:<br/>N последних копий"] --> CLD["Закрытое хранилище<br/>в облаке"]
CLD --> RST["Восстановление:<br/>база, файлы или всё"]
end
R1 --> R2
style R1 fill:none,stroke:none
style R2 fill:none,stroke:noneКопия сначала ложится на диск сервера, а затем уходит в облако — в то самое закрытое хранилище. Диск переживает сбой программы, облако — сбой сервера; копия в одном месте не спасает ни от того, ни от другого.
Копия, которую не разворачивали, — не копия
Файл в облаке ничего не гарантирует, пока из него хотя бы раз не подняли систему. Мы развернули одну из ночных копий на отдельной базе — и по дороге нашли то, что нельзя увидеть, глядя на размер файла: дамп, снятый новой версией PostgreSQL, не читается инструментом более старой версии. На боевом сервере версии совпадают, но при восстановлении на чужой машине это стоило бы нескольких неприятных часов. Теперь это записано в инструкции по восстановлению.
Отсюда же простое правило для эксплуатации: проверять восстановление раз в квартал и после каждого обновления базы. И держать в голове, сколько копий вы обязаны хранить — по закону о персональных данных удалять их бесконечно тоже нельзя.
Как это работает в СмИТ Биллинге
Хранилище настраивается в «Настройках» → «Интеграции» → «Облачное хранилище»: отдельно открытое — для обложек и снимков, отдельно закрытое — для копий, документов и записей. Ключ доступа хранится в настройках установки, файлы к облаку идут через него.
Резервные копии — «Настройки» → «Резервные копии»: конфигурации, расписание, сколько копий держать, выгрузка в облако, журнал запусков и восстановление. Права на раздел выдаются отдельно от остальных настроек: доступ к копиям — это доступ ко всей базе сразу.
Ссылки на документы и записи внутри системы формирует сама платформа — отдельной настройки не требуется. Файл из карточки клиента, счёт в письме, запись разговора в сделке и вложение обращения открываются как раньше, но теперь каждое открытие проходит через проверку прав.
Посмотреть на своих данных
Покажем платформу на живом стенде и разберём ваш случай. Или спросите ассистента прямо сейчас — он отвечает по документации и настройкам.


