Troubleshooting Laravel CI/CD Pipelines: A DevOps Case Study

Troubleshooting Laravel CI/CD Pipelines: A DevOps Case Study

Introduction: When Laravel Assets Disappear in Deployment

Continuous Integration and Deployment (CI/CD) pipelines save developers countless hours, but when they break, debugging can be frustratingly complex. This case study documents a real-world troubleshooting journey that DevOps engineers and Laravel developers will find familiar.

My challenge: compiled assets were visible in local builds but missing on the production server after deployment. A seemingly simple issue that took a full day to resolve.

The Project Setup

My setup included:

  • Framework: Laravel application with Laravel Mix
  • CI/CD: Bitbucket Pipelines
  • Server: RunCloud-managed VPS
  • Asset Pipeline: NPM scripts building assets into “dist”
  • Environment: Separate staging and production environments

The Symptom: Empty “dist” Directory

Despite successful builds in our pipeline, our application’s dist directory on the staging server contained only a fonts folder—all other compiled assets (JS, CSS) were missing.

$ ls -l /home/runcloud/webapps/application/public/dist
total 4
drwxrwxr-x+ 2 runcloud runcloud 4096 Jun 20 13:06 fonts

Yet the pipeline logs showed a properly populated directory after the build step:

$ ls -l public/dist
total 32
drwxrwxrwx 2 root root 12288 Jun 20 13:05 chunks
drwxrwxrwx 2 root root 4096 Jun 20 13:05 css
drwxrwxrwx 3 root root 4096 Jun 20 13:05 fe-js
drwxrwxrwx 2 root root 4096 Jun 20 13:04 fonts
-rw-rw-rw- 1 root root 517 Jun 20 13:05 mix-manifest.json
drwxrwxrwx 3 root root 4096 Jun 20 13:05 sdk

What happened to my assets between build and deployment?

Phase 1: Environment Configuration

The .env Conundrum

Our first suspicion was the build environment. Laravel Mix requires certain environment variables (MIX_*) to properly build assets.

Problem: Environment variables in .env file were present on the server but not in the Bitbucket Pipeline.

Solution: Add environment variables to the build step:

- echo "MIX_MEDIA=$MIX_MEDIA_STAGING" >> .env
- echo "MIX_URL=$MIX_URL_STAGING" >> .env

# More environment variables...

Lesson: CI/CD environments need the same build-time variables as local development.

Phase 2: SSH and Rsync Configuration

Deployment required SSH keys and proper rsync commands. I encountered several issues:

  1. SSH Authentication: Keys needed to be generated and added to Bitbucket
  2. Rsync Missing: The deployment container didn’t have rsync installed
  3. Permission Issuesrsync with default flags changed permissions

Solution:

- apt-get update && apt-get install -y rsync openssh-client
- rsync -avz --no-perms --no-owner --no-group --delete […]

Lesson: Always use --no-perms --no-owner --no-group flags with rsync in CI/CD to preserve server permissions.

Phase 3: Multi-Container Pipeline Architecture

After addressing environment and SSH issues, we still had missing assets. The breakthrough came when we examined Bitbucket Pipelines architecture.

The Critical Discovery: Bitbucket Pipelines runs each step in a separate container with its own filesystem. Files don’t persist between steps unless explicitly defined as artifacts.

My pipeline had separate steps for:

  1. Building assets with Node.js
  2. Deploying with PHP

But the built assets weren’t being passed between containers!

Solution: Add artifacts to the build step:

- step:
name: Build for staging
# ... build commands ...
artifacts:
- public/**

Lesson: In multi-step pipelines, files don’t automatically persist between steps.

The Solution: Working Pipeline Configuration

My final working configuration included:

  1. Environment variables properly passed to the build step
  2. SSH and rsync properly configured
  3. Artifacts to pass built assets between pipeline steps
  4. Debugging commands to verify files at each stage
- step:
name: Build for staging
image: node:23.5.0
script:
- npm install
# Environment variables
- echo "MIX_MEDIA=$MIX_MEDIA_STAGING" >> .env
# ... more env vars ...
- npm run build
- ls -l public/dist # Verify build output
artifacts:
- public/**

Followed by proper deployment:

- step:
name: Deploy to staging
script:
- apt-get update && apt-get install -y rsync openssh-client
- ls -l public/dist # Verify artifacts were received
- rsync -avz --no-perms --no-owner --no-group --delete [...] public/ runcloud@server:/path/to/public/

Key Insights for DevOps Engineers

  1. Container Isolation: Each pipeline step is isolated—use artifacts to share files
  2. Environment Variables: Build environments need the same variables as development
  3. Rsync Options: Use --no-perms --no-owner --no-group to preserve server permissions
  4. Troubleshooting: Add commands like ls -l at each step to track file presence
  5. Deployment Strategy: For Laravel apps, consider separate syncs for public and the full application

Conclusion: DevOps Is Detective Work

This case study illustrates the complexity of modern web application CI/CD pipelines. What seemed like a simple deployment issue required investigating:

  • Build environments
  • SSH configuration
  • File transfer settings
  • Container architecture
  • File permissions

For teams implementing CI/CD for Laravel applications, understanding these elements is crucial for a smooth deployment pipeline.

Impressed by this solution?

I build scalable, custom solutions tailored for startups, founders, and digital teams. Let's explore how I can help your business grow.

⚠️ To maintain quality and avoid spam, I prefer working via Upwork or via a qualified inquiry form.