Задеплоить Next.js-приложение легко. Задеплоить его безопасно — вот этот шаг обычно и пропускают, особенно когда бóльшую часть кода сгенерировали за вас. Это практический чеклист перед деплоем: десять вещей, которые реально ломаются в Next.js-приложениях, почему каждая из них важна и быстрая команда для проверки.
Идите сверху вниз. К каждому пункту есть ссылка на полный гайд, если нужны детали.
1. Отключите source maps в продакшене
Source maps восстанавливают ваш минифицированный бандл обратно в исходные .tsx-файлы. Если они доступны публично, любой может прочитать ваш код прямо в DevTools — включая комментарии, внутреннюю логику и то самое место, где вы захардкодили что не следовало.
curl -I https://yoursite.com/_next/static/chunks/main.js.map
# Должно вернуть 404, а не 200
Полный фикс: /guides/source-maps-production
2. Уберите API-ключи из бандла
Всё, что попадает в браузер, доступно всем. Секретный ключ Stripe, ключ OpenAI или строка подключения к БД во фронтенд-бандле — это уже утечка, и единственный фикс — ротация ключа.
# Поищите в собранном бандле распространённые префиксы ключей
grep -rE "sk_live_|AIza|ghp_|xoxb-" .next/static
# Не должно ничего найтись
Полный фикс: /guides/api-key-leaks
3. Добавьте security headers (CSP, HSTS, …)
По умолчанию Next.js не отдаёт ни Content-Security-Policy, ни HSTS, ни X-Frame-Options. Это оставляет вас открытыми для XSS, clickjacking и понижения протокола. Добавьте их один раз в next.config.js.
// next.config.js
const securityHeaders = [
{ key: "X-Frame-Options", value: "DENY" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "Strict-Transport-Security", value: "max-age=63072000; includeSubDomains; preload" },
]
module.exports = {
async headers() {
return [{ source: "/:path*", headers: securityHeaders }]
},
}
Полный фикс: /guides/security-headers
4. Проверьте настройку TLS/SSL
Если вы на Vercel или Netlify — это сделано за вас. На своём сервере или прокси убедитесь, что у вас TLS 1.2+, валидный неистекающий сертификат и совпадающий домен.
echo | openssl s_client -connect yoursite.com:443 -servername yoursite.com 2>/dev/null | openssl x509 -noout -dates
Полный фикс: /guides/tls-ssl
5. Не выносите секреты в NEXT_PUBLIC_
Префикс NEXT_PUBLIC_ — это не мера безопасности, а наоборот. Он говорит Next.js встроить значение в клиентский бандл. Кладите туда только то, что не жалко напечатать на билборде (публичный publishable-ключ, публичный ID аналитики).
| Переменная | Куда попадает | Можно секрет? |
|---|---|---|
DATABASE_URL | Только сервер | ✅ остаётся приватной |
NEXT_PUBLIC_API_URL | Встраивается в браузер | ❌ публичная, никогда не секрет |
Правило: если переменная с префиксом NEXT_PUBLIC_, считайте, что её прочитает весь мир.
6. Защитите server actions и route handlers
Server Actions и route handlers в app/api/* выполняются на сервере, но это всё равно публичные HTTP-эндпоинты. Их может вызвать кто угодно напрямую — не только ваш интерфейс. Проверяйте аутентификацию и права внутри экшена, не полагайтесь на то, что кнопка спрятана.
"use server"
export async function deleteAccount(id: string) {
const session = await auth()
if (!session) throw new Error("Unauthorized")
if (session.userId !== id) throw new Error("Forbidden")
// ... только теперь выполняем работу
}
7. Валидируйте env-переменные на этапе сборки
Пропущенная или опечатанная env-переменная не должна падать в продакшене в самый неподходящий момент. Валидируйте весь набор при старте, чтобы сборка падала сразу.
// env.ts
import { z } from "zod"
export const env = z
.object({
DATABASE_URL: z.string().url(),
STRIPE_SECRET_KEY: z.string().startsWith("sk_"),
})
.parse(process.env)
Импортируйте env вместо чтения process.env напрямую — и плохой конфиг никогда не дойдёт до пользователей.
8. Закройте CORS
Если вы открываете API для других источников, не отражайте каждый Origin обратно с Access-Control-Allow-Origin: *, одновременно разрешая credentials — эта комбинация сливает аутентифицированные ответы любому сайту. Разрешайте явный список источников.
const allowed = ["https://yourapp.com"]
const origin = req.headers.get("origin")
if (origin && allowed.includes(origin)) {
res.headers.set("Access-Control-Allow-Origin", origin)
}
9. Базовый SEO и мета-теги
Безопасность готова — не задеплойтесь невидимыми. Каждой странице нужны уникальный <title>, <meta name="description">, один <h1>, Open Graph-теги и canonical URL. Next.js делает это декларативно через экспорт metadata.
export const metadata = {
title: "My Page",
description: "Понятное описание на 120–160 символов.",
alternates: { canonical: "https://yourapp.com/page" },
openGraph: { title: "My Page", images: ["/og.png"] },
}
Полный фикс: /guides/seo-meta-tags
10. Просканируйте перед деплоем
Чеклисты легко не доделать. Самый быстрый способ убедиться, что вы реально закрыли все дыры, — просканировать задеплоенный URL и прочитать отчёт.
Вставьте свой продакшен-URL в vibeblame — он проверит source maps, утечки ключей, заголовки, TLS и SEO примерно за 30 секунд и выдаст готовый AI-промпт для фикса всего найденного.