Skip to main content
Deploy Zoo Arcadia in containerized environments using Docker for consistent development and production setups.

Prerequisites

Ensure you have Docker and Docker Compose installed:

Docker

Version 20.10 or higher

Docker Compose

Version 2.0 or higher
Verify installation:
docker --version
docker compose version

Architecture Overview

The Docker setup consists of three services:

Docker Compose Configuration

The docker-compose.yml defines the complete stack:
docker-compose.yml
version: '3.8'

services:
  # PHP + Apache Web Server
  web:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: zoo-arcadia-web
    ports:
      - "8080:80"
    volumes:
      - ./public:/var/www/html/public
      - ./App:/var/www/html/App
      - ./includes:/var/www/html/includes
      - ./config.php:/var/www/html/config.php
      - ./.env:/var/www/html/.env
    depends_on:
      - db
    environment:
      - DB_HOST=db
      - DB_NAME=zoo_arcadia
      - DB_USER=zoo_user
      - DB_PASS=zoo_password
    networks:
      - zoo-network

  # MariaDB Database
  db:
    image: mariadb:11.4
    container_name: zoo-arcadia-db
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: zoo_arcadia
      MYSQL_USER: zoo_user
      MYSQL_PASSWORD: zoo_password
    volumes:
      - mysql_data:/var/lib/mysql
      - ./database:/docker-entrypoint-initdb.d
    networks:
      - zoo-network
    command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

volumes:
  mysql_data:

networks:
  zoo-network:
    driver: bridge

Service Breakdown

Container: zoo-arcadia-web
  • Base Image: Custom Dockerfile (PHP 8.2 + Apache)
  • Port: 8080 (host) → 80 (container)
  • Volumes: Code directories mounted for live editing
  • Environment: Database credentials
The web container includes:
  • PHP extensions (GD, PDO MySQL, Zip)
  • Apache with mod_rewrite enabled
  • Composer dependencies
  • Node.js 18 for asset compilation

Dockerfile

The custom Dockerfile builds the web application container:
Dockerfile
# Base image: PHP 8.2 with Apache
FROM php:8.2-apache

# Install PHP extensions
RUN apt-get update && apt-get install -y \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    libzip-dev \
    unzip \
    git \
    curl \
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) gd pdo pdo_mysql zip \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# Install Node.js 18
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
    && apt-get install -y nodejs

# Enable Apache modules
RUN a2enmod rewrite headers

# Copy Apache configuration
COPY docker/apache-config.conf /etc/apache2/sites-available/000-default.conf

# Set working directory
WORKDIR /var/www/html

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

# Install PHP dependencies
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --no-interaction

# Install Node.js dependencies
COPY package.json package-lock.json ./
RUN npm ci --production=false

# Copy application files
COPY . .

# Build assets (CSS and JS)
RUN npx gulp buildCss || (npm run css || echo "Warning: CSS compilation failed") \
    && npx gulp buildJs || echo "Warning: JS build failed"

# Set permissions
RUN chown -R www-data:www-data /var/www/html \
    && chmod -R 755 /var/www/html

EXPOSE 80

CMD ["apache2-foreground"]

Getting Started with Docker

1

Configure Environment

Ensure you have the Docker-specific .env file:
cp .env.example .env
Or use the helper script (Windows):
switch-to-docker.bat
Key settings for Docker:
.env
DB_HOST=db  # Container name, not localhost
DB_NAME=zoo_arcadia
DB_USER=zoo_user
DB_PASS=zoo_password
2

Build Containers

Build the Docker images:
docker compose build
First build may take 5-10 minutes as it downloads base images and compiles assets.
3

Start Services

Start all containers:
docker compose up -d
The -d flag runs containers in detached mode (background).
4

Verify Services

Check container status:
docker compose ps
You should see:
NAME                STATUS      PORTS
zoo-arcadia-web     Up          0.0.0.0:8080->80/tcp
zoo-arcadia-db      Up          0.0.0.0:3306->3306/tcp
5

Access the Application

Open your browser to:
http://localhost:8080
The application should be running with a fully initialized database.

Accessing Services

Web Application

http://localhost:8080

Database Connection

Connect to MariaDB from your host machine:
mysql -h 127.0.0.1 -P 3306 -u zoo_user -p
# Password: zoo_password

Container Logs

View real-time logs:
docker compose logs -f

Volume Management

Docker uses volumes for persistent data and development:

Development Volumes (Bind Mounts)

These directories are mounted from your host machine for live editing:
Host PathContainer PathPurpose
./public/var/www/html/publicFrontend assets
./App/var/www/html/AppPHP application code
./includes/var/www/html/includesShared PHP includes
./config.php/var/www/html/config.phpConfiguration
./.env/var/www/html/.envEnvironment variables
Changes to these files on your host are immediately reflected in the container.

Persistent Volume

The database uses a Docker volume for data persistence:
# List volumes
docker volume ls

# Inspect the database volume
docker volume inspect zoo-arcadia_mysql_data

# Remove volume (⚠️ destroys all data)
docker volume rm zoo-arcadia_mysql_data

Database Migrations in Docker

The database is automatically initialized on first run using the /docker-entrypoint-initdb.d directory.

Auto-initialization

SQL scripts in database/ are executed in alphabetical order:
  1. 01_init.sql - Create database and users
  2. 02_tables.sql - Create all tables
  3. 03_constraints.sql - Add foreign keys
  4. 04_indexes.sql - Create indexes (if exists)
  5. 05_procedures.sql - Stored procedures (if exists)
  6. 06_seed_data.sql - Initial data
  7. 07_cleanup.sql - Cleanup tasks (if exists)

Manual Migration

To re-run migrations:
1

Stop Containers

docker compose down
2

Remove Database Volume

docker volume rm zoo-arcadia_mysql_data
3

Restart Services

docker compose up -d
The database will be recreated automatically.

Execute SQL Scripts Manually

# Copy SQL file into container
docker compose cp database/02_tables.sql db:/tmp/

# Execute the script
docker compose exec db mysql -u root -proot_password zoo_arcadia < /tmp/02_tables.sql

Common Docker Commands

# Start all services
docker compose up -d

# Stop all services
docker compose down

# Stop and remove volumes
docker compose down -v

# Restart a specific service
docker compose restart web

Troubleshooting

Check logs:
docker compose logs web
docker compose logs db
Common causes:
  • Port already in use (change ports in docker-compose.yml)
  • Insufficient disk space
  • Missing .env file
Verify database is running:
docker compose ps db
Check credentials:
  • Ensure .env has DB_HOST=db (not localhost)
  • Verify credentials match docker-compose.yml
Test connection:
docker compose exec web php -r "echo new PDO('mysql:host=db;dbname=zoo_arcadia', 'zoo_user', 'zoo_password');"
Rebuild with fresh dependencies:
docker compose down
docker compose build --no-cache
docker compose up -d
Check Node.js installation:
docker compose exec web node --version
docker compose exec web npm --version
For code changes: Should be immediate (using bind mounts)For config changes: Restart the web service
docker compose restart web
For Dockerfile changes: Rebuild
docker compose up -d --build
Change the host port in docker-compose.yml:
services:
  web:
    ports:
      - "8081:80"  # Changed from 8080
Then restart:
docker compose down
docker compose up -d

Production Deployment

For production deployments, consider these best practices:
1

Use Production Environment

Update .env for production:
APP_ENV=production
DB_PASS=<strong-password>
2

Remove Development Volumes

Don’t mount source code in production. Remove bind mounts from docker-compose.yml:
# Remove these lines:
volumes:
  - ./public:/var/www/html/public
  - ./App:/var/www/html/App
3

Use Docker Secrets

For sensitive data, use Docker secrets instead of environment variables.
4

Enable HTTPS

Use a reverse proxy (Nginx, Traefik) with SSL certificates.
5

Set Resource Limits

Add resource constraints:
services:
  web:
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 1G
Never expose the database port (3306) to the internet in production.

Next Steps

Database Schema

Explore the database structure

Environment Setup

Configure local development without Docker

Asset Pipeline

Learn about asset compilation

Environment Setup

Set up local development environment

Build docs developers (and LLMs) love