Вопрос или проблема
Я запрограммировал веб-сервис, используя фреймворк 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 взаимодействуют, поможет вам не только в корректном решении текущих проблем, но и в развертывании аналогичных проектов в будущем. Продолжайте экспериментировать с конфигурацией и анализировать логи, это поможет вам осознать корневую проблему и выбрать наилучшее решение. Если после всех исправлений проблема остается, возможно, стоит рассмотреть тестирование различий в среде (например, локальная против производственной) и их влияния на ваше приложение.