Я являюсь частью команды, в которой мы создаем веб-приложение 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.