Пошук уроків, статей та іншого контенту
Налаштуєте Nginx як reverse proxy перед Next.js, домен, HTTPS і проксіювання запитів.
Reverse proxy — це сервер, який приймає запити від клієнтів і передає їх внутрішньому застосунку.
У нашому випадку схема буде такою:
Користувач
↓ HTTPS
Nginx :443
↓ HTTP
Next.js :3000Користувач не звертається безпосередньо до порту 3000. Nginx:
приймає запити на домені;
завершує HTTPS-з’єднання;
передає запити до Next.js;
повертає відповіді клієнту;
може перенаправляти HTTP на HTTPS.
Next.js працюватиме лише на локальному порту сервера, тому порт
3000На сервері застосунок можна запустити в production-режимі:
npm ci
npm run build
npm run startУ package.json мають бути відповідні scripts:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}За замовчуванням next start запускає сервер на порту 3000.
Перевірити застосунок локально на сервері можна так:
curl http://127.0.0.1:3000Якщо застосунок потрібно запустити на іншому порту, використовуйте змінну PORT:
PORT=3000 npm run startВажливо, щоб Next.js був доступний локально, а не лише через development-команду next dev.
Для production-застосунку не варто залишати процес запущеним у відкритій SSH-сесії. Зручно створити systemd-сервіс.
Припустімо, застосунок розташований у каталозі /var/www/my-next-app, а запускати його потрібно від користувача deploy.
Створіть файл /etc/systemd/system/my-next-app.service:
[Unit]
Description=Next.js application
After=network.target
[Service]
Type=simple
User=deploy
WorkingDirectory=/var/www/my-next-app
Environment=NODE_ENV=production
Environment=PORT=3000
ExecStart=/usr/bin/npm run start
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.targetШлях до npm може відрізнятися залежно від способу встановлення Node.js. Перевірити його можна командою:
which npmПісля створення сервісу виконайте:
sudo systemctl daemon-reload
sudo systemctl enable my-next-app
sudo systemctl start my-next-appПеревірка статусу:
sudo systemctl status my-next-appПерегляд журналу:
sudo journalctl -u my-next-app -fНа Ubuntu або Debian Nginx можна встановити так:
sudo apt update
sudo apt install nginxПеревірте, що сервіс запущений:
sudo systemctl status nginxNginx зазвичай використовує:
80 — HTTP;
443 — HTTPS.
Переконайтеся, що DNS-запис домену вказує на IP-адресу сервера. Наприклад:
example.com A 203.0.113.10
www.example.com A 203.0.113.10Замість example.com і 203.0.113.10 потрібно використовувати власні значення.
Створіть конфігурацію сайту:
sudo nano /etc/nginx/sites-available/my-next-appПочаткова конфігурація без HTTPS:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Основні директиви:
listen 80 — Nginx приймає HTTP-запити;
server_name — домени, для яких застосовується конфігурація;
proxy_pass — адреса Next.js;
Host — оригінальний домен запиту;
X-Real-IP — IP-адреса клієнта;
X-Forwarded-For — ланцюжок проксі та IP клієнта;
X-Forwarded-Proto — початковий протокол, наприклад http або https.
Активуйте конфігурацію:
sudo ln -s /etc/nginx/sites-available/my-next-app \
/etc/nginx/sites-enabled/my-next-appЯкщо стандартний сайт Nginx більше не потрібен, його можна вимкнути:
sudo rm /etc/nginx/sites-enabled/defaultПеревірте синтаксис:
sudo nginx -tЗастосуйте зміни:
sudo systemctl reload nginxТепер запит до http://example.com має пройти через Nginx до Next.js на 127.0.0.1:3000.
Nginx за замовчуванням не передає всі характеристики початкового з’єднання до Next.js. Тому в конфігурації явно задають заголовки:
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;Це важливо, коли застосунок:
формує абсолютні URL;
визначає, чи був запит HTTPS;
записує IP-адресу клієнта в журнали;
працює з редиректами або cookies.
Не слід передавати клієнтський заголовок Host безпосередньо через $http_host, якщо немає потреби в порту. Для більшості конфігурацій достатньо $host.
Для HTTPS потрібен TLS-сертифікат. Практичний варіант для домену — використати Certbot і Let’s Encrypt.
Встановлення Certbot з плагіном для Nginx:
sudo apt update
sudo apt install certbot python3-certbot-nginxПереконайтеся, що:
домен уже вказує на цей сервер;
порт 80 доступний з інтернету;
Nginx має коректну HTTP-конфігурацію;
сайт відповідає через домен.
Запустіть отримання сертифіката:
sudo certbot --nginx -d example.com -d www.example.comCertbot перевірить домен і може автоматично додати HTTPS-конфігурацію та перенаправлення з HTTP.
Перевірити автоматичне поновлення сертифіката:
sudo certbot renew --dry-runСертифікати мають обмежений строк дії, тому автоматичне поновлення є обов’язковим для production-сервера.
Після отримання сертифіката конфігурація може мати такий вигляд:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Перший блок перенаправляє всі HTTP-запити на HTTPS:
http://example.com/page
↓
https://example.com/pageЗмінна $request_uri зберігає шлях і query-параметри, тому вони не втрачаються під час редиректу.
Наприклад:
http://example.com/products?page=2перетвориться на:
https://example.com/products?page=2Після зміни конфігурації:
sudo nginx -t
sudo systemctl reload nginxУ production-застосунку Next.js зазвичай достатньо стандартного HTTP-проксіювання. Проте для коректної роботи протоколів, які використовують upgrade-з’єднання, можна додати відповідні заголовки.
У файлі /etc/nginx/nginx.conf, усередині блоку http, додайте:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}Наприклад:
http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# Інші налаштування Nginx
}У server-блоці для Next.js додайте:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}Після цього знову перевірте конфігурацію:
sudo nginx -t
sudo systemctl reload nginxДеякі сторінки Next.js можуть генеруватися довше за стандартний час очікування Nginx. Для таких застосунків можна збільшити тайм-аут:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}Не варто без потреби встановлювати дуже великі значення. Великий тайм-аут може довго утримувати з’єднання, якщо Next.js завис або перевантажений.
Перевіряйте компоненти послідовно.
curl -I http://127.0.0.1:3000Якщо відповіді немає, проблема ще не пов’язана з Nginx.
sudo nginx -tcurl -I http://example.comОчікувано можна отримати редирект:
HTTP/1.1 301 Moved Permanently
Location: https://example.com/curl -I https://example.comОчікувано сервер має повернути відповідь від Next.js, наприклад 200, 301, 302 або інший коректний для маршруту статус.
Журнал Nginx:
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.logЖурнал Next.js:
sudo journalctl -u my-next-app -fЗа журналами можна визначити, де виникла проблема:
запит не потрапляє в Nginx;
Nginx не може під’єднатися до порту 3000;
помилка виникає всередині Next.js;
некоректно налаштований TLS або домен.
Після налаштування домену та сертифіката підсумкова конфігурація може виглядати так:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}Після збереження:
sudo nginx -t
sudo systemctl reload nginxЯкщо curl http://127.0.0.1:3000 не повертає відповідь, Nginx покаже помилку 502 Bad Gateway.
Перевірте:
sudo systemctl status my-next-app
sudo journalctl -u my-next-app -n 100Якщо Next.js запущений на порту 3001, а в Nginx указано 3000, проксіювання не працюватиме.
Адреса в proxy_pass і значення PORT мають збігатися:
proxy_pass http://127.0.0.1:3000;Environment=PORT=3000Ніколи не застосовуйте зміни без перевірки:
sudo nginx -tЯкщо синтаксис неправильний, nginx -t покаже файл і номер рядка з помилкою.
Сертифікат має бути виданий для домену, який указано в server_name. Наприклад, сертифікат лише для example.com не обов’язково покриває www.example.com.
Для доступу з інтернету сервер має приймати з’єднання на портах 80 і 443. Якщо використовується firewall, ці порти потрібно дозволити.
Якщо порт 3000 відкритий у firewall або застосунок слухає всі мережеві інтерфейси, користувачі можуть обходити Nginx.
Для схеми з reverse proxy достатньо локальної адреси:
127.0.0.1:3000а не публічної адреси сервера.
Next.js запускається в production-режимі на локальному порту, наприклад 127.0.0.1:3000.
Nginx приймає запити від клієнтів і передає їх до Next.js через proxy_pass.
Заголовки Host, X-Real-IP, X-Forwarded-For і X-Forwarded-Proto зберігають інформацію про початковий запит.
HTTP перенаправляється на HTTPS.
TLS-сертифікат можна отримати й автоматично поновлювати за допомогою Certbot.
Після кожної зміни конфігурацію потрібно перевіряти командою nginx -t.
У production Next.js і Nginx зручно запускати як systemd-сервіси.