Docker nginx php-fpm ошибка 404 при подключении css и js

Рейтинг: 0Ответов: 2Опубликовано: 05.03.2023

Пишу приложение на laravel, хочу чтоб админ панель была на шаблонах blade, а фронт на vue. Собираю все на докере, вроде даже нгинкс смог настроить, но в админке не подключаются скрипты и стили (net::ERR_ABORTED 404 (Not Found)).

Впервые настраиваю лемп сервер на докере, в нгинксе не силен, поэтому добавлю все все все возможные файлы и файловую систему(только основные файлы)

Файловая система

d: backend
    - d: _docker
        - d: app
            - f: Dockerfile
            - f: php.ini
        - d: nginx
            - f: Dockerfile
            - d: conf.d
                 - f: nginx.conf
    - d: public
        - d: dist
        - symlink: plugins
        - f: index.php
d: frontend
    - f: nginx.conf
    - f: Dockerfile
f: docker-compose.yml

docker-compose.yml

version: '3'

services:
  nginx:
    build: 
      context: ./backend
      dockerfile: _docker/nginx/Dockerfile
    volumes:
      - ./backend/_docker/nginx/conf.d/:/etc/nginx/conf.d/
    ports: 
      - "80:80"
    depends_on:
      - backend
      - frontend
    container_name: jundevs_nginx
    networks:
      - app-network

  backend:
    build: 
      context: ./backend
      dockerfile: _docker/app/Dockerfile
    volumes:
      - ./backend/:/var/www/
    depends_on:
      - db
    user: 1000:1000
    container_name: jundevs_backend
    networks:
      - app-network

  frontend:
    build: 
      context: ./frontend
      dockerfile: Dockerfile
    working_dir: /home/node/app
    volumes:
    - ./frontend:/home/node/app
    environment:
      NODE_ENV: development
    container_name: jundevs_frontend
    networks:
      - app-network

  db:
    image: postgres:15.2
    restart: always
    volumes:
      - ./backend/tmp/db:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: jundevs
      POSTGRES_USER: root
      POSTGRES_PASSWORD: root
      PGDATA: /var/lib/postgresql/data/pgdata
      POSTGRES_INITDB_ARGS: '--encoding=UTF-8'
    ports:
      - "5432:5432"
    container_name: jundevs_db
    networks:
      - app-network

  adminer:
    image: adminer:4
    restart: always
    ports:
      - 8888:8888
    container_name: jundevs_db_adminer
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

Dockerfile nginx

FROM nginx:stable-alpine

COPY ./conf.d/nginx.conf /etc/nginx/conf.d/default.conf
RUN mkdir /app
COPY ../../public /app

Nginx.conf для backend сервера (думаю что где-то вот здесь то у меня и косяк)

upstream frontend {
    server frontend:3000;
}

upstream backend {
    server backend:9000;
}

server {
    listen 80;
    index index.php index.html;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/public;

    location / {
        proxy_pass http://frontend;
    }

    location ~ ^/(api|admin)/ {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
    }

    location ~ ^/(dist|plugins)/ {
        alias /app;
        autoindex on;
        log_not_found off; # не логируем, если файл со статикой не найден

        # директивы ниже по желанию (опционально)
        expires 90d; # кэшируем браузером на 90 дней
        gzip on; # активируем динамическое сжатие статики

        # указываем какой тип статики сжимать (фильтр). 
        # В данном случае, это текст, css, js
        gzip_types text/plain text/css application/x-javascript text/javascript;

        # если рядом с файлом статики будет расположен его сжатый вариант .gz, 
        # то отдаст сразу его без сжатия (экономия ресурсов сервера).
        # Как вариант - использовать для сжатия gulp + плагин gulp-gzip
        gzip_static on;
        gzip_http_version 1.1;
        gzip_comp_level 8;
    }

    # Nginx Pass requests to PHP-FPM
    location ~ \.php$ {
        # try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass backend;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

Dockerfile php-fpm

FROM php:8.1.16-fpm

RUN apt-get update && apt-get install -y \
      apt-utils \
      libpq-dev \
      libpng-dev \
      libzip-dev \
      zip unzip \
      git && \
      docker-php-ext-install pdo && \
      docker-php-ext-install pdo_pgsql && \
      docker-php-ext-install pgsql && \
      docker-php-ext-install bcmath && \
      docker-php-ext-install gd && \
      docker-php-ext-install zip && \
      apt-get clean && \
      rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

COPY ./_docker/app/php.ini /usr/local/etc/php/conf.d/php.ini

# Install composer
ENV COMPOSER_ALLOW_SUPERUSER=1
RUN curl -sS https://getcomposer.org/installer | php -- \
    --filename=composer \
    --install-dir=/usr/local/bin

WORKDIR /var/www

# Copy existing application directory contents to the working directory
COPY . /var/www

# Assign permissions of the working directory to the www-data user
RUN chown -R www-data:www-data \
    /var/www/storage \
    /var/www/bootstrap/cache \
    /var/www/public

EXPOSE 9000
CMD ["php-fpm"]

Dockerfile vue frontend

FROM node:lts-alpine3.17 as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY ./ .
RUN npm run build

FROM nginx:stable-alpine
EXPOSE 3000
RUN mkdir /app
COPY /nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build-stage /app/dist /app

Nginx для frontend

server {
  listen 3000;

  location / {
    root /app;
    index index.html index.htm;
    try_files $uri $uri/ /index.html;
  }
}

Ошибки подключения файлов

errors screenshot

Ответы

▲ 1Принят

Я понятия не имею что именно привело к успеху, но я просто выложу готовый вариант. Возможно это кому-то поможет. После последнего изменения я перезагрузил браузер с очисткой кэша (cntl + f5) и все заработало. Знай я это раньше то я бы только так и перезагружал.

Структура папок осталась прежней (см. заданный вопрос)

Docker-compose.yml

version: '3'

services:
  nginx:
    image: nginx:stable-alpine
    volumes:
      - ./backend/_docker/nginx/conf.d/:/etc/nginx/conf.d/
      - ./backend/:/var/www
    ports: 
      - "80:80"
    depends_on:
      - backend
      - frontend
    container_name: jundevs_nginx
    networks:
      - app-network

  backend:
    build: 
      context: ./backend
      dockerfile: _docker/app/Dockerfile
    volumes:
      - ./backend/:/var/www/
    depends_on:
      - db
    user: "1000:1000"
    container_name: jundevs_backend
    networks:
      - app-network

  frontend:
    build: 
      context: ./frontend
      dockerfile: Dockerfile
    working_dir: /home/node/app
    volumes:
    - ./frontend:/home/node/app
    environment:
      NODE_ENV: development
    container_name: jundevs_frontend
    networks:
      - app-network

  db:
    image: postgres:15.2
    restart: always
    volumes:
      - ./backend/tmp/db:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: jundevs
      POSTGRES_USER: root
      POSTGRES_PASSWORD: root
      PGDATA: /var/lib/postgresql/data/pgdata
      POSTGRES_INITDB_ARGS: '--encoding=UTF-8'
    ports:
      - "5432:5432"
    container_name: jundevs_db
    networks:
      - app-network

  adminer:
    image: adminer:4
    restart: always
    ports:
      - 8888:8888
    container_name: jundevs_db_adminer
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

Nginx.conf backend

upstream frontend {
    server frontend:3000;
}

server {
    listen 80;
    index index.php index.html;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/public;

    location / {
        proxy_pass http://frontend;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass backend:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    location ~ ^/(api|admin|dist|plugins)/ {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
    }
}

Dockerfile php-fpm

FROM php:8.1.16-fpm

# Copy composer.lock and composer.json
COPY composer.lock composer.json /var/www/

# Set working directory
WORKDIR /var/www

# Install dependencies
RUN apt-get update && apt-get install -y \
      apt-utils \
      libpq-dev \
      libpng-dev \
      libzip-dev \
      zip unzip \
      git && \
      docker-php-ext-install pdo && \
      docker-php-ext-install pdo_pgsql && \
      docker-php-ext-install pgsql && \
      docker-php-ext-install bcmath && \
      docker-php-ext-install gd && \
      docker-php-ext-install zip && \
      apt-get clean && \
      rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Add user for laravel application
RUN groupadd -g 1000 www
RUN useradd -u 1000 -ms /bin/bash -g www www

# Copy existing application directory contents
COPY . /var/www

# Copy existing application directory permissions
COPY --chown=www:www . /var/www

# Change current user to www
USER www

# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]

Nginx frontend (остался прежним, но продублирую)

server {
  listen 3000;

  location / {
    root /app;
    index index.html index.htm;
    try_files $uri $uri/ /index.html;
  }
}

Dockerfile node (остался прежним, но продублирую)

FROM node:lts-alpine3.17 as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY ./ .
RUN npm run build

FROM nginx:stable-alpine
EXPOSE 3000
RUN mkdir /app
COPY /nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build-stage /app/dist /app
▲ 0

Первое, что мне бросилось в глаза, это отсутствие конфиг файла nginx в backend. Мне пока что не очень понятно как вы планируете разрабатывать приложение, но наличие балансировки на два сервера (на php и на node), кажется излишним, но возможно, так и надо и вы знаете что делаете. На мой взгляд, должно выбираться что-то одно. Если это у вас два отдельных приложения, то ок. А если это одно приложение, то вы можете спокойно обойтись без frontend, так как для работы с node, вам придётся пилить отдельный api (на сколько я понимаю, вы так планируете это делать). Но подозреваю, что у вас всё api будет на laravel (то есть на php). Фронт часть можно спокойно делать на vue без node, если не планируете делать отдельное api для админки.

d: backend
    - d: _docker
        - d: app
            - f: Dockerfile
            - f: php.ini
        - d: nginx
            - f: Dockerfile
            - f: nginx.conf # Здесь у вас этого файла нет, а должен быть
    - d: public
        - d: dist
        - symlink: plugins
        - f: index.php
d: frontend
    - f: nginx.conf
    - f: Dockerfile
f: docker-compose.yml

Если смотреть на docker-compose, то у вас там тоже должен быть файл. Возможно, просто ваша опечатка.

nginx:
    ...
    volumes:
      - ./backend/_docker/nginx/conf.d/:/etc/nginx/conf.d/
    ...

А на frontend-е как раз быть не должно:

frontend:
    ...
    volumes:
    - ./frontend:/home/node/app # здесь нет /nginx/conf.d
    ...

Но учитывая, что вы далее описываете nginx конфиг для frontend, судя по всему вы его ожидаете.

Обратите внимание, что наружу у вас для frontend сервера пробрасывается порт 3000. И по nginx вы прослушиваете именно его: listen 3000.

Тут, на сколько я понимаю, статику вы планируете хранить на backend сервере. Её можно отдать так:

location / {
try_files $uri $uri/ /index.php?$query_string;
}

P.S.: Если вы только начинаете делать приложение, обратите внимание на то, что в laravel есть уже свой готовый docker-compose и специально приложения (sail: https://laravel.com/docs/9.x/sail) для управления им (в docker вообще лезть не придётся).