Building laravel in multiple container environment

Docker is pretty new to me, so I’m not really sure what I’m doing wrong.

I’ve tried multiple approaches, which I’ll include below. I’ll give you the docker-compose and dockerfile first:

# docker-compose.yml
version: '3.7'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: php:8.2-fpm
    container_name: laravel_app
    working_dir: /var/www
    volumes:
      - /volume1/web:/var/www
      - laravel_app:/var/www
      - laravel_vendor:/var/www/vendor
      - laravel_node_modules:/var/www/node_modules
    ports:
      - "9000:9000" # Exposes PHP-FPM to be used by Nginx
    entrypoint: /bin/sh -c "
      cp .env.production .env &&
      chmod -R 775 /var/www/storage /var/www/bootstrap/cache &&
      chown -R www-data:www-data /var/www &&
      chmod +x /var/www/clear_allcache.sh &&
      /var/www/clear_allcache.sh &&
      php artisan key:generate &&
      php-fpm"
    # entrypoint: /bin/sh -c "chmod +x /var/www/clear_allcache.sh && /var/www/clear_allcache.sh && php-fpm"

  webserver:
    image: nginx:alpine
    container_name: laravel_nginx
    working_dir: /var/www
    volumes:
      - laravel_app:/var/www
      - laravel_vendor:/var/www/vendor
      - laravel_node_modules:/var/www/node_modules
      - /volume1/web/plaves/nginx.conf:/etc/nginx/conf.d/default.conf
      - /volume1/web/plaves/syno_ddns_cert:/etc/nginx/certs:ro
    ports:
      - "5443:443" # Exposes port 443 on your NAS through port 5443
    depends_on:
      - app

volumes:
  laravel_app:
  laravel_vendor:
  laravel_node_modules:

And the dockerfile:

# Stage 1: Build environment
FROM composer:2.5 AS build

# Set working directory
WORKDIR /var/www

COPY composer.json composer.json
COPY composer.lock composer.lock
COPY . .

# Install PHP dependencies
RUN composer install --no-dev --optimize-autoloader

# Stage 2: Build environment for Node.js dependencies
FROM node:22.11 AS node-build

# Set working directory
WORKDIR /var/www

# Copy package.json and package-lock.json
COPY package.json package-lock.json ./

# Install npm dependencies
RUN npm install

# Copy application files from the build stage
COPY --from=build /var/www /var/www

# Install npm dependencies and build assets
RUN npm run build

# Use the base PHP 8.2 FPM image
FROM php:8.2-fpm As php-fpm-build

# Set working directory
WORKDIR /var/www

# Install system dependencies and PHP extensions for Laravel
RUN apt-get update && apt-get install -y 
        git 
        unzip 
        libpng-dev 
        libjpeg62-turbo-dev 
        libfreetype6-dev 
        libonig-dev 
        libxml2-dev 
        zip 
        libcurl4-openssl-dev 
# Configure and install GD extension
    && docker-php-ext-configure gd --with-freetype --with-jpeg 
# Install additional PHP extensions
    && docker-php-ext-install -j$(nproc) 
        gd 
        bcmath 
        exif 
        pcntl 
    && apt-get clean && rm -rf /var/lib/apt/lists/*

# Copy application files from the build stage
COPY --from=node-build /var/www /var/www

# Remove /public/hot if it exists
RUN rm -rf /var/www/public/hot

# Copy and configure environment variables
COPY .env.production /var/www/.env

# Set permissions for storage and bootstrap/cache
RUN chmod -R 775 storage bootstrap/cache 
    && chown -R www-data:www-data /var/www

# Make the script executable
RUN chmod +x clear_allcache.sh 
    && sed -i 's/r$//' clear_allcache.sh

The clear_allcache.sh file just rebuilds all caches:

#!/bin/bash

php artisan config:clear
php artisan config:cache
php artisan event:clear
php artisan event:cache
php artisan route:clear
php artisan route:cache
php artisan view:clear
php artisan view:cache

# Set permissions for storage and bootstrap/cache
chmod -R 775 storage bootstrap/cache
chown -R www-data:www-data storage bootstrap/cache

From what I understand, split-build stages are subcontainers that don’t share changes apart from the mounted volume. So I copy each folder (vendor, node-modules) from build stage to build stage.
I know this works, because I managed to get the site up and running. But it had it’s issues, like not being able to do post requests.

This is where I’m at now:
The issue must be my mounting logic. I tried mounting /volume1/web directly to /var/www, but that might not work because not all changes are transferred to both containers, right?
So know I’m using shared mounts to make sure all changes are visible to both containers.

I’ve tried playing with this, but it always results in a 404 – file not found or a 403 – forbidden when I run the containers and visit the site.
Any suggestion is appreciated, even if that means throwing my progress in the bin 🙂

The build succeeds, and I can sh into both containers to verify the files are all there.
From laravel_nginx:

d---------    1 33       33             238 Dec  8 14:54 public
d---------    1 33       33              20 Dec  8 14:54 resources
d---------    1 33       33              90 Dec  8 14:54 routes
----------    1 33       33             329 Nov 26 21:23 set_permissions.sh
drwxrwxr-x    1 33       33              32 Dec  8 14:54 storage
drwxr-xr-x    1 33       33             476 Dec  1 17:38 vendor

And from laravel_app:

d--------- 1 www-data www-data    238 Dec  8 14:54  public
d--------- 1 www-data www-data     20 Dec  8 14:54  resources
d--------- 1 www-data www-data     90 Dec  8 14:54  routes
---------- 1 www-data www-data    329 Nov 26 21:23  set_permissions.sh
drwxrwxr-x 1 www-data www-data     32 Dec  8 14:54  storage
drwxr-xr-x 1 www-data www-data    476 Dec  1 17:38  vendor

bootstrap/cache:

drwxrwxr-x    1 33       33             134 Dec  8 15:10 cache
drwxrwxr-x 1 www-data www-data  134 Dec  8 15:10 cache

In case you want to look into it, here’s the build output from docker:

$ sudo docker-compose down; sudo docker-compose up -d --build
[+] Running 3/3
⠿ Container laravel_nginx  Removed                                                                                2.5s
⠿ Container laravel_app    Removed                                                                               15.7s
⠿ Network plaves_default   Removed                                                                                0.9s
[+] Building 739.7s (27/27) FINISHED
=> [internal] load build definition from Dockerfile                                                               1.3s
=> => transferring dockerfile: 29B                                                                                0.0s
=> [internal] load .dockerignore                                                                                  1.8s
=> => transferring context: 32B                                                                                   0.0s
=> [internal] load metadata for docker.io/library/php:8.2-fpm                                                     0.0s
=> [internal] load metadata for docker.io/library/composer:2.5                                                    3.0s
=> [internal] load metadata for docker.io/library/node:22.11                                                      4.3s
=> [internal] load build context                                                                                  3.1s
=> => transferring context: 151.41kB                                                                              0.9s
=> [build 1/6] FROM docker.io/library/composer:2.5@sha256:71e5a2761bee175e0ef866ebcaab2dbd4e460ca6da4e0a84fa11ca  0.0s
=> [php-fpm-build 1/8] FROM docker.io/library/php:8.2-fpm                                                       135.4s
=> [node-build 1/6] FROM docker.io/library/node:22.11@sha256:ec878c763e9fad09d22aae86e2edcb7a05b397dfe8411c16e  144.1s
=> => resolve docker.io/library/node:22.11@sha256:ec878c763e9fad09d22aae86e2edcb7a05b397dfe8411c16e2b90158d595e2  1.7s
=> => sha256:ec878c763e9fad09d22aae86e2edcb7a05b397dfe8411c16e2b90158d595e2ce 6.41kB / 6.41kB                     0.0s
=> => sha256:748cfe6211ab7422bd4a6597e93e45355e8e6baf5d4707887843522a0c6ea860 2.49kB / 2.49kB                     0.0s
=> => sha256:4424cf09130c419aafde9798c3ac35e0a906a2b173c482319e2bac9c0ca42b90 6.39kB / 6.39kB                     0.0s
=> => sha256:fdf894e782a221820acf469d425b802be26aedb5e5d26ea80a650ff6a974d488 48.50MB / 48.50MB                  30.4s
=> => sha256:551df7f94f9c131f2fec0e8063142411365f0a1c88b935b9fac22be91af227e0 64.39MB / 64.39MB                  34.8s
=> => sha256:5bd71677db44bb63b94de61b6f1f95d5540b4ba2d6a8a6bc4d19f422b25e0c2b 23.87MB / 23.87MB                   6.1s
=> => sha256:ce82e98d553dd62ca6a12bebfe83992ae9f9ae2748275e74b66a68cc094f868b 211.31MB / 211.31MB                42.8s
=> => extracting sha256:fdf894e782a221820acf469d425b802be26aedb5e5d26ea80a650ff6a974d488                          6.0s
=> => sha256:cd8cd1fac358b1e715594bbe9128429f444efb4453c30d706bc11b8332a74ebf 3.32kB / 3.32kB                    33.1s
=> => sha256:a626dd299f99240da9e4e632a1fca3035e0ca04c632cc624968306bd18fb771d 54.61MB / 54.61MB                  44.4s
=> => sha256:480cf7800ccb638f7049ba8b450e5dafccb825d97380e5863a11d661a766399b 1.25MB / 1.25MB                    36.6s
=> => sha256:6f76c9e452df20903e7da8bc4b270f474d3ef02555846fbd66d5ae21e4b2cf47 447B / 447B                        37.7s
=> => extracting sha256:5bd71677db44bb63b94de61b6f1f95d5540b4ba2d6a8a6bc4d19f422b25e0c2b                          2.0s
=> => extracting sha256:551df7f94f9c131f2fec0e8063142411365f0a1c88b935b9fac22be91af227e0                          7.7s
=> => extracting sha256:ce82e98d553dd62ca6a12bebfe83992ae9f9ae2748275e74b66a68cc094f868b                         23.3s
=> => extracting sha256:cd8cd1fac358b1e715594bbe9128429f444efb4453c30d706bc11b8332a74ebf                          3.2s
=> => extracting sha256:a626dd299f99240da9e4e632a1fca3035e0ca04c632cc624968306bd18fb771d                          7.5s
=> => extracting sha256:480cf7800ccb638f7049ba8b450e5dafccb825d97380e5863a11d661a766399b                          3.9s
=> => extracting sha256:6f76c9e452df20903e7da8bc4b270f474d3ef02555846fbd66d5ae21e4b2cf47                          0.6s
=> CACHED [build 2/6] WORKDIR /var/www                                                                            0.0s
=> CACHED [build 3/6] COPY composer.json composer.json                                                            0.0s
=> CACHED [build 4/6] COPY composer.lock composer.lock                                                            0.3s
=> [build 5/6] COPY . .                                                                                           8.8s
=> [build 6/6] RUN composer install --no-dev --optimize-autoloader                                               21.9s
=> [php-fpm-build 2/8] WORKDIR /var/www                                                                           4.3s
=> [php-fpm-build 3/8] RUN apt-get update && apt-get install -y         git         unzip         libpng-dev     84.4s
=> [node-build 2/6] WORKDIR /var/www                                                                              5.9s
=> [node-build 3/6] COPY package.json package-lock.json ./                                                        3.0s
=> [node-build 4/6] RUN npm install                                                                             416.7s
=> [node-build 5/6] COPY --from=build /var/www /var/www                                                           7.4s
=> [node-build 6/6] RUN npm run build                                                                            20.2s
=> [php-fpm-build 4/8] COPY --from=node-build /var/www /var/www                                                  11.1s
=> [php-fpm-build 5/8] RUN rm -rf /var/www/public/hot                                                             7.4s
=> [php-fpm-build 6/8] COPY .env.production /var/www/.env                                                         3.2s
=> [php-fpm-build 7/8] RUN chmod -R 775 storage bootstrap/cache     && chown -R www-data:www-data /var/www        5.8s
=> [php-fpm-build 8/8] RUN chmod +x clear_allcache.sh     && sed -i 's/r$//' clear_allcache.sh                   7.8s
=> exporting to image                                                                                            69.4s
=> => exporting layers                                                                                           34.1s
=> => writing image sha256:6a2203ce3493eeff1633120c29fec62415f6f2882dcb4576c5fb97e4b86d09dd                       0.1s
=> => naming to docker.io/library/php:8.2-fpm                                                                     0.1s
[+] Running 3/3
⠿ Network plaves_default   Created                                                                                1.3s
⠿ Container laravel_app    Started                                                                                8.6s
⠿ Container laravel_nginx  Started                                                                               10.8s

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật