Статические файлы Django не загружаются корректно в производстве с Apache

У меня возникли проблемы с обслуживанием статических файлов в приложении Django, развернутом на Apache. Несмотря на многочисленные руководства и предложения, я все еще сталкиваюсь с 404 ошибками для моих статических файлов. Ниже приведены соответствующие детали моей установки и проблемы, с которыми я сталкиваюсь.

Окружение:

Django Версия: 3.0 Версия Python: 3.8 Веб-сервер: Apache2 ОС: Ubuntu Описание проблемы:

В режиме разработки с DEBUG=True статические файлы загружаются корректно, и я могу видеть свою сборку React. Однако в режиме производства с DEBUG=False (или даже с Debug=True) я сталкиваюсь со следующими ошибками:

Ошибки

404 для файлов JavaScript и CSS Ошибки типа MIME, указывающие на то, что файлы обслуживаются как text/html вместо их правильных типов Ошибки в консоли браузера:


GET https://www.myapp.com/static/js/main.a14a4a4b.js net::ERR_ABORTED 404 (Not Found)
Refused to execute script from 'https://www.myapp.com/static/js/main.a14a4a4b.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
Refused to apply style from 'https://www.myapp.com/static/css/main.868dfa48.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
GET https://www.myapp.com/favicon.png 404 (Not Found)
GET https://www.myapp.com/manifest.json 404 (Not Found)
Manifest: Line: 1, column: 1, Syntax error.

Структура каталога:

Вот структура моего каталога staticfiles:

/var/www/jmyapp/staticfiles:
asset-manifest.json  css  favicon.png  index.html  js  logo192.png  logo512.png  manifest.json  media  robots.txt  sitemap.xml  static

/var/www/jmyapp/staticfiles/css:
main.868dfa48.css  main.868dfa48.css.map

/var/www/jmyapp/staticfiles/js:
main.a14a4a4b.js  main.a14a4a4b.js.LICENSE.txt  main.a14a4a4b.js.map

/var/www/jmyapp/staticfiles/media:
MyAppSwap.7be50f5ecb7b614c38c9.png  eth.df265e367364f285053a1285ad8d418d.svg

/var/www/jmyapp/staticfiles/static:
css  js  media

/var/www/jmyapp/staticfiles/static/css:
main.868dfa48.css  main.868dfa48.css.map

/var/www/jmyapp/staticfiles/static/js:
main.a14a4a4b.js  main.a14a4a4b.js.LICENSE.txt  main.a14a4a4b.js.map

/var/www/jmyapp/staticfiles/static/media:
MyAppSwap.7be50f5ecb7b614c38c9.png  eth.df265e367364f285053a1285ad8d418d.svg
settings.py:

import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
REACT_APP_DIR = os.path.join(BASE_DIR, 'myappswap', 'dex', 'build')


STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
    os.path.join(REACT_APP_DIR, "static"),
]

DEBUG = False


TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            os.path.join(BASE_DIR, 'templates'),
            REACT_APP_DIR,
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'mysite.wsgi.application'

Конфигурация Apache:

default-ssl.conf:

<IfModule mod_ssl.c>
    <VirtualHost _default_:443>
        ServerName www.myapp.com
        ServerAlias myapp.com

        DocumentRoot /var/www/jmyapp

        WSGIDaemonProcess mysite python-path=/var/www/jmyapp/mysite_env/lib/python3.8/site-packages
        WSGIProcessGroup mysite
        WSGIScriptAlias / /var/www/jmyapp/mysite/wsgi.py

        Alias /robots.txt /var/www/jmyapp/staticfiles/robots.txt
        Alias /favicon.ico /var/www/jmyapp/staticfiles/favicon.png
        Alias /static/ /var/www/jmyapp/staticfiles/
        Alias /media/ /var/www/jmyapp/media/

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        SSLEngine on
        SSLProtocol -ALL +TLSv1.2
        SSLCertificateFile /etc/letsencrypt/live/myapp.com/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/myapp.com/privkey.pem

        <IfModule mod_headers.c>
            <Location "/geconame/">
                SetEnvIf Origin "http(s)?://(www\.)?(localhost|www\.myapp\.com)$" ACAO=$0
                Header set Access-Control-Allow-Origin %{ACAO}e env=ACAO
                Header merge Vary Origin
            </Location>
        </IfModule>

        <FilesMatch "\.(cgi|shtml|phtml|php)$">
            SSLOptions +StdEnvVars
        </FilesMatch>
        <Directory /usr/lib/cgi-bin>
            SSLOptions +StdEnvVars
        </Directory>

        <Directory /var/www/jmyapp>
            Require all granted
        </Directory>

        <Directory /var/www/jmyapp/staticfiles>
            Require all granted
        </Directory>

        <Directory /var/www/jmyapp/media>
            Require all granted
        </Directory>

        <Directory /var/www/jmyapp/mysite>
            <Files wsgi.py>
                Require all granted
            </Files>
        </Directory>

        BrowserMatch "MSIE [2-6]" \
            nokeepalive ssl-unclean-shutdown \
            downgrade-1.0 force-response-1.0
    </VirtualHost>
</IfModule>

mysite.conf:

<VirtualHost *:80>
    ServerName www.myapp.com
    ServerAlias myapp.com
    ErrorLog /var/log/apache2/error.log
    CustomLog /var/log/apache2/access.log combined

    <IfModule mod_headers.c>
        <Location "/geconame/">
            SetEnvIf Origin "http(s)?://(www\.)?(localhost|www\.myapp\.com)$" ACAO=$0
            Header set Access-Control-Allow-Origin %{ACAO}e env=ACAO
            Header merge Vary Origin
        </Location>
    </IfModule>

    WSGIDaemonProcess jmyapp python-path=/var/www/jmyapp/mysite_env/lib/python3.8/site-packages
    WSGIProcessGroup jmyapp
    WSGIScriptAlias / /var/www/jmyapp/mysite/wsgi.py

    Alias /robots.txt /var/www/jmyapp/staticfiles/robots.txt
    Alias /favicon.ico /var/www/jmyapp/staticfiles/favicon.png
    Alias /static/ /var/www/jmyapp/staticfiles/
    Alias /media/ /var/www/jmyapp/media/

    <Directory /var/www/jmyapp>
        Require all granted
    </Directory>

    <Directory /var/www/jmyapp/staticfiles>
        Require all granted
    </Directory>

    <Directory /var/www/jmyapp/media>
        Require all granted
    </Directory>

    <Directory /var/www/jmyapp/mysite>
        <Files wsgi.py>
            Require all granted
        </Files>
    </Directory>

    <Directory /var/www/jmyapp/staticfiles>
        Require all granted
    </Directory>
</VirtualHost>

Конфигурация URLs:

main/urls.py:

from django.urls import path
from . import views
from django.contrib.staticfiles.storage import staticfiles_storage

app_name = 'main'

urlpatterns = [
    path('', views.mappage, name='mappage'),
    path('coins/<cryptoname>', views.coinspage, name='coinspage'),
    path('prices/<number>', views.prices, name='prices'),
    path('new_prices/<number>', views.new_prices, name='new_prices'),
    path('geconame/', views.get_coin, name='coin_name'),
    path('api/crypto-data/', views.crypto_data_api, name='crypto_data_api'),
    path('api/socialinfo/', views.socialinfo, name='socialinfo'),
    path('web3/tokenPrice/', views.token_price, name='token_price'),
    path('web3/dexSwap/', views.dex_swap, name='dex_swap'),
    path('web3/broadcastTransaction/', views.broadcast_transaction, name='broadcast_transaction'),
]

mysite/urls.py:

from django.contrib import admin
from django.urls import path, include
from django.views.generic import TemplateView
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('', include('main.urls')),
    path('admin/', admin.site.urls),
    path('blog/', include('blogs.urls')),
    path('swap/', TemplateView.as_view(template_name='index.html'), name='swap'),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

package.json:


"name": "dex",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@ant-design/icons": "^5.0.0",
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "antd": "^5.1.5",
    "axios": "^1.2.3",
    "browserify-zlib": "^0.2.0",
    "cors": "^2.8.5",
    "crypto-browserify": "^3.12.0",
    "ethers": "^5.7.2",
    "node-fetch": "^2.7.0",
    "os-browserify": "^0.3.0",
    "path-browserify": "^1.0.1",
    "querystring-es3": "^0.2.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.6.2",
    "react-scripts": "5.0.1",
    "stream-browserify": "^3.0.0",
    "url": "^0.11.3",
    "wagmi": "^0.10.11",
    "web-vitals": "^2.1.4",
    "web3": "^4.9.0",
    "yesno": "^0.4.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "eslint-config-airbnb": "^19.0.4",
    "eslint-plugin-import": "^2.29.1",
    "eslint-plugin-jsx-a11y": "^6.8.0",
    "eslint-plugin-react": "^7.34.2"
  },
  "proxy": "http://localhost:8000"
}

Взятые шаги:

Убедитесь, что права доступа к файлам правильные:

sudo chown -R www-data:www-data /var/www/jmyapp/staticfiles
sudo chmod -R 755 /var/www/jmyapp/staticfiles

Выполните команду collectstatic, чтобы собрать все статические файлы:

python manage.py collectstatic

Перезапуск Apache:

sudo systemctl restart apache2

Убедились, что файлы существуют в правильных каталогах.

Выпуск:

Даже после всех этих шагов статические файлы все еще не обслуживаются корректно в продакшене. Браузер пытается загрузить их с URL /static/, но они не найдены, что приводит к 404 ошибкам и проблемам с типом MIME. Я даже установил

<BrowserRouter basename="/">

Вопросы:

Почему статические файлы не обнаруживаются в производстве? Как решить проблему с типом MIME? Может быть, что-то не так с конфигурацией Apache или настройками Django? Любая помощь будет очень признательна.

Вернуться на верх