如何通过 Passenger/Nginx 在 Digital Ocean 上部署 Django/React/Webpack 应用程序

How to deploy Django/React/Webpack app on Digital Ocean through Passenger/Nginx

我正在尝试在 Digital Ocean droplet 上部署一个使用 Django/Redux/React/Webpack 构建的网络应用程序。我在部署服务器上使用 Phusion Passenger 和 Nginx。

我使用 create-react-app 构建了一个 Django 应用程序,它有一个使用 React/Redux 的前端和一个使用 django-rest-framework 的后端 api。我使用 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_wsgi.py:

设置了 Passenger
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.html https://www.phusionpassenger.com/library/walkthroughs/deploy/python/digital_ocean/nginx/oss/xenial/deploy_app.html https://www.phusionpassenger.com/library/deploy/wsgi_spec.html

我已经尝试将教程第 1 部分代码直接克隆到我的服务器上并按照 运行 的说明进行操作。我通过将 "proxy": "http://localhost:8000" 添加到 frontend/package.json 使其在服务器上运行。如果我 运行 带有 ./manage.py runserver --settings=ponynote.production_settings xxx.x.x.x:8000 的 Django 服务器,那么该应用程序会在 myserver: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 root 提供的页面现在似乎具有指向 js 文件的正确链接,例如 "text/javascript" src="/static/bundles/js/main.a416835a.js,但链接不起作用:预期的 js 不存在。Passenger 无法提供来自 static/bundles/js 的 js 文件,即使 Django 服务器可以找到它们。

非常感谢任何帮助或想法。

Create-react-app 对本地和生产环境有一个相当自以为是的设置。

在本地,运行宁 npm start 将 运行 一个 webpack-dev-server, which you would typically access on port 3000. It runs a local nodejs web server to serve the files. You can route requests to your local Django server via the proxy 设置。

值得注意的是,此时您的 React 应用程序和 Django 之间几乎没有或没有连接。如果您使用代理设置,连接这两个应用程序的唯一方法是通过端口将您的 React 应用程序未处理的任何请求路由到您的 Django 应用程序。

默认情况下,在 create-react-app 中(如您提到的教程中所述),在生产中您将 运行 npm run build 处理您的 create-react-app 文件进入静态 JS 和 CSS 文件,然后在 Django 中访问这些文件,如 static files any other Django app.

为了访问静态文件,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

文件名中添加了一个随机哈希值以确保 cache busting. This is where webpack-bundle-tracker and django-webpack-loader 出现。生成构建文件时,还会创建一个名为 manifest.json 的附带文件,列出为构建创建的文件。这是在 Webpack 中生成并由 django-webpack-loader 获取的,这样 Django 就可以知道要导入哪些文件。

可以在生产环境中 运行 nodejs 服务器,或者使用 server-side rendering,但是如果您遵循您提到的教程并使用 create-react-app 默认设置,那么运行宁 npm run build 和部署静态文件是最简单、最安全的选择。

除了部署 Python/Django 应用程序之外,您提到的任何 Passenger 部署链接中没有任何内容 - 您需要管理两个应用程序和部署才能将 Django 和 React 运行ning 作为服务器生产中。

请注意,您提到的教程涵盖了如何在生产环境中将构建文件导入 Django,但您需要确保 webpack-bundle-tracker, django-webpack-loader 和 Django 静态文件配置全部配置为协同工作。

缺少的关键设置是 Passenger 配置文件中的 'location' 设置。

虽然 Django 服务器提供静态文件,包括 React 应用程序的构建文件,但 Nginx 看不到任何静态文件,除了 'public' 目录中的那些。

因此,要将使用 Webpack 构建的 Django 应用程序部署到生产环境,您需要将这些文件告知 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 文件作为您应用程序的入口点。您需要一个 passenger_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()