> For the complete documentation index, see [llms.txt](https://docs.iexexchanger.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.iexexchanger.com/ustanovka-i-obnovlenie/ustanovka/nastroika-fastpanel/nastroika-nginx.md).

# Настройка Nginx

На этом этапе необходимо настроить Nginx для совместной работы Frontend и Backend частей iEXExchanger.

Nginx принимает входящие запросы и направляет их в нужный компонент системы:

* публичные страницы — в Angular SSR;
* API-запросы — в Laravel через PHP-FPM;
* WebSocket-соединения — в Laravel Reverb;
* изображения и загруженные файлы — в публичные каталоги Backend;
* пользовательские Frontend-файлы — в каталог `/ng-custom`;
* файлы подтверждения — в отдельный каталог Backend;
* экспортируемые файлы — в каталог экспортов.

Инструкция предназначена для установки iEXExchanger через FastPanel, когда Frontend и Backend находятся на одном сервере.

{% hint style="warning" %}
Все домены, IP-адреса, имена пользователей, пути и сокеты в инструкции являются шаблонами. Перед сохранением конфигурации замените их реальными значениями проекта.
{% endhint %}

## Перед началом

Перед настройкой убедитесь, что:

* основной домен `ваш_домен` создан в FastPanel;
* технический поддомен `app.ваш_домен` создан в FastPanel;
* SSL-сертификаты установлены для обоих доменов;
* Frontend загружен и настроен;
* Backend загружен и настроен;
* рабочей директорией Backend является каталог `public`;
* Backend работает через PHP-FPM;
* Angular SSR запускается через PM2;
* Angular SSR слушает `127.0.0.1:4000`;
* Laravel Reverb слушает `127.0.0.1:8080`;
* у вас есть доступ к FastPanel и серверу по SSH.

## Что необходимо заменить

<table data-search="false"><thead><tr><th width="350.28125">Значение</th><th>Назначение</th></tr></thead><tbody><tr><td><code>ваш_домен</code></td><td>Основной домен Frontend</td></tr><tr><td><code>www.ваш_домен</code></td><td>Дополнительный Frontend-домен</td></tr><tr><td><code>app.ваш_домен</code></td><td>Технический домен Backend</td></tr><tr><td><code>IP_СЕРВЕРА</code></td><td>Публичный IP-адрес сервера</td></tr><tr><td><code>имя_пользователя_frontend</code></td><td>Системный пользователь Frontend</td></tr><tr><td><code>имя_пользователя_backend</code></td><td>Системный пользователь Backend</td></tr><tr><td><code>/var/run/app.ваш_домен.sock</code></td><td>Сокет PHP-FPM Backend</td></tr></tbody></table>

Пример:

```
Основной домен: example.com
Backend-домен: app.example.com

Frontend-пользователь: example_com_usr
Backend-пользователь: app_example_com_usr

PHP-FPM-сокет: /var/run/app.example.com.sock
```

## Сохранение текущей конфигурации

Перед изменениями сохраните текущую конфигурацию обоих сайтов.

Для Backend откройте:

**«Сайты» — выберите `app.ваш_домен` — «Ручная настройка» — «Frontend»**

Для Frontend откройте:

**«Сайты» — выберите `ваш_домен` — «Ручная настройка» — «Frontend»**

Скопируйте обе конфигурации в отдельные файлы. Это позволит быстро вернуть предыдущую версию, если при редактировании будет допущена ошибка.

***

## Настройка Nginx для Backend

Backend работает на техническом поддомене:

```
app.ваш_домен
```

Стандартную Laravel-конфигурацию FastPanel заменять не нужно. На стороне Backend необходимо сохранить существующую обработку PHP и добавить маршруты Laravel Reverb.

{% stepper %}
{% step %}

### Открытие конфигурации Backend

В FastPanel откройте:

**«Сайты» — выберите `app.ваш_домен` — «Ручная настройка» — «Frontend»**
{% endstep %}

{% step %}

### Проверка PHP-FPM

В конфигурации найдите стандартный PHP-блок:

```nginx
location ~ \.php$ {
    include /etc/nginx/fastcgi_params;
    fastcgi_pass unix:/var/run/app.ваш_домен.sock;
    fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
    fastcgi_param DOCUMENT_ROOT $realpath_root;
}
```

В реальной конфигурации FastPanel сокет будет содержать ваш Backend-домен:

```
fastcgi_pass unix:/var/run/app.example.com.sock;
```

Проверьте существование сокета:

```
ls -la /var/run/app.ваш_домен.sock
```

Если файла нет, проверьте настройки PHP-FPM в FastPanel.
{% endstep %}

{% step %}

### Добавление WebSocket Laravel Reverb

После PHP-блока добавьте:

```nginx
location = /app {
    return 308 /app/;
}

location ^~ /app/ {
    proxy_pass http://iex_reverb;
    proxy_http_version 1.1;

    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Port $server_port;

    proxy_hide_header X-Powered-By;
    proxy_buffering off;

    proxy_connect_timeout 10s;
    proxy_read_timeout 3600s;
    proxy_send_timeout 3600s;
}
```

Маршрут `/app/` используется для WebSocket-соединений.

Через него работают:

* обновления статусов заявок;
* чат заявки;
* онлайн-статусы;
* системные события;
* уведомления в реальном времени;
* обновления административной панели.
  {% endstep %}

{% step %}

### Добавление HTTP API Laravel Reverb

После блока `/app/` добавьте:

```nginx
location = /apps {
    return 308 /apps/;
}

location ^~ /apps/ {
    proxy_pass http://iex_reverb;
    proxy_http_version 1.1;

    proxy_set_header Host $host;
    proxy_set_header Connection "";

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Port $server_port;

    proxy_hide_header X-Powered-By;

    proxy_connect_timeout 10s;
    proxy_read_timeout 60s;
    proxy_send_timeout 60s;
}
```

Маршрут `/apps/` используется внутренним HTTP API Laravel Reverb.

Он не является WebSocket-соединением, поэтому для него используется:

```
proxy_set_header Connection "";
```

WebSocket-заголовки нужны только для `/app/`.
{% endstep %}

{% step %}

### Почему proxy\_pass используется без завершающего слеша

Используется:

```
proxy_pass http://iex_reverb;
```

Без завершающего `/` Nginx сохраняет исходный URI:

```
/app/...  → /app/...
/apps/... → /apps/...
```

Если добавить завершающий слеш, путь может быть изменён при проксировании.
{% endstep %}

{% step %}

### Сохранение настройки Backend

После добавления блоков нажмите **«Сохранить»**.

Проверьте конфигурацию:

```
sudo nginx -t
```

Если ошибок нет, примените изменения:

```
sudo systemctl reload nginx
```

{% endstep %}
{% endstepper %}

***

## Настройка Nginx для Frontend

Frontend работает на основном домене:

```
ваш_домен
```

На стороне Frontend необходимо удалить стандартное проксирование FastPanel через Apache и настроить:

* Angular SSR;
* Backend API;
* Laravel Reverb;
* статические файлы Backend;
* пользовательские файлы `/ng-custom`;
* файлы подтверждения;
* экспортируемые файлы;
* кеширование;
* HTTPS.

{% stepper %}
{% step %}

### Открытие конфигурации Frontend

В FastPanel откройте:

**«Сайты» — выберите `ваш_домен` — «Ручная настройка» — «Frontend»**
{% endstep %}

{% step %}

### Удаление старых правил FastPanel

В конфигурации основного домена удалите стандартное проксирование через Apache:

```nginx
location / {
    proxy_pass http://127.0.0.1:81;
    proxy_redirect http://127.0.0.1:81/ /;
    include /etc/nginx/proxy_params;
}
```

Удалите старое правило статических файлов:

```
location ~* ^.+\.(jpg|jpeg|gif|png|svg|js|css|mp3|ogg|mpeg|avi|zip|gz|bz2|rar|swf|ico|7z|doc|docx|map|ogg|otf|pdf|ttf|tif|txt|wav|webp|woff|woff2|xls|xlsx|xml)$ {
    try_files $uri $uri/ @fallback;
}
```

Удалите named location:

```nginx
location @fallback {
    proxy_pass http://127.0.0.1:81;
    proxy_redirect http://127.0.0.1:81/ /;
    include /etc/nginx/proxy_params;
}
```

Если в конфигурации остался старый API-маршрут `/apis`, удалите:

```nginx
location /apis {
    alias /var/www/имя_пользователя_backend/data/www/app.ваш_домен/public;
    try_files $uri $uri/ @apis;
}

location @apis {
    rewrite ^/apis/(.*)$ /apis/index.php?/$1 last;
}
```

В новой конфигурации используется:

```
/backend-api/
```

Удалите старые языковые правила:

```
map $http_accept_language ...
map $cookie_lang ...
location ~ ^/(ru|en) ...
```

Удалите глобальный заголовок:

```
add_header Vary "Accept-Language, Cookie" always;
```

Языки должны обрабатываться Angular SSR, а не Nginx.
{% endstep %}

{% step %}

### Основные переменные Frontend

Внутри блока `server` добавьте:

```nginx
client_max_body_size 64m;

set $backend_domain app.ваш_домен;
set $backend_public_path /var/www/имя_пользователя_backend/data/www/app.ваш_домен/public;
set $frontend_public_path /var/www/имя_пользователя_frontend/data/www/ваш_домен/public;
```

Пример:

```nginx
client_max_body_size 64m;

set $backend_domain app.example.com;
set $backend_public_path /var/www/app_example_com_usr/data/www/app.example.com/public;
set $frontend_public_path /var/www/example_com_usr/data/www/example.com/public;
```

Параметр:

```
client_max_body_size 64m;
```

разрешает принимать запросы размером до 64 МБ.

Для загрузки файлов также проверьте PHP-настройки:

```
upload_max_filesize
post_max_size
```

{% endstep %}

{% step %}

### Настройка Gzip

Найдите:

```
gzip_comp_level 1;
```

Замените на:

```
gzip_comp_level 5;
```

Рекомендуемая конфигурация:

```nginx
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 1024;

gzip_types
    text/plain
    text/css
    text/xml
    application/json
    application/javascript
    application/manifest+json
    application/xml
    application/rss+xml
    image/svg+xml
    font/ttf
    font/otf
    application/vnd.ms-fontobject;
```

Уровень `5` обеспечивает хорошее сжатие без чрезмерной нагрузки на процессор.
{% endstep %}

{% step %}

### Настройка файлов подтверждения

Файлы подтверждения используются сервисами, которые требуют разместить файл в корне основного домена.

Примеры:

```
https://ваш_домен/google123456.html
https://ваш_домен/verification.txt
```

Файлы должны находиться в Backend:

```
app.ваш_домен/public/site-verification-files
```

Добавьте:

```nginx
location ~* "^/(?!(?:3rdpartylicenses\.txt|favicon\.ico|hot|index\.php|ngsw\.json|project_info\.txt|robots\.txt|valuta\.xml|web\.config)$)([A-Za-z0-9][A-Za-z0-9._-]{0,127}\.(?:txt|html|htm|xml|json))$" {
    alias $backend_public_path/site-verification-files/$1;

    types {
        text/plain       txt;
        text/html        html htm;
        application/xml  xml;
        application/json json;
    }

    default_type text/plain;

    access_log off;
    log_not_found off;
}
```

Пример:

```
Файл на сервере:
app.example.com/public/site-verification-files/google123.html

Публичный адрес:
https://example.com/google123.html
```

{% endstep %}

{% step %}

### Настройка `/ng-custom/`

Каталог `/ng-custom/` содержит Frontend-файлы, которые могут изменяться без полной пересборки Angular.

Файлы находятся в:

```
/var/www/имя_пользователя_frontend/data/www/ваш_домен/public/ng-custom
```

Добавьте:

```nginx
location ^~ /ng-custom/ {
    alias $frontend_public_path/ng-custom/;
    try_files $uri =404;

    add_header Cache-Control "no-store, no-cache, must-revalidate";
    add_header Pragma "no-cache";
    add_header Expires "0";

    autoindex off;
    access_log off;
    log_not_found off;
}
```

Пример проверки:

```
https://ваш_домен/ng-custom/ssr-head.html
```

Длительное кеширование отключено, поскольку содержимое файла может измениться без изменения URL.
{% endstep %}

{% step %}

### Настройка Backend API

Frontend обращается к Laravel через:

```
/backend-api/
```

Пример внешнего запроса:

```
https://ваш_домен/backend-api/client-api/v1/ping
```

Laravel должен получить путь без внешнего префикса:

```
/client-api/v1/ping
```

Добавьте:

```nginx
location = /backend-api {
    return 308 /backend-api/;
}

location ^~ /backend-api/ {
    rewrite ^/backend-api/(.*)$ /$1 break;

    include /etc/nginx/fastcgi_params;

    fastcgi_param SCRIPT_FILENAME $backend_public_path/index.php;
    fastcgi_param SCRIPT_NAME     /index.php;
    fastcgi_param DOCUMENT_ROOT   $backend_public_path;
    fastcgi_param REQUEST_URI     $uri$is_args$args;
    fastcgi_param QUERY_STRING    $query_string;

    fastcgi_param HTTP_HOST        $backend_domain;
    fastcgi_param SERVER_NAME      $backend_domain;
    fastcgi_param SERVER_PORT      443;
    fastcgi_param HTTPS            on;

    fastcgi_param HTTP_AUTHORIZATION       $http_authorization;
    fastcgi_param HTTP_X_REAL_IP           $remote_addr;
    fastcgi_param HTTP_X_FORWARDED_FOR     $proxy_add_x_forwarded_for;
    fastcgi_param HTTP_X_FORWARDED_HOST    $host;
    fastcgi_param HTTP_X_FORWARDED_PROTO   $scheme;
    fastcgi_param HTTP_X_FORWARDED_PORT    $server_port;

    # Защита от HTTPoxy.
    fastcgi_param HTTP_PROXY "";

    fastcgi_hide_header X-Powered-By;

    fastcgi_buffering off;
    fastcgi_connect_timeout 10s;
    fastcgi_read_timeout 60s;
    fastcgi_send_timeout 60s;

    fastcgi_pass unix:/var/run/app.ваш_домен.sock;
}
```

Схема работы:

```
Внешний запрос:
/backend-api/client-api/v1/ping

↓ Nginx удаляет /backend-api

Laravel получает:
/client-api/v1/ping
```

API передаётся напрямую в PHP-FPM. Запрос не проходит через внешний Backend-домен и не требует отдельного HTTPS-проксирования.
{% endstep %}

{% step %}

### Публичный API `/api/v3/`

Этот маршрут добавляется только в том случае, если публичный API должен открываться через основной домен.

Префикс `/api/v3/` сохраняется:

```
/api/v3/rates → /api/v3/rates
```

Добавьте перед общим `location /`:

```nginx
location = /api/v3 {
    return 308 /api/v3/;
}

location ^~ /api/v3/ {
    include /etc/nginx/fastcgi_params;

    fastcgi_param SCRIPT_FILENAME $backend_public_path/index.php;
    fastcgi_param SCRIPT_NAME     /index.php;
    fastcgi_param DOCUMENT_ROOT   $backend_public_path;
    fastcgi_param REQUEST_URI     $request_uri;
    fastcgi_param QUERY_STRING    $query_string;

    fastcgi_param HTTP_HOST        $backend_domain;
    fastcgi_param SERVER_NAME      $backend_domain;
    fastcgi_param SERVER_PORT      443;
    fastcgi_param HTTPS            on;

    fastcgi_param HTTP_AUTHORIZATION       $http_authorization;
    fastcgi_param HTTP_X_REAL_IP           $remote_addr;
    fastcgi_param HTTP_X_FORWARDED_FOR     $proxy_add_x_forwarded_for;
    fastcgi_param HTTP_X_FORWARDED_HOST    $host;
    fastcgi_param HTTP_X_FORWARDED_PROTO   $scheme;
    fastcgi_param HTTP_X_FORWARDED_PORT    $server_port;

    fastcgi_param HTTP_PROXY "";

    fastcgi_hide_header X-Powered-By;

    fastcgi_buffering off;
    fastcgi_connect_timeout 10s;
    fastcgi_read_timeout 60s;
    fastcgi_send_timeout 60s;

    fastcgi_pass unix:/var/run/app.ваш_домен.sock;
}
```

{% hint style="info" %}
Если публичный API через основной домен не используется, не добавляйте маршрут `/api/v3/`.
{% endhint %}
{% endstep %}

{% step %}

## Настройка изображений Backend

Добавьте:

```nginx
location ^~ /images/ {
    root $backend_public_path;
    try_files $uri =404;

    add_header Cache-Control "public, max-age=31536000, immutable";

    autoindex off;
    access_log off;
    log_not_found off;
}
```

Изображения кешируются на один год при условии, что каждый новый файл получает новый URL.
{% endstep %}

{% step %}

### Настройка Laravel Storage

Добавьте:

```nginx
location ^~ /storage/ {
    root $backend_public_path;
    try_files $uri =404;

    add_header Cache-Control "public, max-age=31536000, immutable";

    autoindex off;
    access_log off;
    log_not_found off;
}
```

{% endstep %}

{% step %}

### Настройка `/dist/`

В каталоге `/dist/` могут находиться файлы с постоянными именами:

```
/dist/assets/i18n/en.json
/dist/assets/animations/loading.json
/dist/assets/icons/locale/en.svg
/dist/assets/images/avatar_default.png
```

Их содержимое может измениться без изменения URL.

Добавьте:

```nginx
location ^~ /dist/ {
    root $backend_public_path;
    try_files $uri =404;

    add_header Cache-Control "public, max-age=0, must-revalidate";

    autoindex off;
    access_log off;
    log_not_found off;
}
```

Не используйте для всего `/dist/`:

```
immutable
```

Иначе переводы, изображения и другие файлы могут не обновляться у клиентов.
{% endstep %}

{% step %}

### Настройка `/static/`

Добавьте:

```nginx
location ^~ /static/ {
    root $backend_public_path;
    try_files $uri =404;

    autoindex off;
    access_log off;
    log_not_found off;
}
```

Явная политика кеширования не задаётся, поскольку не для всех файлов подтверждена неизменяемость URL.
{% endstep %}

{% step %}

### Настройка `/exports/`

Если файлы находятся в:

```
Backend public/exports
```

добавьте:

```nginx
location ^~ /exports/ {
    root $backend_public_path;
    try_files $uri =404;

    add_header Cache-Control "no-store, no-cache, must-revalidate";
    add_header Pragma "no-cache";
    add_header Expires "0";

    autoindex off;
    access_log off;
    log_not_found off;
}
```

Если экспорты находятся в:

```
Backend public/static/exports
```

используйте:

```nginx
location ^~ /exports/ {
    alias $backend_public_path/static/exports/;
    try_files $uri =404;

    add_header Cache-Control "no-store, no-cache, must-revalidate";
    add_header Pragma "no-cache";
    add_header Expires "0";

    autoindex off;
    access_log off;
    log_not_found off;
}
```

{% hint style="warning" %}
Проверьте фактическое расположение файлов экспорта. Не добавляйте одновременно оба варианта.
{% endhint %}
{% endstep %}
{% endstepper %}

### Настройка Laravel Reverb на Frontend

Если публичный сайт подключается к Reverb через основной домен, добавьте маршруты `/app/` и `/apps/`.

{% stepper %}
{% step %}

#### WebSocket

```nginx
location = /app {
    return 308 /app/;
}

location ^~ /app/ {
    proxy_pass http://iex_reverb;
    proxy_http_version 1.1;

    proxy_set_header Host $backend_domain;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Port $server_port;

    proxy_hide_header X-Powered-By;
    proxy_buffering off;

    proxy_connect_timeout 10s;
    proxy_read_timeout 3600s;
    proxy_send_timeout 3600s;
}
```

{% endstep %}

{% step %}

#### HTTP API Reverb

```nginx
location = /apps {
    return 308 /apps/;
}

location ^~ /apps/ {
    proxy_pass http://iex_reverb;
    proxy_http_version 1.1;

    proxy_set_header Host $backend_domain;
    proxy_set_header Connection "";

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Port $server_port;

    proxy_hide_header X-Powered-By;

    proxy_connect_timeout 10s;
    proxy_read_timeout 60s;
    proxy_send_timeout 60s;
}
```

{% endstep %}
{% endstepper %}

### Настройка статических файлов Angular

Статические файлы Angular передаются в SSR-процесс:

```
location ~* \.(?:avif|bmp|css|eot|gif|ico|jpe?g|js|json|map|mjs|png|svg|ttf|webmanifest|webp|woff2?)$ {
    proxy_pass http://iex_frontend_ssr;
    proxy_http_version 1.1;

    proxy_set_header Host $host;
    proxy_set_header Connection "";

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Port $server_port;

    proxy_connect_timeout 10s;
    proxy_read_timeout 60s;
    proxy_send_timeout 60s;

    access_log off;
}
```

Nginx не переопределяет `Cache-Control` для Angular-файлов. Политику кеширования определяет SSR-сервер.

### Настройка Angular SSR

Добавьте общий маршрут:

```nginx
location / {
    proxy_pass http://iex_frontend_ssr;
    proxy_redirect off;
    proxy_http_version 1.1;

    proxy_set_header Host $host;
    proxy_set_header Connection "";

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Port $server_port;

    proxy_connect_timeout 10s;
    proxy_read_timeout 60s;
    proxy_send_timeout 60s;
}
```

Для обычных SSR-запросов не нужны:

```
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
```

WebSocket работает только через `/app/`.

Поэтому для Angular используется:

```
proxy_set_header Connection "";
```

Это позволяет Nginx повторно использовать соединения с SSR через keepalive.

### Настройка языков

Языки не настраиваются в Nginx.

Не добавляйте:

```
map $http_accept_language ...
map $cookie_lang ...
location ~ ^/(ru|en) ...
```

Если на сайте используются языки:

```
ru
en
es
fr
pl
uk
zh
ka
kk
de
```

они должны быть настроены во Frontend.

Nginx только передаёт запрос в Angular SSR:

```
location / {
    proxy_pass http://iex_frontend_ssr;
}
```

Angular SSR самостоятельно определяет язык, маршрут и необходимые редиректы.

### Cloudflare и HTTPS

Для перенаправления HTTP на HTTPS можно использовать:

```nginx
if ($scheme = http) {
    return 308 https://ваш_домен$request_uri;
}
```

Если FastPanel уже создала отдельный блок для порта `80`, используйте отдельный редирект:

```nginx
server {
    listen IP_СЕРВЕРА:80;
    server_name ваш_домен www.ваш_домен;

    return 308 https://ваш_домен$request_uri;
}
```

В этом случае в HTTPS-блоке не должно быть повторного:

```
listen IP_СЕРВЕРА:80;
```

Для Cloudflare используйте:

```
Full
```

или предпочтительно:

```
Full (strict)
```

{% hint style="danger" %}
Не используйте Cloudflare Flexible. Это приведёт к бесконечному циклу перенаправлений между Cloudflare и Nginx.
{% endhint %}

### Что не нужно добавлять

Не добавляйте:

```
BACKEND_ORIGIN_IP
```

Не добавляйте:

```
upstream iex_backend_https
```

Не используйте старый маршрут:

```
/apis
```

Не проксируйте Frontend через:

```
127.0.0.1:81
```

Не добавляйте языковые `map`-блоки.

Не добавляйте глобально:

```
add_header Vary "Accept-Language, Cookie" always;
```

Не используйте в `proxy_pass`:

```
0.0.0.0
```

Не добавляйте `/api/v3/`, если публичный API не используется.

***

## Полная готовая конфигурация Nginx

Ниже приведён пример полной конфигурации Nginx для основного домена Frontend.

Перед сохранением обязательно замените:

* `ваш_домен`;
* `www.ваш_домен`;
* `app.ваш_домен`;
* `имя_пользователя_frontend`;
* `имя_пользователя_backend`;
* `IP_СЕРВЕРА`;
* путь к SSL-сертификату;
* путь к SSL-ключу;
* PHP-FPM socket Backend.

```nginx
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      '';
}

upstream iex_frontend_ssr {
    server 127.0.0.1:4000;
    keepalive 32;
}

upstream iex_backend_php {
    server unix:/var/run/app.ваш_домен.sock;
}

upstream iex_reverb {
    server 127.0.0.1:8080;
    keepalive 32;
}

server {
    server_name ваш_домен www.ваш_домен;

    listen IP_СЕРВЕРА:80;
    listen IP_СЕРВЕРА:443 ssl;
    http2 on;

    # Для Cloudflare должен использоваться режим Full или Full (strict).
    # В режиме Flexible такой редирект вызовет цикл перенаправлений.
    if ($scheme = http) {
        return 308 https://ваш_домен$request_uri;
    }

    server_tokens off;
    tcp_nodelay on;

    proxy_headers_hash_max_size 1024;
    proxy_headers_hash_bucket_size 128;

    ssl_certificate "/var/www/httpd-cert/ваш_сертификат.crt";
    ssl_certificate_key "/var/www/httpd-cert/ваш_сертификат.key";

    charset utf-8;

    gzip on;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types
        text/plain
        text/css
        text/xml
        application/xml
        application/json
        application/javascript
        application/manifest+json
        image/svg+xml
        image/x-icon;
    gzip_comp_level 5;
    gzip_vary on;
    gzip_min_length 256;
    gzip_buffers 16 8k;
    gzip_disable "msie6";

    set $root_path /var/www/имя_пользователя_frontend/data/www/ваш_домен;
    root $root_path;
    
    disable_symlinks if_not_owner from=$root_path;

    client_max_body_size 64m;

    set $backend_domain app.ваш_домен;
    set $backend_public_path /var/www/имя_пользователя_backend/data/www/app.ваш_домен/public;
    set $frontend_public_path /var/www/имя_пользователя_frontend/data/www/ваш_домен/public;

    location ~* "^/(?!(?:3rdpartylicenses\.txt|favicon\.ico|hot|index\.php|ngsw\.json|project_info\.txt|robots\.txt|valuta\.xml|web\.config)$)([A-Za-z0-9][A-Za-z0-9._-]{0,127}\.(?:txt|html|htm|xml|json))$" {
        alias $backend_public_path/site-verification-files/$1;

        types {
            text/plain       txt;
            text/html        html htm;
            application/xml xml;
            application/json json;
        }

        default_type text/plain;
        access_log off;
    }

    location ^~ /ng-custom/ {
        alias $frontend_public_path/ng-custom/;

        expires off;
        add_header Cache-Control "no-store, no-cache, must-revalidate";

        autoindex off;
        access_log off;
    }

    location ^~ /images/ {
        alias $backend_public_path/images/;

        add_header Cache-Control "public, max-age=31536000, immutable";

        autoindex off;
        access_log off;
    }

    location ^~ /storage/ {
        alias $backend_public_path/storage/;

        add_header Cache-Control "public, max-age=31536000, immutable";

        autoindex off;
        access_log off;
    }

    location ^~ /static/ {
        alias $backend_public_path/static/;

        autoindex off;
        access_log off;
    }

    location ^~ /dist/ {
        alias $backend_public_path/dist/;
        expires 30d;

        autoindex off;
        access_log off;
    }

    location ^~ /exports/ {
        alias $backend_public_path/static/exports/;

        # Курсы валют должны перепроверяться клиентом,
        # а не сохраняться надолго.
        expires off;
        add_header Cache-Control "no-store, no-cache, must-revalidate";

        autoindex off;
        access_log off;
    }

    location = /backend-api {
        return 308 /backend-api/;
    }

    location ~ ^/backend-api/(?<backend_api_uri>.*)$ {
        include /etc/nginx/fastcgi_params;

        fastcgi_pass iex_backend_php;
        fastcgi_index index.php;

        fastcgi_param SCRIPT_FILENAME $backend_public_path/index.php;
        fastcgi_param DOCUMENT_ROOT $backend_public_path;
        fastcgi_param SCRIPT_NAME /index.php;

        fastcgi_param REQUEST_URI /$backend_api_uri$is_args$args;
        fastcgi_param QUERY_STRING $query_string;

        fastcgi_param HTTP_HOST $backend_domain;
        fastcgi_param SERVER_NAME $backend_domain;
        fastcgi_param SERVER_PORT 443;
        fastcgi_param HTTPS on;

        fastcgi_param HTTP_X_REAL_IP $remote_addr;
        fastcgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for;
        fastcgi_param HTTP_X_FORWARDED_HOST $host;
        fastcgi_param HTTP_X_FORWARDED_PROTO $scheme;
        fastcgi_param HTTP_X_FORWARDED_PORT $server_port;

        # Защита от HTTPoxy.
        fastcgi_param HTTP_PROXY "";

        fastcgi_hide_header X-Powered-By;

        fastcgi_buffering off;
        fastcgi_connect_timeout 10s;
        fastcgi_read_timeout 60s;
        fastcgi_send_timeout 10s;
    }

    location = /app {
        return 308 /app/;
    }

    location ^~ /app/ {
        proxy_pass http://iex_reverb;
        proxy_http_version 1.1;

        proxy_set_header Host $backend_domain;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port $server_port;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_hide_header X-Powered-By;
        proxy_buffering off;

        proxy_connect_timeout 10s;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }


    location = /apps {
        return 308 /apps/;
    }

    location ^~ /apps/ {
        proxy_pass http://iex_reverb;
        proxy_http_version 1.1;

        proxy_set_header Host $backend_domain;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port $server_port;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_hide_header X-Powered-By;
        proxy_buffering off;

        proxy_connect_timeout 10s;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }

    location ~* ^/(assets/|theme/|.*\.(?:js|css|map|ico|txt|xml|json|csv|pdf|webmanifest|woff|woff2|ttf|otf|svg|png|jpg|jpeg|gif|webp|avif))$ {
        proxy_pass http://iex_frontend_ssr;
        proxy_http_version 1.1;

        proxy_set_header Host $host;
        proxy_set_header Connection "";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port $server_port;

        access_log off;
    }

    location / {
        proxy_pass http://iex_frontend_ssr;
        proxy_redirect off;
        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-Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port $server_port;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_buffering on;
        proxy_buffers 16 64k;
        proxy_buffer_size 128k;

        proxy_connect_timeout 10s;
        proxy_read_timeout 60s;
        proxy_send_timeout 10s;
    }

    include "/etc/nginx/fastpanel2-sites/имя_пользователя_frontend/ваш_домен.includes";
    include /etc/nginx/fastpanel2-includes/*.conf;

    error_log /var/www/имя_пользователя_frontend/data/logs/ваш_домен-frontend.error.log;
    access_log /var/www/имя_пользователя_frontend/data/logs/ваш_домен-frontend.access.log fastpanel;
}
```

{% hint style="info" %}
Не добавляйте `BACKEND_ORIGIN_IP`, `upstream iex_backend_https`, языковые `map`-блоки и старый путь `/apis`. В этой версии Backend API работает через PHP-FPM socket и путь `/backend-api/`.
{% endhint %}

## Коротко

Настройка выполняется отдельно для двух сайтов.

На Backend-домене сохраняется стандартная Laravel-конфигурация FastPanel и добавляются маршруты Laravel Reverb:

```
/app/
/apps/
```

На Frontend-домене настраиваются:

```
Angular SSR
/backend-api/
/images/
/storage/
/dist/
/static/
/exports/
/ng-custom/
/app/
/apps/
```

После настройки публичный сайт работает через Angular SSR на порту `4000`, Laravel API подключается напрямую через PHP-FPM, а события реального времени передаются в Reverb на порту `8080`.

* языки обрабатывает Angular SSR, а не Nginx.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.iexexchanger.com/ustanovka-i-obnovlenie/ustanovka/nastroika-fastpanel/nastroika-nginx.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
