Я являюсь частью команды, в которой мы создаем веб-приложение NextJS, и недавно мы искали варианты развертывания. Поскольку большая часть нашей инфраструктуры находится на Heroku, это был очевидный первый выбор для нас, поскольку у команды был хороший опыт работы с ним в быстром режиме, и мы хотели сосредоточиться на том, чтобы свести разработку к минимуму. Основные требования к нашему приложению заключались в том, что мы собирались использовать домены с подстановочными знаками, и нам абсолютно необходим SSL для приложения.
Если бы был один домен, Heroku довольно прост, поскольку SSL и автоматические перенаправления SSL работают из коробки. Однако для нашего варианта использования, несмотря на то, что Heroku предоставляет подстановочные SSL-сертификаты с их автоматическим управлением SSL, его получение было непомерно дорогим. Поэтому мы хотели использовать внешний сертификат для веб-сайта. Настройка внешних сертификатов на Heroku довольно проста, но, к сожалению, она не обеспечивает автоматическое перенаправление SSL. Поэтому, если пользователь попадает на страницу http
, вам придется либо прибегнуть к редиректам на стороне клиента (для этого, кстати, react-https-redirect
— один из самых простых в настройке), либо возиться с конфигурацией билдпака, чтобы включить автоматические редиректы.
Мы решили пойти по второму пути, используя nginx-buildpack
поверх пакета сборки heroku/nodejs
, который мы использовали для создания приложения NextJS. Первый шаг, добавьте пакет сборки в ваше приложение:
$ heroku buildpacks:add heroku-community/nginx
Для того, чего мы хотели достичь, нам понадобится функция «Настраиваемая конфигурация NGINX» из пакета сборки. Вот как выглядит наш config/nginx.config.erb
:
daemon off;
# Heroku dynos have at least 4 cores.
worker_processes <%= ENV['NGINX_WORKERS'] || 4 %>;
events {
use epoll;
accept_mutex on;
worker_connections <%= ENV['NGINX_WORKER_CONNECTIONS'] || 1024 %>;
}
http {
gzip on;
gzip_comp_level 2;
gzip_min_length 512;
server_tokens off;
log_format l2met 'measure#nginx.service=$request_time request_id=$http_x_request_id';
access_log <%= ENV['NGINX_ACCESS_LOG_PATH'] || 'logs/nginx/access.log' %> l2met;
error_log <%= ENV['NGINX_ERROR_LOG_PATH'] || 'logs/nginx/error.log' %>;
include mime.types;
default_type application/octet-stream;
sendfile on;
# Must read the body in 5 seconds.
client_body_timeout 5;
server {
listen <%= ENV["PORT"] %>;
server_name _;
keepalive_timeout 5;
location / {
<% if ENV['NGINX_SKIP_HTTPS_PROXY'] == 'true' %>
if ($http_x_forwarded_proto != "https") {
return 301 https://$host$request_uri;
}
<% end %>
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://localhost:3000; #next serve listens here and receives nginx requests
}
}
}
Все остальные части этой конфигурации довольно просты. Основная часть, где происходит волшебство, заключается в следующем:
location / {
<% if ENV['NGINX_SKIP_HTTPS_PROXY'] == 'true' %>
if ($http_x_forwarded_proto != "https") {
return 301 https://$host$request_uri;
}
<% end %>
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://localhost:3000; #next serve listens here and receives nginx requests
}
Это перехватывает все пути, к которым осуществляется доступ по протоколу http
, мы перенаправляем с кодом 301 на соответствующий путь по протоколу https
. Здесь все становится интереснее. Даже с протоколом https Heroku всегда перенаправляет запрос в блок http, поскольку внутри маршрутизатора Heroku (поверх) пишет заголовки запроса X-Forwarded-Proto и X-Forwarded-Port. Итак, если значение заголовка X-Forwarded-Proto
, мы не должны перенаправлять и вместо этого настраивать reverse-proxy
для нашего развернутого приложения.
Первоначально опубликовано на https://pulkitgoyal.in.