Как развернуть приложение Django / React / Webpack в Digital Ocean через Passenger / Nginx

Я пытаюсь развернуть веб-приложение, созданное с помощью Django / Redux / React / Webpack, на капле Digital Ocean. Я использую Phusion Passenger и Nginx на сервере развертывания.

Я использовал create-response-app для создания приложения Django, у которого есть интерфейс, использующий React / Redux, и бэкэнд api, использующий django-rest-framework. Я построил интерфейс с помощью npm run build.

Приложение Django настроено на поиск файлов в папке frontend / build, и все работает как положено, включая аутентификацию. Он основан на этом руководстве: http://v1k45.com/blog/modern-django-part-1-setting-up-django-and-react/

В settings.py:

ALLOWED_HOSTS = ['*']

TEMPLATES = [
... 
       'DIRS': [
            os.path.join(BASE_DIR, 'frontend/build'),
        ],
...
]

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'frontend/build/static'),
]

На своей машине разработки я активирую виртуальную среду Python 3.6 и запускаю ./manage.py runserver, и приложение отображается по адресу localhost: 3000.

На сервере развертывания я клонировал файлы в папку в var / www / и построил интерфейс.

Я настроил Passenger в соответствии с документами с помощью файла passenger_wsgi.py:

import myapp.wsgi
application = myapp.wsgi.application

И файл wsgi.py находится в папке djangoapp ниже:

import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myapp.settings')
application = get_wsgi_application()

Документация по Passenger распространяется только на приложение, состоящее из одной части:

https://www.phusionpassenger.com/library/walkthroughs/start/python.htmlhttps://www.phusionpassenger.com/library/walkthroughs/deploy/python/digital_ocean/nginx/oss/xenial/deploy_app.htmlhttps://www.phusionpassenger.com/library/deploy/wsgi_spec.html

Я пробовал клонировать код учебной части 1 прямо на свой сервер и, следуя инструкциям, запустить его. Я заставил это работать на сервере, добавив "proxy": "http://localhost:8000" в frontend / package.json. Если я запускаю сервер Django с ./manage.py runserver --settings=ponynote.production_settings xxx.x.x.x:8000 , тогда приложение правильно обслуживается на моем сервере: 8000. Однако Passenger по-прежнему не обслуживает нужные файлы.

Я изменил wsgi.py, чтобы сказать следующее:

import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.production_settings")
application = get_wsgi_application()

Страница, обслуживаемая Passenger в корневом URL-адресе, теперь имеет правильные ссылки на файлы js, такие как "text / javascript" src = "/ static / bundles / js / main.a416835a.js, но ссылки не работают: ожидаемого js нет. Passenger не обслуживает файлы js из static / bundles / js, хотя сервер Django может их найти.

Очень благодарен за любую помощь или идеи.

Обычно файлы внешнего интерфейса создаются (в приложении create-response это делается при запуске npm run build), а затем включаются в Django через рабочий процесс staticfiles. Я прошел через это и обнаружил, что конфигурация django-webpack-loader немного неудобна - вам нужно убедиться, что после создания ваших файлов django ищет файл manifest.json и статические файлы в нужном месте.

Toby 06.12.2018 19:11

Django находится в нужном месте на сервере разработки, так разве это не значит, что он находится в нужном месте и на рабочем сервере? Расположение в settings.py является относительным и должно быть одинаково правильным в производственной среде.

Little Brain 06.12.2018 19:39

В качестве ответа я опубликовал более полное объяснение - сложно точно определить причину, по которой приложение React не отображается, но приведенный ниже ответ должен дать общее представление о том, почему в руководстве, которому вы следуете, рекомендуется делать то, что они делают.

Toby 06.12.2018 19:53
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
5
3
2 376
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Приложение Create-react-app имеет довольно оптимистичную настройку для локальных и производственных сред.

Локально при запуске npm start будет запущен webpack-dev-сервер, к которому вы обычно обращаетесь через порт 3000. Он запускает локальный веб-сервер nodejs для обслуживания файлов. Вы можете направлять запросы на локальный сервер Django с помощью параметра доверенное лицо.

Стоит отметить, что на данный момент связь между вашим приложением React и Django практически отсутствует. Если вы используете настройку прокси, единственное, что связывает два приложения, - это маршрутизация любых запросов, не обрабатываемых вашим приложением React, в ваше приложение Django через порт.

По умолчанию в приложении create-response-app (и, как указано в руководстве, которое вы упомянули, вы следуете), в производстве вы должны запустить npm run build, который преобразует ваши файлы приложения create-response-app в статические файлы JS и CSS, которые затем доступны в Django. как статические файлы любое другое приложение Django.

Одна вещь, которую Django не хватает для доступа к статическим файлам, - это способ узнать, какие файлы создаются при запуске npm run build. Запуск сборки обычно приводит к выходным файлам, подобным этому:

- css
   |- main.e0c3cfcb.css
   |- main.e0c3cfcb.css.map
- js
   |- 0.eb5a2873.chunk.js
   |- 0.eb5a2873.chunk.js.map
   |- 1.951bae33.chunk.js
   |- 1.951bae33.chunk.js.map

К именам файлов добавляется случайный хэш, чтобы гарантировать очистка кеша. Здесь на помощь приходят веб-пакет-трекер и django-webpack-загрузчик. При создании файлов сборки также создается сопутствующий файл с именем manifest.json, в котором перечислены файлы, созданные для сборки. Он генерируется в Webpack и подбирается django-webpack-loader, чтобы Django мог знать, какие файлы импортировать.

Можно запустить сервер nodejs в производстве или использовать рендеринг на стороне сервера, но если вы следуете упомянутому вами руководству и используете настройки по умолчанию для create-response-app, то запуск npm run build и развертывание статических файлов - самый простой и безопасный вариант. .

Ничто в упомянутых вами ссылках развертывания Passenger не касается чего-либо, кроме развертывания приложения Python / Django - вам нужно будет управлять двумя приложениями и развертываниями, чтобы и Django, и React работали как серверы в производственной среде.

Обратите внимание, что в указанном вами руководстве рассказывается, как загрузить файлы сборки в Django в производственной среде, но вам необходимо убедиться, что у вас есть веб-пакет-трекер, django-webpack-загрузчик и конфигурация статических файлов Django, настроенная для совместной работы.

Спасибо за ваше объяснение. Я считаю, что следую именно тому процессу, который вы предлагаете - я запустил npm run build на производственной машине, - но я не могу понять, почему статические файлы не обнаруживаются на производственном сервере. Они присутствуют в указанной папке, и я не изменил конфигурацию того, что работает на машине разработки, где я определенно нет запускает отдельное приложение для клиента, только основное приложение Django, которое находит статические файлы и обслужить их без проблем. В настоящее время я не могу думать, как исследовать это дальше.

Little Brain 06.12.2018 20:37

В браузере я вижу, что приложение загрузило два файла: build / static / js / 1.ab5b0163.chunk.js и build / static / js / main.53d060d0.chunk.js. Однако содержимое выглядит неправильно, каждое из них - это просто html. Соответствующие файлы, созданные на моей машине для разработки, содержат много сжатого JavaScript. Итак, я думаю, что с моим процессом сборки что-то не так.

Little Brain 06.12.2018 21:37

какой HTML в этих файлах?

Toby 06.12.2018 21:38

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

Little Brain 06.12.2018 21:48

Я настоятельно рекомендую создавать файлы локально и развертывать их для работы с остальной частью приложения Django. Я не уверен, почему файл js, созданный на сервере, включает HTML и всю кодовую базу, но это, очевидно, неправильно.

Toby 06.12.2018 22:15

Это похоже на гораздо лучший план. Я новичок в Django и не знаю, как правильно развернуть его в prod - я привык к Meteor, где вы просто создаете пакет и распаковываете его на сервере. Вы можете порекомендовать метод? Например. мне добавить файлы сборки в GitHub? Или есть хороший инструмент для прямого копирования приложения с локального на прод?

Little Brain 07.12.2018 12:37

Я скопировал файлы build / static с моего локального компьютера на сервер и открыл 1.xxx.chunk.js, чтобы убедиться, что он имеет то же содержимое, что и локальный файл. Однако браузер по-прежнему видит неправильный контент, который на самом деле является общедоступным файлом index.html, и я сделал жесткую перезагрузку. Кажется, что сервер обслуживает public / index.html вместо всех моих статических файлов?

Little Brain 07.12.2018 13:09

файл index.html из приложения create-response-app не используется в производстве - в prod у вас будет шаблон Django, который должен иметь ссылку внизу на файлы, созданные Webpack (через django-webpack-loader). Вы можете проверить файлы в GitHub, но если вы работаете с другими, они будут постоянным источником конфликтов слияния. В настоящее время моя команда использует Docker для управления средами и развертываниями.

Toby 07.12.2018 13:57

Позвольте нам продолжить обсуждение в чате.

Little Brain 07.12.2018 14:51
Ответ принят как подходящий

Ключевым отсутствующим параметром был параметр «местоположение» в конфигурационном файле Passenger.

Хотя сервер Django обслуживает статические файлы, включая файлы сборки для вашего приложения React, Nginx не видит никаких статических файлов, кроме тех, что находятся в «общедоступном» каталоге.

Итак, чтобы развернуть приложение Django, созданное с помощью Webpack, в рабочей среде, вам необходимо сообщить Nginx об этих файлах. Если вы используете Passenger, эти настройки, вероятно, находятся в отдельном файле конфигурации Passenger. «alias» - это команда, которую следует использовать в том случае, когда имя папки отличается от «static» (на которое указывают ссылки веб-страницы).

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

/etc/nginx/sites-enabled/myapp.conf

server {
    listen 80;
    server_name xx.xx.xx.xx;

    # Tell Passenger where the Python executable is
    passenger_python /var/www/myapp/venv36/bin/python3.6;

    # Tell Nginx and Passenger where your app's 'public' directory is
    # And where to find wsgi.py file
    root /var/www/myapp/myapp/myapp;

    # Tell Nginx where Webpack puts the bundle folder 
    location /static/ {
       autoindex on;
       alias /var/www/myapp/myapp/assets/;
    }

    # Turn on Passenger
    passenger_enabled on;
}

Passenger использует файл wsgi.py как точку входа в ваше приложение. Вам нужен файл пассажира_wsgi.py на один уровень выше файла wsgi.py. Это сообщает Пассажиру, где найти файл wsgi.py.

/var/www/myapp/myapp/passenger_wsgi.py

import myapp.wsgi
application = myapp.wsgi.application

/var/www/myapp/myapp/myapp/wsgi.py

Если вы используете отдельный файл production_settings.py, убедитесь, что он указан здесь.

import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.production_settings")
application = get_wsgi_application()

Другие вопросы по теме