• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 9+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Dockerizing and Orchestrating Legacy Laravel Systems on Modern OVH Infrastructure

Dockerizing and Orchestrating Legacy Laravel Systems on Modern OVH Infrastructure

Assessing Legacy Laravel Application Dependencies

Before embarking on containerization, a thorough audit of the legacy Laravel application’s dependencies is paramount. This involves identifying not only PHP package requirements but also system-level libraries, external services, and specific environment configurations that the application relies upon. For older Laravel versions (e.g., < 5.5), Composer's autoloading might be less sophisticated, and manual bootstrapping or specific PHP extensions could be critical. We need to catalog:

  • PHP version and required extensions (e.g., gd, redis, pdo_mysql).
  • System packages (e.g., imagemagick, unzip).
  • Database drivers and versions.
  • Caching mechanisms (e.g., Redis, Memcached).
  • Queue workers and their configurations.
  • Cron jobs and their execution context.
  • Environment variables and their sources (e.g., .env files, system variables).
  • External API integrations and their authentication methods.

This inventory forms the bedrock for constructing an accurate Dockerfile and understanding the orchestration requirements.

Crafting the Dockerfile for Legacy Laravel

The Dockerfile needs to be tailored to the specific Laravel version and its dependencies. For a typical legacy setup, we’ll aim for a multi-stage build to keep the final image lean. This example assumes PHP 7.x and common extensions. Adjust the PHP version and extensions based on your audit.

We’ll start with a base PHP image, install necessary system packages, copy application code, install Composer dependencies, and set up the entrypoint.

Base Image and System Dependencies

# Stage 1: Builder
FROM php:7.4-fpm AS builder

# Set working directory
WORKDIR /var/www/html

# Install system dependencies
RUN apt-get update && apt-get install -y \
    git \
    unzip \
    libzip-dev \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    libonig-dev \
    libxml2-dev \
    libssl-dev \
    libcurl4-openssl-dev \
    libzip-dev \
    imagemagick \
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) gd \
    && docker-php-ext-install pdo pdo_mysql zip exif pcntl bcmath opcache \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Copy application code
COPY . /var/www/html

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

# Clear cache
RUN rm -rf var/cache/* var/log/* bootstrap/cache/*

# Stage 2: Production Image
FROM php:7.4-fpm-alpine

# Set working directory
WORKDIR /var/www/html

# Install system dependencies for production
RUN apk update && apk add --no-cache \
    libzip \
    libpng \
    libjpeg-turbo \
    freetype \
    oniguruma \
    libxml2 \
    openssl \
    curl \
    imagemagick \
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) gd \
    && docker-php-ext-install pdo pdo_mysql zip exif pcntl bcmath opcache \
    && rm -rf /var/lib/apt/lists/*

# Copy compiled dependencies and application code from builder stage
COPY --from=builder /var/www/html /var/www/html

# Copy production .env file (or use build arguments/secrets)
COPY .env.production .env

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

# Expose port
EXPOSE 9000

# Define entrypoint
ENTRYPOINT ["php-fpm"]

Key Considerations:

  • PHP Version: Ensure the PHP version in the `FROM` instruction matches your legacy application’s requirements.
  • Extensions: The `docker-php-ext-install` and `docker-php-ext-enable` commands are crucial for enabling necessary PHP extensions. For Alpine-based images, you’ll use `apk add` for system libraries and `docker-php-ext-install` for PHP extensions.
  • Composer: Using a multi-stage build with a dedicated Composer image (`composer:latest`) ensures a clean installation of dependencies without bloating the final production image.
  • Environment Variables: The `.env.production` file is copied directly. In a real-world scenario, consider using Docker secrets or build arguments for sensitive information.
  • Permissions: Correctly setting ownership and permissions for `storage` and `bootstrap/cache` directories is vital for Laravel’s operation.
  • Alpine vs. Debian: The example shows both a Debian-based builder and an Alpine-based production image. Alpine images are significantly smaller but might have compatibility nuances with certain libraries.

Containerizing Supporting Services

Legacy Laravel applications often depend on external services like databases, caching layers, and queue workers. These also need to be containerized or managed externally. For simplicity and consistency, we’ll define them in a docker-compose.yml file.

Database (MySQL Example)

services:
  db:
    image: mysql:5.7
    container_name: legacy_laravel_db
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: your_root_password
      MYSQL_DATABASE: your_database_name
      MYSQL_USER: your_database_user
      MYSQL_PASSWORD: your_database_password
    ports:
      - "3306:3306"
    volumes:
      - db_data:/var/lib/mysql

# ... other services
volumes:
  db_data:

Notes:

  • Use a specific MySQL version (e.g., 5.7) if your legacy app has strict compatibility requirements.
  • Environment variables are used to configure the database.
  • A named volume (`db_data`) is used for persistent storage of database files.

Caching (Redis Example)

services:
  # ... db service
  redis:
    image: redis:5
    container_name: legacy_laravel_redis
    restart: always
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data

# ... other services
volumes:
  # ... db_data
  redis_data:

Notes:

  • Redis 5 is a common choice for older Laravel versions.
  • A named volume (`redis_data`) ensures cache persistence if needed (though often not desired for cache).

Queue Worker

The queue worker needs to run as a separate process. This can be achieved by defining a new service in docker-compose.yml that uses the same application image but with a different command.

services:
  # ... db, redis services
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: legacy_laravel_app
    restart: always
    ports:
      - "8000:80" # For web server, if applicable
    volumes:
      - .:/var/www/html
    depends_on:
      - db
      - redis
    environment:
      DB_HOST: db
      DB_PORT: 3306
      REDIS_HOST: redis
      REDIS_PORT: 6379
      APP_ENV: production
      # ... other environment variables

  queue_worker:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: legacy_laravel_queue_worker
    restart: always
    volumes:
      - .:/var/www/html
    depends_on:
      - db
      - redis
    command: >
      php artisan queue:work
      --tries=3
      --sleep=5
      --timeout=60
      --queue=default,high
    environment:
      DB_HOST: db
      DB_PORT: 3306
      REDIS_HOST: redis
      REDIS_PORT: 6379
      APP_ENV: production
      # ... other environment variables

Notes:

  • The `app` service will typically run PHP-FPM for web requests.
  • The `queue_worker` service uses the same application image but overrides the `ENTRYPOINT` with `php artisan queue:work`.
  • Adjust the `command` arguments for `queue:work` based on your application’s needs (e.g., number of tries, sleep intervals, queues).
  • Ensure environment variables correctly point to the service names (e.g., `DB_HOST: db`).

Orchestration with Docker Compose on OVHcloud

OVHcloud offers various solutions for deploying Dockerized applications, from bare-metal servers to managed Kubernetes services. For simplicity and direct control, deploying on an OVHcloud Dedicated Server or Public Cloud instance with Docker installed is a common approach. We’ll use docker-compose for orchestration.

Deployment Steps on an OVHcloud Instance

  • Provision an OVHcloud Instance: Choose a suitable Public Cloud instance or Dedicated Server. Ensure it has sufficient CPU, RAM, and disk space.
  • Install Docker and Docker Compose: Connect to your instance via SSH and install Docker and Docker Compose.
# Install Docker (example for Ubuntu)
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io

# Install Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo docker-compose --version

Note: The Docker Compose version (1.29.2 in this example) should be checked for the latest stable release.

Deploying the Application

1. Transfer Files: Copy your Laravel application code, Dockerfile, and docker-compose.yml to the OVHcloud instance. A common method is using scp or Git.

# On your local machine
scp -r /path/to/your/laravel/app user@your_ovh_ip:/home/user/legacy_laravel

2. Navigate and Build: SSH into your OVHcloud instance, navigate to the application directory, and start the services.

# On the OVHcloud instance
cd /home/user/legacy_laravel
docker-compose up -d --build

The -d flag runs containers in detached mode, and --build ensures the Docker images are built from your Dockerfile.

Managing and Monitoring

Once deployed, you’ll use docker-compose commands to manage the stack:

# View running containers
docker-compose ps

# View logs for all services
docker-compose logs -f

# Stop all services
docker-compose down

# Restart a specific service
docker-compose restart app

# Execute a command inside a container (e.g., Artisan command)
docker-compose exec app php artisan cache:clear

For more advanced monitoring and logging, consider integrating with OVHcloud’s monitoring tools or deploying a dedicated logging stack (e.g., ELK or Grafana/Prometheus) that can collect logs and metrics from your Docker containers.

Nginx as a Reverse Proxy

While PHP-FPM is running inside the container, you’ll typically want Nginx running either on the host or within another container to act as a reverse proxy, handle SSL termination, serve static assets, and manage incoming traffic. Here’s an example of an Nginx configuration to proxy requests to the PHP-FPM container.

Nginx Configuration (within a container or on host)

server {
    listen 80;
    server_name your_domain.com; # Replace with your domain

    root /var/www/html/public; # Assuming your public directory is here

    index index.php index.html index.htm;

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

    location ~ \.php$ {
        # Ensure the fastcgi_pass directive points to your PHP-FPM container's IP/port
        # If PHP-FPM is in a container named 'app' and exposed on port 9000
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # Serve static files directly
    location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|webp)$ {
        expires 30d;
        add_header Cache-Control "public";
    }

    # Deny access to hidden files
    location ~ /\. {
        deny all;
    }

    # Deny access to .env files
    location ~ /\.env {
        deny all;
    }
}

Integration with Docker Compose:

You can add an Nginx service to your docker-compose.yml. This Nginx container would then proxy requests to the `app` service (which runs PHP-FPM).

services:
  # ... db, redis, app, queue_worker services

  nginx:
    image: nginx:latest
    container_name: legacy_laravel_nginx
    ports:
      - "80:80" # Map host port 80 to container port 80
      - "443:443" # For SSL
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf # Mount your Nginx config
      - ./public:/var/www/html/public # Mount public directory for static assets
    depends_on:
      - app
    restart: always

# ... volumes

Important: Ensure the `fastcgi_pass` directive in your Nginx configuration correctly points to the PHP-FPM service. If your PHP-FPM service is named `app` in docker-compose.yml, `fastcgi_pass app:9000;` is correct. If Nginx is running on the host, you would typically map the PHP-FPM container’s port (e.g., 9000) to the host and configure Nginx to point to that host port.

Scaling and OVHcloud Specifics

For scaling legacy Laravel applications on OVHcloud:

  • Horizontal Scaling: For the web application (`app` service), you can increase the number of replicas using Docker Swarm or Kubernetes. On a single server with Docker Compose, you can’t easily scale horizontally. OVHcloud’s Managed Kubernetes Service (K8s) is the ideal platform for this.
  • Database Scaling: For databases, consider OVHcloud’s managed database services (e.g., Managed Databases for MySQL/PostgreSQL) which offer built-in replication and scaling capabilities, offloading management overhead.
  • Load Balancing: If running multiple instances of your web application, an OVHcloud Load Balancer (either software-based like HAProxy within a container, or a managed OVHcloud Load Balancer service) is essential to distribute traffic.
  • Persistent Storage: For stateful services like databases, ensure you are using persistent volumes. OVHcloud Public Cloud offers various block storage and object storage options that can be integrated with container orchestrators.
  • CI/CD Integration: Automate your build, test, and deployment pipeline using tools like GitLab CI, Jenkins, or GitHub Actions, targeting your OVHcloud infrastructure.

Containerizing legacy Laravel applications on modern infrastructure like OVHcloud provides significant benefits in terms of portability, scalability, and manageability. By carefully auditing dependencies, crafting robust Dockerfiles, and leveraging orchestration tools, you can modernize even older systems for production readiness.

Primary Sidebar

A little about the Author

Having 9+ Years of Experience in Software Development.
Expertised in Php Development, WordPress Custom Theme Development (From scratch using underscores or Genesis Framework or using any blank theme or Premium Theme), Custom Plugin Development. Hands on Experience on 3rd Party Php Extension like Chilkat, nSoftware.

Recent Posts

  • Step-by-Step: Diagnosing thread pools deadlock during concurrent ActiveRecord transaction processing on Linode Servers
  • Securing Your E-commerce APIs: Preventing SQL Injection (SQLi) in customized checkout queries in WooCommerce Implementations
  • Disaster Recovery 101: Architecting Auto-Failovers for MySQL and Ruby Deployments on Linode
  • High-Throughput Caching Strategies: Scaling MySQL for Perl Application APIs
  • Disaster Recovery 101: Architecting Auto-Failovers for DynamoDB and Laravel Deployments on DigitalOcean

Copyright © 2026 · Vinay Vengala