Простая конфигурация Nginx для SPA приложения без SSR

Билд SPA приложения без SSR, в нашем случае это Vite.js + React, представляет собой набор статических файлов, с отдачей которых справится базовая настройка Nginx с минимальными изменениями.

В нашем случае мы используем Webmin/Virtualmin для настройки, но это не особо влияет на саму конфигурацию.

Для запуска SPA приложения на базовой конфигурации Nginx сервера, нам не хватает нескольких моментов:

  1. Переадресация всех путей на наш рут, /index.html в данном случае;
  2. Зарезервированный путь для получения/обновления SSL сертификатов.

Переадресация путей

Тут нам надо исправить 2 момента:

#Установим root и точку входа, у нас index.html в папка dist
root /home/my_domain/my_domain/dist/; 
index index.html;
# Укажем, как обрабатывать пути, кроме статических файлов (отбор по расширениям)

location / {
        if (-f $request_filename) {
            	expires max;
            	break;
        }
        if ($request_filename !~ "\.(js|htc|ico|gif|jpg|png|css)$") {
            	rewrite ^(.*) /index.html last;
        }
}

Получение/обновление SSL

В данном случае мы используем Let’s Encrypt, Webmin для автоматической работы с этими сертификатами использует папку /.well-known, соответственно выделяем ее так, что бы она не обрабатывалась нашим SPA — например меняем для этого location root.

location /.well-known/ {
	root /home/my_domain/public_html;
}

Итоговый шаблон

server {
	server_name my_domain.ru www.my_domain.ru;

	# your server IP
	listen 00.00.00.00;

	root /home/my_domain/my_domain/dist/;
	index index.html;

	access_log /var/log/virtualmin/my_domain.ru_access_log;
	error_log /var/log/virtualmin/my_domain.ru_error_log;
	fastcgi_param GATEWAY_INTERFACE CGI/1.1;
	fastcgi_param SERVER_SOFTWARE nginx;
	fastcgi_param QUERY_STRING $query_string;
	fastcgi_param REQUEST_METHOD $request_method;
	fastcgi_param CONTENT_TYPE $content_type;
	fastcgi_param CONTENT_LENGTH $content_length;
	fastcgi_param SCRIPT_FILENAME /home/my_domain/public_html$fastcgi_script_name;
	fastcgi_param SCRIPT_NAME $fastcgi_script_name;
	fastcgi_param REQUEST_URI $request_uri;
	fastcgi_param DOCUMENT_URI $document_uri;
	fastcgi_param DOCUMENT_ROOT /home/my_domain/public_html;
	fastcgi_param SERVER_PROTOCOL $server_protocol;
	fastcgi_param REMOTE_ADDR $remote_addr;
	fastcgi_param REMOTE_PORT $remote_port;
	fastcgi_param SERVER_ADDR $server_addr;
	fastcgi_param SERVER_PORT $server_port;
	fastcgi_param SERVER_NAME $server_name;
	fastcgi_param PATH_INFO $fastcgi_path_info;
	fastcgi_param HTTPS $https;

	location /.well-known/ {
		root /home/my_domain/public_html;
	}

	location / {
        	if (-f $request_filename) {
            		expires max;
            		break;
        	}

        	if ($request_filename !~ "\.(js|ico|gif|jpg|png|css)$") {
            		rewrite ^(.*) /index.html last;
        	}
    	}

	# your server IP
	listen 00.00.00.00:443 ssl;
	ssl_certificate /etc/ssl/virtualmin/PATH_TO_KEY/ssl.combined;
	ssl_certificate_key /etc/ssl/virtualmin/PATH_TO_KEY/ssl.key;
}

Итого

Очевидно, что все папки и адреса Вам необходимо заменить на собственные, но идея остается прежней: перехватываем все пути и замыкаем на index.html, а отдельные служебные пути выделяем в location и оставляем например в стандартной public_html для удобства.

Так же при необходимости использования API с этого же сервера, Вы можете самостоятельно добавить location по типу /api/ и сделать редирект на обработчик например.