Не бывает «просто перенести на VPS»
Перенос сайта на VPS звучит как задача на полдня. Почему дешёвый код, старые системы и реальная инфраструктура делают её заметно сложнее.
- Автор
- Sky
- Опубликовано
- 5 минут чтения
- web · infrastructure · devops
В этой заметке
«Просто перенеси на VPS» звучит как задача на полдня. Берёшь старый сайт, переписываешь то, что нужно переписать, копируешь данные, направляешь домен на новый сервер — готово. Сейчас это кажется даже проще, чем звучит: обычно у меня есть референсный проект с той же архитектурой, frontend-стек, которому я доверяю, конфиги деплоя, которые я уже однажды отладил, и AI-агент, который с радостью напишет половину кода.
В этом году я сделал две такие миграции подряд. Ни одна не заняла полдня.
Код подешевел
Это самое смешное. С нормальным референсным проектом и агентом пересобрать клиентский сайт получается до абсурда быстро по сравнению с тем, что было несколько лет назад. Компоненты, однотипные шаблоны, адаптеры, чистка API, перевод старых паттернов на современный стек — большая часть этого превращается в ревью диффов. На одном из проектов я в первый же день прошёл путь от написанной спецификации до схемы базы, импортёра и первых парсеров. В такой момент трудно не подумать, что к выходным всё будет готово.
А потом ты деплоишь.
Приложение — только одна часть сайта
Production-сайт — это не папка с кодом. Это DNS, сертификаты, редиректы, почтовые записи, кеши, reverse proxy, базы данных, права на файлы, старые URL, на которые поисковики всё ещё отправляют людей, забытые поддомены, cron-задачи, аналитика, представления хостинг-панели о конфигурации, а иногда и софт, который годами никто не трогает, потому что все его боятся. Ничего из этого не исчезает оттого, что новое приложение чище, и у всего этого есть мнение о твоём деплое.
Вот как это выглядело на практике:
- Сайт идеально работал в разработке и уходил в бесконечный редирект в production-сборке, причём только на корневом URL языка по умолчанию.
- nginx запомнил IP контейнера и после перезапуска продолжал отправлять трафик в контейнер, которого больше не существовало. Привет, 502.
- Запросы авторизованных пользователей в админку молча отбрасывались, потому что auth-куки не помещались в стандартные буферы заголовков nginx.
- Пул подключений к базе на 100 соединений в каждом контейнере, умноженный на четыре контейнера, при лимите базы в 200 подключений. Всё было нормально ровно до того момента, как редакторы начали работать.
- Production-образ Docker собирался без единой жалобы, а потом падал на каждой странице админки, потому что файлы переводов так и не попали в образ.
Ничего из этого не сложно починить. Всё это невозможно увидеть с localhost.
У старых систем есть история
Legacy-системы редко бывают сложными специально. Они усложняются, потому что что-то происходило: переехал домен, кто-то пять лет назад добавил редирект, другой разработчик перестроил структуру каталогов, плагин тихо зависел от чего-то недокументированного, временный костыль стал постоянным, а хостинг-панель сгенерировала конфигурацию, которую никто не помнит, как писал. После всего этого ты уже не столько заменяешь код, сколько восстанавливаешь годы накопленных допущений.
Мой любимый пример: один из старых сайтов хранил каждую языковую версию страницы отдельной записью, слабо связанной с остальными. Объединить их в одну запись на страницу было правильным решением — и заодно оно тихо сломало около пятидесяти URL на одном из языков. Заметил я это только потому, что перед переключением прогнал каждый старый URL через новое приложение.
Инфраструктуре всё равно, какой у тебя фреймворк
Next.js всё равно, что на твоём VPS почти нет памяти. Docker всё равно, что сеть между сервером и registry нестабильна. Твоему CI всё равно, что production живёт за каким-то специфичным ограничением провайдера. А пользователям уж точно всё равно, что деплой упал, потому что не удалось скачать образ. Им важно, что сайт лежит.
Насколько я могу судить, большая часть production-инженерии — это выяснение того, сколько допущений твоя среда разработки молча делала за тебя.
Референсный код и AI сокращают известную работу
Иметь проект с той же архитектурой — отлично. Как и AI-агентов, переиспользуемые Dockerfile, общие компоненты, тесты и инфраструктуру, которую ты уже понимаешь. Вместе они превращают дни написания кода в часы. Но сокращают они известную работу, а дорогая часть миграции — неизвестная: куда на самом деле указывает этот домен, зачем существует этот редирект, какие старые URL всё ещё получают трафик, что сломается, если это выключить, откуда на самом деле берётся настройка и почему что-то работает на одном сервере, но не на другом.
Агент по-настоящему помогает во всём этом разбираться. Он просто не может сделать так, чтобы эти вопросы перестали существовать.
Вайб-кодинг всё равно встречается с реальностью
Большую часть миграции можно навайбкодить, и я так и делаю. Даёшь агенту референсную реализацию, описываешь нужный результат, смотришь, что вернулось, тестируешь, повторяешь — и абсурдное количество работы над приложением просто исчезает. Но последние 20% — это место, где всё перестаёт быть абстрактным. Есть реальный сервер, реальная сеть, реальные исторические данные, реальные пользователи и обычно одна невероятно глупая вещь, которую никто не мог предсказать.
Лучшая защита, которую я нашёл, скучная. Сделать дампы баз и пометить образы для отката до того, как что-то трогать, поднять новый стек рядом со старым на других портах, проверить его там — и только потом переключать. На одном из проектов благодаря этому всё переключение уложилось в одну ночь, а старые контейнеры всё это время стояли рядом на случай, если понадобятся.
Так что да, переноси на VPS
Только не называй это просто переносом на VPS. Новый код вполне может оказаться самой лёгкой частью. Настоящая работа — понять всё вокруг него настолько хорошо, чтобы, когда ты заменяешь одну деталь, остальная система этого не заметила. Пока что никакие AI, автоматизация, переиспользуемая инфраструктура и агрессивный вайб-кодинг этого не изменили.