Представьте приложение, которое «переехало». Новый сервер отвечает, главная страница открывается, в панели админки всё зелёное. А потом пользователь загружает аватар, и файл молча уходит в бакет, который остался в старом аккаунте AWS. Письмо с подтверждением отправляется через почтовый сервис, который по-прежнему доверяет только старому IP. База данных на новом сервере есть, но приложение, как выяснилось, смотрит в переменную окружения с адресом прежней. Формально машина перенесена. Фактически новый сервер стал красивым фасадом перед старой инфраструктурой.
Эта статья про то, как не попасть в такую ситуацию. Главный вопрос: какие зависимости остаются за пределами образа Lightsail? Ответ почти всегда длиннее, чем ожидаешь, и начинать лучше не с команд, а с наблюдения за тем, что приложение делает на самом деле.
Три действия пользователя и всё, что за ними стоит
Самый честный способ найти зависимости — не открывать консоль AWS, а пройти путь пользователя и записать, куда обращается приложение на каждом шаге. Возьмём условное веб-приложение: Linux-сервер на Lightsail, Nginx, приложение в Docker Compose, PostgreSQL, загрузка пользовательских файлов, письма с подтверждением. Три действия: открыть страницу, загрузить файл, получить письмо.
Открытие страницы. Браузер сначала спрашивает DNS: где живёт домен. Запись указывает на статический IP Lightsail. Дальше TLS-сертификат (где он выпущен и кто его продлевает?), затем Nginx, затем приложение, затем база. Если страница отдаёт картинки и скрипты с отдельного домена или CDN, добавляется ещё одно звено. Уже здесь видно, что «сервер» — только середина цепочки: до него есть DNS и сертификат, после него — база и, возможно, кэш.
Загрузка файла. Приложение принимает файл и кладёт его либо на локальный диск, либо в object storage. Если в S3-совместимое хранилище, то в конфигурации лежит имя бакета, регион и ключи доступа или привязанная роль. Всё это не живёт в образе системного диска как «данные приложения»: бакет существует сам по себе, в аккаунте, со своей политикой доступа.
Отправка письма. Приложение обращается к SMTP или API почтового сервиса. Там свои учётные данные, подтверждённый домен отправителя, записи SPF и DKIM в DNS и, нередко, ограничения по адресам, с которых разрешено отправлять. Новый IP сервера почтовый провайдер может не знать вовсе.
После этого упражнения у вас на листе получается не «один сервер», а карта.
Карта зависимостей условного приложения
Вот как может выглядеть такая карта для описанного приложения. Названия условные, у вас будут свои.
| Что | Где живёт сейчас | Попадает ли в образ машины | Что делать при переезде |
|---|---|---|---|
| Код и конфигурация приложения | Каталог на системном диске, Compose-файл | Да | Перенести файлы или пересобрать из репозитория |
| Nginx, системные пакеты | Системный диск | Да, но версии нужно сверить | Установить заново, перенести конфиги |
| Данные PostgreSQL | Контейнер или пакет на машине либо отдельная управляемая база | Зависит от варианта | Отдельный дамп, проверка версии |
| Роли базы | Кластер PostgreSQL | Только если живёт на диске этой машины | Перенести отдельно от дампа одной базы |
| Пользовательские файлы | Bucket в object storage | Нет | Решить: оставить, скопировать или сменить хранилище |
| DNS-зона | Сервис DNS у регистратора или в облаке | Нет | Понизить TTL, изменить записи |
| Почтовый сервис | Внешний провайдер | Нет | Проверить доверенные адреса, SPF, DKIM |
| Секреты и ключи доступа | Переменные окружения, файлы, роли | Частично | Инвентаризация, ротация |
| Сертификаты TLS | Каталог на диске или у внешнего сервиса | Частично | Выпустить заново или перенести |
Обратите внимание на колонку про образ машины. Она вскрывает типичную иллюзию: кажется, что если снять «слепок» сервера, то в нём окажется всё. Но слепок содержит то, что физически лежит на дисках этого сервера. Бакет, DNS-зона и аккаунт почтового провайдера лежат в другом месте.
Что такое экспорт Lightsail и чем он не является
Теперь про сам экспорт. В документации AWS CLI операция export-snapshot описана как перенос snapshot Lightsail в Amazon EC2: снимок инстанса превращается в AMI и EBS, снимок диска — в EBS-том. Экспорт происходит в тот же регион AWS, где находится исходный snapshot.
Из этого следует важный вывод, который легко пропустить. Экспорт — это способ выйти из Lightsail в соседний сервис того же провайдера, а не способ получить файл образа, который можно загрузить на любую другую площадку. Подтверждения, что полученный AMI или EBS можно импортировать на VPS MAATRIX, у нас нет, и закладывать такой путь в план не стоит. Если кто-то обещает «просто загрузить образ из Lightsail», проверьте это на практике до того, как от этого зависит график работ.
Что остаётся? Перенос на уровне приложения: новый чистый Linux-сервер, на котором вы воспроизводите среду, а данные приезжают отдельными, понятными артефактами. Это дольше, чем нажать кнопку, зато вы точно знаете, что на новой машине стоит, и не тащите за собой накопившийся мусор: забытые пакеты, старые cron-задачи, ручные правки в системных файлах.
У такого подхода есть побочное достоинство. Когда вы вынуждены описать окружение руками, становится видно, чего вы о нём не знали. Каждая найденная «странность» — это зависимость, которая иначе проявилась бы уже в продакшене.
Диск, база и хранилище: три разных вопроса
Системный диск, база данных и object storage ведут себя по-разному, и смешивать их в одну задачу «скопировать данные» опасно.
Системный диск: переносим решения, а не байты
На системном диске лежит то, что можно воспроизвести: пакеты, конфиги Nginx, Compose-файлы, юнит-файлы systemd, задания cron. Правильный вопрос здесь не «как скопировать диск», а «что из этого мы не смогли бы восстановить по записям». Код обычно живёт в репозитории. Конфигурация — не всегда: правки, которые кто-то внёс на сервере руками, существуют только там. Их нужно извлечь и положить под версионный контроль до переезда.
Если приложение запускается через Compose, то у вас есть удобная точка опоры. В документации Docker Compose для production-режима сказано, что одну конфигурацию можно использовать в разных средах с отличающимися настройками, а в production может понадобиться убрать bind mount кода, поменять порты и окружение и добавить restart policy. Для переезда это означает: сделайте отдельный файл переопределений для нового сервера. Адреса бакета, базы и почтового провайдера пусть меняются там, а не правкой основного файла. Тогда при откате вы возвращаете одну переменную, а не вспоминаете, что и где исправляли.
Ещё одна деталь из той же документации пригодится при репетициях: обновление кода внутри образа требует пересборки образа и пересоздания контейнера, но отдельный сервис можно обновить, не трогая зависимости. Значит, во время репетиции можно менять приложение, не пересоздавая контейнер базы, и не рисковать данными.
База данных: отдельный артефакт со своими правилами
С PostgreSQL важно помнить три вещи, и все они следуют из описания pg_dump.
Первое: pg_dump делает согласованный экспорт одной базы, даже если в это время идут чтения и записи. Это удобно, потому что останавливать приложение на время снятия дампа не обязательно. Но согласованность означает состояние на момент начала дампа. Всё, что записано позже, в дамп не попадёт, поэтому для финального переключения нужен момент, когда запись прекращена.
Второе: роли и tablespaces — глобальные объекты — в дамп одной базы не входят, для них предназначен pg_dumpall. Типичная ошибка: восстановили базу, а приложение не может подключиться, потому что роль, под которой оно работало, на новом сервере не существует, либо существует без нужных прав. Список ролей и их привилегий стоит выписать заранее.
Третье: версии. pg_dump не работает с сервером более новой major-версии, чем сам инструмент, а восстановление в более старый сервер не гарантируется. На практике это правило такое: на новом сервере ставьте ту же или более новую major-версию PostgreSQL, чем была, и делайте дамп клиентом, не старше сервера-источника. Понижать версию при переезде не стоит.
Формат дампа определяет способ восстановления: архивные форматы разворачиваются через pg_restore, обычный SQL — через psql. Выбор лучше сделать сознательно. Архивный формат даёт больше контроля при восстановлении, обычный SQL проще просмотреть глазами.
Базовая последовательность для базы, работающей на самом сервере, может выглядеть так (имена условные):
pg_dump -Fc -f app.dump appdb
pg_dumpall --globals-only -f globals.sql
# на новом сервере:
psql -f globals.sql
createdb appdb
pg_restore -d appdb app.dumpЕсли база у вас не на сервере, а отдельный управляемый сервис, то она вообще не входит в системный образ, и вопрос переезда базы превращается в самостоятельный проект: нужно решить, остаётся ли она там или переезжает, и в первом случае — разрешит ли она подключения с нового адреса.
Object storage: самое незаметное
Бакет не содержится ни в каком образе сервера. Пока приложение ходит в него по старым ключам, оно будет работать, и именно поэтому зависимость так легко не заметить. У вас три честных варианта.
- Оставить хранилище на месте. Быстро и безопасно для данных, но вы продолжаете зависеть от прежнего аккаунта, платить за него и отдавать трафик наружу с каждого запроса. Это не полный переезд, а временная или осознанная гибридная схема.
- Скопировать файлы на новое хранилище. Приложение получает новые адреса и ключи. Нужно решить, как быть со ссылками на файлы, уже сохранёнными в базе: если там лежат полные URL старого бакета, после копирования их придётся пересчитать или переписать.
- Перейти на локальное хранение на VPS. Проще в схеме, но размер данных становится вопросом диска. Тарифы MAATRIX различаются объёмом NVMe (от 40 ГБ у Ba до 320 ГБ у Djed), и сравнивать с ними нужно реальный объём файлов плюс запас, а не руководствоваться только числами из таблицы.
Какой бы вариант вы ни выбрали, проверьте, как приложение хранит ссылки: ключ объекта или полный адрес. От этого зависит, будет ли переезд хранилища невидимым для пользователей.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации Россия, США, Франция и Великобритания. Оплата картой РФ и по СБП.
DNS: общий выключатель всего переезда
DNS отличается от остального тем, что именно он решает, куда придёт пользователь. Поэтому запись нужно рассматривать как инструмент переключения и отката, а не как последний шаг «после переезда».
Практическая схема такая. За несколько дней до переключения понизьте TTL записей, которые будете менять, чтобы кэши по всему миру успели обновиться быстрее. На репетиции проверьте новый сервер, не меняя публичный DNS: либо через локальную запись в файле hosts на своей машине, либо через отдельное тестовое имя. Для переключения измените запись на адрес нового сервера. Для отката — верните прежний адрес. Именно поэтому старый сервер нельзя удалять сразу: пока он жив и содержит актуальные данные, откат — это одна правка записи.
Здесь же всплывают забытые записи. Помимо A и AAAA в зоне могут быть MX для почты, TXT с SPF и DKIM, записи верификации сторонних сервисов, CNAME для поддоменов. Если вы переносите только запись основного домена, остальное продолжит работать по-старому, но если вы переносите всю зону на новый DNS-хостинг, пропущенная запись — это тихо отвалившийся сервис.
Запросите полную выгрузку зоны и сверьте её с картой зависимостей: у каждой записи должен быть владелец и причина существования.
Права и сетевые разрешения: почему «всё настроено», а не работает
Теперь самое коварное. Есть группа зависимостей, которые не лежат ни на диске, ни в базе, а существуют как разрешения: кто имеет право куда обращаться.
В AWS обращения между сервисами нередко держатся на ролях и политиках: сервер получает права на чтение и запись в бакет не через явно записанный пароль, а через принадлежность к аккаунту и привязанные разрешения. На новой площадке такой неявной привилегии нет. Приложение, которое раньше «просто работало», теперь не найдёт учётных данных, и ошибка будет выглядеть как отказ в доступе к хранилищу. Решение — выдать явные ключи с минимально необходимыми правами, а не копировать старые ключи с широкими привилегиями.
Вторая группа — сетевые списки разрешённых адресов. Управляемая база, почтовый провайдер, платёжный шлюз, внешний API партнёра — любой из них может принимать запросы только с известных IP. Новый сервер получит новый адрес, и до тех пор пока вы его не добавите в разрешённые, запросы будут отклоняться или молча таймаутиться. Важно: наличие самого адреса не означает, что внешний сервис станет доступен из выбранной локации. Доступность стороннего API с нового IP нужно проверить запросом именно с нового сервера, а не предполагать.
Третья группа — секреты. Ключи API, токены, пароли баз часто разбросаны: что-то в переменных окружения Compose, что-то в файле на диске, что-то в панели хостинга. При переезде это шанс навести порядок: составить список всех секретов, выяснить, где каждый используется, и по возможности выпустить новые для нового сервера, а старые отозвать после переключения. Так вы заодно закрываете ситуацию, когда ключ от прежней инфраструктуры продолжает жить в забытом файле.
Практическая проверка здесь одна: запустите приложение на новом сервере и пройдите по каждому внешнему адресу из карты. Для каждого ответьте на вопрос «кто меня пускает и по какому признаку». Если ответ «по IP», внесите новый адрес. Если «по роли», создайте явный доступ. Если «по ключу», решите, переносить его или выпустить новый.
Репетиция с адресами новой площадки
Пока все обращения идут на старые адреса, вы не узнаете, какие из них вы пропустили. Поэтому репетиция должна быть устроена так, чтобы новый сервер использовал только то, что вы осознанно подключили.
Разверните VPS MAATRIX с root-доступом, установите окружение и поднимите приложение с переопределённой конфигурацией. Публичные материалы описывают VPS на NVMe с процессорами AMD EPYC, локации UK, US, RU и FR, оплату картой РФ и через СБП и автоматическое создание сервера после оплаты. Для репетиции важно другое: выбирайте локацию с учётом того, откуда обращаются ваши пользователи и куда ходит приложение. Точные ОС и наличие в выбранной локации уточняйте в форме заказа, одинаковую доступность везде предполагать нельзя.
С размером тарифа действуйте осторожно. Ресурсы из каталога — Ba с 1 vCPU и 2 ГБ RAM, Uab с 2 vCPU и 4 ГБ, Heka с 4 vCPU и 8 ГБ и так далее — это ориентир для сравнения с вашей текущей нагрузкой, а не обещание ёмкости. Посмотрите, сколько памяти реально занимают процессы на Lightsail под обычной нагрузкой, и добавьте запас на базу и пики. Если приложение и PostgreSQL живут на одной машине, считать нужно их сумму.
Затем пройдите тот же сценарий из трёх действий, с которого мы начали, но уже с наблюдением за сетью:
- Откройте страницу через тестовое имя или запись в hosts. Убедитесь, что TLS работает и что в ответе нет ссылок на старый адрес.
- Загрузите файл. Проверьте, в каком хранилище он появился, и откройте его по сохранённой ссылке. Посмотрите в базе, какой адрес записан.
- Запустите отправку письма. Проверьте, дошло ли оно, и откройте заголовки: проходят ли SPF и DKIM с нового адреса.
Хорошая защита от самообмана — на время репетиции закрыть исходящий доступ с нового сервера к старым адресам, если это технически просто, либо сравнить журналы: ни одного обращения к старым хостам быть не должно, кроме заведомо оставленных по решению.
Ещё одна репетиция касается базы: восстановите свежий дамп на новом сервере, подключите приложение и убедитесь, что оно видит роли и права. Засеките время дампа и восстановления — оно определяет, сколько продлится окно, когда записи нужно остановить при финальном переключении.
Когда переключаться и когда возвращаться
Критерии стоит записать до начала, а не придумывать в момент волнения.
Переключать можно, когда выполнено всё из списка: три действия пользователя проходят на новом сервере; восстановление базы из свежего дампа проверено, время известно; все внешние обращения из карты либо подтверждены, либо оставлены сознательно; TTL понижен; старый сервер остаётся нетронутым.
Финальное переключение выглядит так: остановить запись в приложении, снять последний дамп, восстановить на новом сервере, изменить DNS, пройти те же три действия уже по публичному адресу. Если дамп из-за PostgreSQL согласован на момент начала, то окно остановки записи должно покрывать всё время от начала дампа до смены записи.
Критерии возврата тоже должны быть конкретными: не открывается страница, ошибка загрузки файлов, письма не уходят, ошибки подключения к базе. Откат — возврат DNS-записи на прежний адрес. Но здесь есть тонкость: если за время работы на новом сервере пользователи успели создать данные, то простой возврат записи их потеряет. Поэтому решение об откате нужно принимать в первые минуты, пока расхождение невелико, а дальше — перекладывать данные уже осознанно.
Не удаляйте старый сервер, бакет и ключи, пока не пройдёт срок, достаточный, чтобы проявились редкие сценарии: ежемесячные отчёты, ночные задания, письма, которые отправляются раз в неделю. Зависимость, которая срабатывает раз в месяц, найдётся только через месяц, если вы её не записали.
Если нужен общий взгляд на перенос с AWS без привязки к Lightsail, он собран в материале как перенести сайт и сервер с AWS на свой VPS.
Машина и экосистема: два разных переезда
Теперь можно сформулировать различие, ради которого всё затевалось. Перенос машины — это воспроизведение на новом VPS системы, пакетов, конфигурации и данных, которые физически лежали на дисках Lightsail. Он конечен и проверяем: вы знаете, что где стояло, и можете это сравнить.
Выход из экосистемы — другая задача. Он включает всё, что с машиной связано только договорённостями: бакеты, роли и политики, списки разрешённых адресов, DNS-зону, почтовые домены, ключи и сертификаты. Эти вещи не приедут вместе с сервером, и приложение продолжит их использовать, пока вы явно не скажете ему иначе.
Поэтому честный ответ на вопрос «переехали ли мы» звучит так: если новый сервер обслуживает пользователей, но запросы всё ещё идут в старые сервисы, вы перенесли машину и сохранили зависимость. Это допустимое состояние, часто даже разумное как промежуточный шаг. Плохо другое — не знать, что оно именно такое. Карта зависимостей и репетиция нужны, чтобы каждое «оставили» было решением, а не забытой строкой в конфиге.