Проблемы с веб-сервисом Python Flask за обратным прокси-сервером NGINX

Вопрос или проблема

Я запрограммировал веб-сервис, используя фреймворк Python-Flask, который взаимодействует с REST-сервисом, предоставляемым другим подразделением моей компании. Сервис работает нормально, если я запускаю его без NGINX. Однако в продуктивной среде мне нужно развернуть его за обратным прокси-сервером NGINX, и здесь я застрял.

Фласк-сервис определяет конечные точки/маршруты сервиса

* @bp.route("https://serverfault.com/", methods=["GET", "POST"]): корневой/индексный путь
* @bp.route('/get_source_state', methods=['GET']): получить состояние источника
* @bp.route('/update_source_state', methods=["GET", "PUT"]): обновить состояние источника

В настоящее время мой конфиг NGINX выглядит следующим образом:

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name host_name;
    return 301 https://$host$request_uri;
}

server {
  listen 443 ssl;
  listen [::]:443 ssl;

  ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Отключение SSLv3, ref: POODLE
  ssl_prefer_server_ciphers on;

  ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
  ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;

  root /var/www/host_name/html;
  index index.html index.htm;

  server_name host_name;

  location /grafana/ { // Сервис Grafana на сервере работает нормально
    proxy_pass http://localhost:3000/;
    proxy_set_header Host $host;
  }

  location /source_status/ { // Это мой Flask-сервис
    proxy_pass http://localhost:8080/;
    proxy_set_header Host $host;
  }
  
  ...

Когда я вызываю сервис с другого клиента, кроме localhost, маршрут /source_status/ работает нормально, и страница открывается. На странице Flask есть кнопки, которые запускают JavaScript-код, вызывающий конечные точки /get_source_state/ и /update_source_state/. Как только я нажимаю на кнопку на веб-странице, ничего не происходит, и отладчик показывает мне сообщение об ошибке

https://host_name/get_source_state/?argument:value  404 Not found

Так что я предполагаю, что мой NGINX настроен неправильно. Как это сделать? Извините, я немного потерялся, так как у меня нет большого опыта работы с NGINX.

Обновление:

Я последовал предложению Джеральда Шнайдера и добавил предложенный proxy_fix в мой код Flask, который теперь выглядит так:

from flask import Flask, render_template, request, Blueprint, jsonify
from requests import Response
from werkzeug.middleware.proxy_fix import ProxyFix

bp = Blueprint("viewer", __name__)
app = Flask(__name__)
app.wsgi_app = ProxyFix(
     app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1
)

... код с определениями маршрутов и т.д.

Должен признаться, что не знаю, что я там делаю, просто скопировал из proxy_fix.

Обновление:

Ошибка в логе NGINX сообщает мне:

"/var/www/server_name/html/get_archive_source_state/index.html" is not found (2: No such file or directory), client: client_ip, server: server_name, request: "GET /get_archive_source_state/?arguements:values HTTP/1.1", host: "server_name", referrer: "https://server_name/source_status/"

Ответ или решение

Для решения проблемы с Flask-сервисом, работающим за NGINX как обратным прокси, необходимо обратиться к нескольким теориям и практическим аспектам, которые помогут вам понять, что может идти не так, и как это исправить.

Теория

NGINX, как обратный прокси, выполняет важную роль в распределении нагрузки и обеспечении безопасности, принимая входящие HTTP(S) запросы и перенаправляя их на серверы приложений, такие как ваш Flask-сервис. Конфигурация NGINX управляет маршрутизацией запросов, используя директиву location для сопоставления URL-путей с проксируемыми маршрутами.

Flask, будучи легковесным веб-фреймворком в Python, решает задачи построения веб-сервисов и предлагает гибкость в настройке URL-маршрутизации. Одним из ключевых моментов интеграции Flask с NGINX является корректное управление заголовками и маршрутизацией, устанавливаемыми NGINX, чтобы Flask-приложение могло правильно обрабатывать запросы и не терять контекст.

Пример

Из вашего описания можно выявить несколько ключевых моментов:

  • Ваш NGINX конфигурирует маршрутизацию через директиву location, передавая запросы с определёнными путями на соответствующие серверы прокси.
  • Возникла проблема с путями, не соответствующими вашим ожиданиям, что приводит к ошибке 404, когда вы вызываете эндпоинты get_source_state и update_source_state через клиентский JavaScript.

Применение

1. Проблема маршрутизации

Из предоставленной информации видно, что NGINX маршрутизирует запросы с префиксом /source_status/ на ваш Flask-сервер, но внутри вашего Flask приложения пути обрабатываются без префикса /source_status/. Это может привести к ошибкам, так как ожидания URL могут не совпадать с тем, что фактически запрашивается.

Решение:

Пересмотрите, каким образом URL обрабатываются в клиентском коде. Посмотрите, как генерируются запросы на get_source_state и update_source_state. Возможно, вам необходимо включить префикс /source_status/ в эти URL, если они отправляются клиентом напрямую к серверу.

Пример изменения клиентского кода:

var url = "/source_status/get_source_state/"; // Добавление префикса

2. Используйте ProxyFix

Вы уже добавили ProxyFix, это правильно, так как он поможет NGINX корректно передавать такие заголовки, как X-Forwarded-Host, X-Forwarded-Proto и другие, что может згладить такие проблемы как протокол или обработка хоста, когда ваш Flask-приложение находится за прокси.

3. Логи NGINX

Проанализируйте логи NGINX. Из вашего примера видно, что NGINX пытается найти файлы в указанной директории HTML на сервере, вместо проксирования этих запросов на Flask-приложение. Проверьте, что конфигурация NGINX корректна и действительно проксирует запросы, а не пытается их обрабатывать как статические файлы.

Пример правильной настройки:
location /source_status/ {
    proxy_pass http://localhost:8080/;
    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;
}

Эта конфигурация гарантирует, что запросы проксируются к Flask-сервису, находящемуся на localhost:8080, и отправляются с корректными заголовками клиента.

4. Проверка SSL/HTTPS

Проверьте настройки SSL, так как они могут повлиять на маршрутизацию, особенно если NGINX перенаправляет HTTP на HTTPS. Убедитесь, что ваш клиентский код учитывает строгие настройки CORS и корректно устанавливает протоколы передачи данных.

Заключение

Ваше понимание того, как Flask и NGINX взаимодействуют, поможет вам не только в корректном решении текущих проблем, но и в развертывании аналогичных проектов в будущем. Продолжайте экспериментировать с конфигурацией и анализировать логи, это поможет вам осознать корневую проблему и выбрать наилучшее решение. Если после всех исправлений проблема остается, возможно, стоит рассмотреть тестирование различий в среде (например, локальная против производственной) и их влияния на ваше приложение.

Оцените материал
Добавить комментарий

Капча загружается...