Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jakubjv's avatar

Node in one conteiner with composer?

Hi, I have a question. I’m developing an application where Laravel will serve as an API and I’m trying to create a Dockerfile. I’m considering using Soketi, which is installed via NPM. However, I’m not sure how to implement Soketi. In my Docker Compose setup, I have a service for Soketi, but the Laravel container does not have NPM, so I can’t install it there. Should I install Soketi only in the frontend container where I’ll have Nuxt.js? My goal is to avoid adding Node.js to the Docker image for Laravel, which will only serve as an API.

this is my dockerfile


# stage 1: build stage
FROM php:8.3-fpm-alpine as build

# installing system dependencies and php extensions
RUN apk add --no-cache \
    zip \
    libzip-dev \
    freetype \
    libjpeg-turbo \
    libpng \
    freetype-dev \
    libjpeg-turbo-dev \
    libpng-dev \
    nodejs \
    npm \
    && docker-php-ext-configure zip \
    && docker-php-ext-install zip pdo pdo_mysql \
    && docker-php-ext-configure gd --with-freetype=/usr/include/ --with-jpeg=/usr/include/ \
    && docker-php-ext-install -j$(nproc) gd \
    && docker-php-ext-enable gd \
    pecl install -o -f redis \
    &&  rm -rf /tmp/pear \
    &&  docker-php-ext-enable redis


# install composer
COPY --from=composer:2.7.6 /usr/bin/composer /usr/bin/composer

WORKDIR /var/www/html

# copy necessary files and change permissions
COPY . .
RUN chown -R www-data:www-data /var/www/html \
    && chmod -R 775 /var/www/html/storage \
    && chmod -R 775 /var/www/html/bootstrap/cache

# install php and node.js dependencies
RUN composer install --no-dev --prefer-dist \
    && npm install \
    && npm run build

RUN chown -R www-data:www-data /var/www/html/vendor \
    && chmod -R 775 /var/www/html/vendor

# stage 2: production stage
FROM php:8.3-fpm-alpine

# install nginx
RUN apk add --no-cache \
    zip \
    libzip-dev \
    freetype \
    libjpeg-turbo \
    libpng \
    freetype-dev \
    libjpeg-turbo-dev \
    libpng-dev \
    oniguruma-dev \
    gettext-dev \
    freetype-dev \
    nginx \
    && docker-php-ext-configure zip \
    && docker-php-ext-install zip pdo pdo_mysql \
    && docker-php-ext-configure gd --with-freetype=/usr/include/ --with-jpeg=/usr/include/ \
    && docker-php-ext-install -j$(nproc) gd \
    && docker-php-ext-enable gd \
    && docker-php-ext-install bcmath \
    && docker-php-ext-enable bcmath \
    && docker-php-ext-install exif \
    && docker-php-ext-enable exif \
    && docker-php-ext-install gettext \
    && docker-php-ext-enable gettext \
    && docker-php-ext-install opcache \
    && docker-php-ext-enable opcache \
    && rm -rf /var/cache/apk/*

# copy files from the build stage
COPY --from=build /var/www/html /var/www/html
COPY ./deploy/nginx.conf /etc/nginx/http.d/default.conf
COPY ./deploy/php.ini "$PHP_INI_DIR/conf.d/app.ini"

WORKDIR /var/www/html

# add all folders where files are being stored that require persistence. if needed, otherwise remove this line.
VOLUME ["/var/www/html/storage/app"]

CMD ["sh", "-c", "nginx && php-fpm"]

this is docker-compose.yml

version: '3.8'

services:
  laravel:
    restart: unless-stopped
    container_name: laravelapp
    build:
      context: ../
      dockerfile: ./deploy/Dockerfile
    # allocate as many volumes as necessary, if needed.
    volumes:
      - ./:/var/www
      - ../storage/app:/var/www/html/storage/app
    environment:
      APP_NAME: ${APP_NAME}
      APP_ENV: ${APP_ENV}
      APP_DEBUG: ${APP_DEBUG}
      APP_KEY: ${APP_KEY}
      APP_VERSION: ${APP_VERSION}
      APP_URL: ${APP_URL}
      DB_CONNECTION: mysql
      DB_HOST: database
      DB_PORT: 3306
      DB_DATABASE: ${DB_DATABASE}
      DB_USERNAME: ${DB_USERNAME}
      DB_PASSWORD: ${DB_PASSWORD}
      MAIL_MAILER: ${MAIL_MAILER}
      MAIL_HOST: ${MAIL_HOST}
      MAIL_PORT: ${MAIL_PORT}
      MAIL_USERNAME: ${MAIL_USERNAME}
      MAIL_PASSWORD: ${MAIL_PASSWORD}
      MAIL_ENCRYPTION: ${MAIL_ENCRYPTION}
      MAIL_FROM_ADDRESS: ${MAIL_FROM_ADDRESS}
      MAIL_FROM_NAME: ${MAIL_FROM_NAME}
    ports:
      - "8080:80"
    networks:
      - laravel-network
    depends_on:
      - database

  redis:
      image: redis:alpine
      container_name: redis
      restart: unless-stopped
      networks:
         - laravel-network
      ports:
          - "6379:6379"
      volumes:
          - ./:/var/www

  database:
    restart: unless-stopped
    image: mysql:latest
    volumes:
      - v-database:/var/lib/mysql
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_USER: ${DB_USERNAME}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
    networks:
      - laravel-network

  soketi:
      image: 'quay.io/soketi/soketi:latest-16-alpine'
      environment:
          SOKETI_DEBUG: '1'
          SOKETI_METRICS_SERVER_PORT: '9601'
          SOKETI_DEFAULT_APP_ID: '${PUSHER_APP_ID}'
          SOKETI_DEFAULT_APP_KEY: '${PUSHER_APP_KEY}'
          SOKETI_DEFAULT_APP_SECRET: '${PUSHER_APP_SECRET}'
      ports:
          - '${PUSHER_PORT:-6001}:6001'
          - '${SOKETI_METRICS_SERVER_PORT:-9601}:9601'
      networks:
          - laravel-network

volumes:
  v-database:


networks:
  laravel-network:
    driver: bridge

0 likes
1 reply

Please or to participate in this conversation.