Skip to content

Docker: production RoadRunner image for GHCR, linux/amd64 only#9

Merged
karabayyazilim merged 9 commits intomasterfrom
copilot/create-docker-setup-roadrunner
Feb 20, 2026
Merged

Docker: production RoadRunner image for GHCR, linux/amd64 only#9
karabayyazilim merged 9 commits intomasterfrom
copilot/create-docker-setup-roadrunner

Conversation

Copy link
Contributor

Copilot AI commented Feb 20, 2026

Adds a production Docker setup using RoadRunner as the app server, published to GHCR via GitHub Actions on push to master or v*.*.* tags.

New files

  • Dockerfile — 4-stage build: node:20-alpine (Vite/React) → composer:2 (vendor) → roadrunner:2024 (rr binary) → php:8.3-cli-alpine (production). Uses mlocati/php-extension-installer for pre-compiled extension binaries instead of compiling from source.
  • .rr.yaml — RoadRunner config: HTTP on 0.0.0.0:8080, gzip + static middleware, JSON production logs to stderr.
  • .dockerignore — excludes .git, .env*, node_modules, vendor, runtime caches, tests/.
  • .github/workflows/docker-publish.yml — single ubuntu-latest job, linux/amd64 only, GHA layer cache, pushes to ghcr.io/codenteq/eventeq.

composer.json

Added laravel/octane: ^2.0 (required by octane:start --server=roadrunner) and regenerated composer.lock via composer require.

Build issues resolved

Error Fix
laravel/octane not in lock file Ran composer require laravel/octane:^2.0 to sync composer.lock
composer:2 ships PHP 8.5, breaks nette/schema (caps at 8.4) Added --ignore-platform-reqs to composer commands
linux/sock_diag.h: No such file or directory building sockets on Alpine install-php-extensions handles kernel headers automatically
Original prompt

Objective

Create a production-ready Docker setup using RoadRunner as the application server for the Laravel + Inertia.js + React.js eventeq project. The Docker image should be published to GitHub Container Registry (GHCR) automatically via GitHub Actions, and be deployable on Dokploy.

Required Files

1. Dockerfile (root of the repo — replace/override the existing Sail-based Dockerfiles)

A multi-stage production Dockerfile with 4 stages:

Stage 1 — Frontend Build (node:20-alpine):

  • Copy package.json, package-lock.json*, yarn.lock*
  • Install JS dependencies (yarn install --frozen-lockfile if yarn.lock exists, else npm ci if package-lock.json exists, else npm install)
  • Copy resources/, vite.config.js, postcss.config.js*, tailwind.config.js*
  • Run npm run build to compile React/CSS assets via Vite

Stage 2 — Composer Dependencies (composer:2):

  • Copy composer.json and composer.lock
  • Run composer install --no-dev --no-interaction --no-scripts --no-autoloader --prefer-dist
  • Copy the full app source
  • Run composer dump-autoload --optimize --no-dev

Stage 3 — RoadRunner Binary:

  • Use ghcr.io/roadrunner-server/roadrunner:2024 to get the rr binary

Stage 4 — Production Image (php:8.3-cli-alpine):

  • Labels: maintainer=codenteq, org.opencontainers.image.source, org.opencontainers.image.description
  • Install system deps & PHP extensions: pdo_mysql, pdo_pgsql, pgsql, gd (with freetype+jpeg), zip, bcmath, intl, xml, mbstring, soap, pcntl, sockets, redis (pecl), imagick (pecl)
  • Use php.ini-production
  • Custom PHP settings: memory_limit=256M, upload_max_filesize=64M, post_max_size=64M, max_execution_time=120, opcache enabled with validate_timestamps=0
  • WORKDIR /var/www/html
  • Copy RoadRunner binary from stage 3 to /usr/local/bin/rr
  • Copy vendor from composer stage, app source, and built frontend assets from frontend stage
  • Create storage/logs, storage/framework/sessions, storage/framework/views, storage/framework/cache/data, bootstrap/cache directories
  • Set ownership to www-data and permissions 775 on storage and bootstrap/cache
  • Copy .rr.yaml config
  • EXPOSE 8080
  • HEALTHCHECK on http://localhost:8080/up
  • Run as USER www-data
  • CMD: config:cache, route:cache, view:cache, migrate --force, then rr serve -c /var/www/html/.rr.yaml

2. .rr.yaml (root of the repo)

RoadRunner configuration:

version: "3"

server:
  command: "php artisan octane:start --server=roadrunner --host=0.0.0.0 --port=8080 --workers=auto --max-requests=1000 --rpc-port=6001"
  relay: pipes

http:
  address: "0.0.0.0:8080"
  middleware:
    - gzip
    - static
  static:
    dir: "/var/www/html/public"
    forbid:
      - ".php"
      - ".htaccess"
    response:
      X-Request-ID: ""
  pool:
    num_workers: 0
    max_jobs: 1000
    allocate_timeout: 60s
    destroy_timeout: 60s
    supervisor:
      max_worker_memory: 128

logs:
  mode: production
  level: warn
  encoding: json
  output: stderr

status:
  address: "0.0.0.0:2114"

reload:
  interval: 1s
  patterns: [".php"]
  services:
    http:
      recursive: true
      dirs: ["/var/www/html"]

3. .dockerignore (root of the repo)

.git
.github
.gitignore
.env
.env.example
.editorconfig
node_modules
vendor
storage/logs/*
storage/framework/cache/*
storage/framework/sessions/*
storage/framework/views/*
bootstrap/cache/*
docker
tests
phpunit.xml
README.md
*.md
.vscode
.idea
.DS_Store
Thumbs.db

4. .github/workflows/docker-publish.yml

GitHub Actions workflow:

  • Trigger: push to master branch, tags matching v*.*.*, and pull requests to master
  • Registry: ghcr.io
  • Image name: ${{ github.repository }} (i.e., codenteq/eventeq)
  • Permissions: contents: read, packages: write
  • Steps:
    1. Checkout
    2. Set up Docker Buildx
    3. Login to GHCR (skip on PR)
    4. Extract metadata with docker/metadata-action (tags: ref/branch, semver patterns, sha prefix, latest on default branch)
    5. Build and push with docker/build-push-action (push only on non-PR, with GHA cache, platforms: linux/amd64 and linux/arm64)

5. Add laravel/octane dependency

Add "laravel/octane": "^2.0" to the require section of composer.json since RoadRunner requires Laravel Octane.

Important Notes

  • The existing Dockerfiles under docker/8.x/ are Laravel Sail development Dockerfiles — they should NOT be modified. The new production Dockerfile goes in the project root.
  • The project uses PHP ^8.2 (target 8.3 for production image), Laravel 11, Inertia.js with React, Vite for frontend bundling.
  • Entry points for Vite are resources/css/app.css and resources/js/app.jsx.
  • The image will be deployed on Dokploy, exposed on port 8080.

This pull request was created from Copilot chat.


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

…eact

Co-authored-by: karabayyazilim <45515180+karabayyazilim@users.noreply.github.com>
@karabayyazilim karabayyazilim marked this pull request as ready for review February 20, 2026 19:12
Copilot AI changed the title [WIP] Create production-ready Docker setup with RoadRunner for Laravel app Add production Docker setup with RoadRunner for Laravel + Inertia + React Feb 20, 2026
Copilot AI requested a review from karabayyazilim February 20, 2026 19:13
Co-authored-by: karabayyazilim <45515180+karabayyazilim@users.noreply.github.com>
Copilot AI changed the title Add production Docker setup with RoadRunner for Laravel + Inertia + React Fix Docker build: add laravel/octane to composer.lock Feb 20, 2026
…ma platform requirement

Co-authored-by: karabayyazilim <45515180+karabayyazilim@users.noreply.github.com>
Copilot AI changed the title Fix Docker build: add laravel/octane to composer.lock Fix Docker build: pin composer stage to PHP 8.4 Feb 20, 2026
…ad of nonexistent composer:2-php8.4

Co-authored-by: karabayyazilim <45515180+karabayyazilim@users.noreply.github.com>
Copilot AI changed the title Fix Docker build: pin composer stage to PHP 8.4 Fix Docker build: composer:2 + --ignore-platform-req=php Feb 20, 2026
…cks in composer stage

Co-authored-by: karabayyazilim <45515180+karabayyazilim@users.noreply.github.com>
Copilot AI changed the title Fix Docker build: composer:2 + --ignore-platform-req=php Fix Docker build: ignore all composer platform requirements in build stage Feb 20, 2026
…ion on Alpine

Co-authored-by: karabayyazilim <45515180+karabayyazilim@users.noreply.github.com>
Copilot AI changed the title Fix Docker build: ignore all composer platform requirements in build stage Fix production Docker build: linux-headers + composer platform reqs + composer.lock sync Feb 20, 2026
…lel arm64/amd64 builds

Co-authored-by: karabayyazilim <45515180+karabayyazilim@users.noreply.github.com>
Copilot AI changed the title Fix production Docker build: linux-headers + composer platform reqs + composer.lock sync Production Docker setup with RoadRunner: build fixes + performance optimizations Feb 20, 2026
Co-authored-by: karabayyazilim <45515180+karabayyazilim@users.noreply.github.com>
Copilot AI changed the title Production Docker setup with RoadRunner: build fixes + performance optimizations Docker: production RoadRunner image for GHCR, linux/amd64 only Feb 20, 2026
@karabayyazilim karabayyazilim merged commit 2f3b67a into master Feb 20, 2026
2 checks passed
Copilot stopped work on behalf of karabayyazilim due to an error February 20, 2026 20:14
Copilot AI added a commit that referenced this pull request Feb 20, 2026
…dency

Co-authored-by: karabayyazilim <45515180+karabayyazilim@users.noreply.github.com>
karabayyazilim added a commit that referenced this pull request Feb 20, 2026
Revert PR #9: Remove production RoadRunner Docker setup and laravel/octane
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants