Tuesday, August 22, 2023

Laravel 10 Local Development: A Docker Compose for SSL, Database, Mock API, and Email

Introduction

In the modern development environment, creating a robust and flexible local development setup is crucial for success as a programmer. Laravel, a popular PHP framework, has evolved over the years to adapt to these demands. In this article, we will take a closer look at an advanced Dockerfile configuration that extends Laravel 10's out-of-the-box setup to include SSL, local testing databases, Mock API servers, and a mock email server.

The Complete File


version: '3'
services:
    laravel.test:
        build:
            context: ./vendor/laravel/sail/runtimes/8.2
            dockerfile: Dockerfile
            args:
                WWWGROUP: '${WWWGROUP}'
        image: sail-8.2/app
        container_name: ${COMPOSE_PROJECT_NAME}-application
        extra_hosts:
            - 'host.docker.internal:host-gateway'
        ports:
            - '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
        environment:
            WWWUSER: '${WWWUSER}'
            LARAVEL_SAIL: 1
            XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
            XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
            IGNITION_LOCAL_SITES_PATH: '${PWD}'
        volumes:
            - '.:/var/www/html'
        depends_on:
            - mariadb
            - smtp
            - mockApiServer

    mariadb:
        image: mariadb:10.6
        container_name: ${COMPOSE_PROJECT_NAME}-mariadb
        ports:
            - '${FORWARD_DB_PORT:-3306}:3306'
        environment:
            MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
            MYSQL_ROOT_HOST: '%'
            MYSQL_DATABASE: '${DB_DATABASE}'
            MYSQL_USER: '${DB_USERNAME}'
            MYSQL_PASSWORD: '${DB_PASSWORD}'
            MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
        volumes:
            - './docker/mariadb/storage/data:/var/lib/mysql'
            - './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
        healthcheck:
            test: [ "CMD", "mysqladmin" ,"ping", "-p${DB_PASSWORD}" ]
            retries: 3
            timeout: 5s

    caddy:
        build:
            context: "./docker/caddy"
            dockerfile: Dockerfile
            args:
                WWWGROUP: "${WWWGROUP}"
        container_name: ${COMPOSE_PROJECT_NAME}-caddy
        restart: unless-stopped
        ports:
            - "${APP_PORT:-80}:80"
            - "${APP_SSL_PORT:-443}:443"
        environment:
            LARAVEL_SAIL: 1
            HOST_DOMAIN: laravel.test
        volumes:
            - "./docker/caddy/Caddyfile:/etc/caddy/Caddyfile"
            - ".:/srv:cache"
            - "./docker/caddy/storage/certificates:/data/caddy/certificates/local"
            - "./docker/caddy/storage/authorities:/data/caddy/pki/authorities/local"
            - "./docker/caddy/storage/data:/data:cache"
            - "./docker/caddy/storage/config:/config:cache"
        depends_on:
            - laravel.test

    smtp:
        image: mailhog/mailhog
        container_name: ${COMPOSE_PROJECT_NAME}-email
        logging:
            driver: none  # disable saving logs
        ports:
            - "1025:1025" # smtp server
            - "8025:8025" # web ui

    mockApiServer:
        # Mock API server to test against third-party services
        # without having to hit the real production server. One does need to
        # add any desired API configurations in the mockserver-initializer.json
        # file.
        container_name: ${COMPOSE_PROJECT_NAME}-mock-api-server
        image: mockserver/mockserver
        ports:
            - "1080:1080"
        environment:
            TZ: "America/New_York"
            MOCKSERVER_PROPERTY_FILE: /config/mockserver.properties
            MOCKSERVER_INITIALIZATION_JSON_PATH: /config/mockserver-initializer.json
        volumes:
            - './docker/mockApiServer:/config'
    

The Servers

System Diagram

caddy

The caddy server is an open-source web server with automatic HTTPS. It is used to provide SSL to the Laravel application and handle reverse proxying.

Configuration

  • WWWGROUP: Similar to the Laravel application server, this variable defines the group used by the web server.
  • Ports: Exposes the standard HTTP and HTTPS ports.
  • Environment: Contains settings related to domain handling.
  • Reverse Proxy: Redirects requests to the Laravel application, adding necessary headers for proper functioning.

laravel.test

This server is responsible for hosting the Laravel application. It handles web requests, communicates with the database and APIs, and sends notifications like email.

Configuration

  • WWWGROUP: This variable defines the group ID for the web server process. If unset, the default group ID from the host system is used.
  • WWWUSER: This variable defines the user ID for the web server process. If it is not set, the default user ID from the host system is used. These variables are optional and can remain unset, allowing the system to use default values.
  • Ports: Maps the application's internal port to an external port on the host system.
  • Environment: Contains environment-specific settings like XDEBUG and IGNITION.
  • Volumes: Mounts the application code into the container's file system.

mariadb

This server provides the MariaDB database system, a popular and robust open-source SQL database management system, essential for storing and managing data in your Laravel application.

Configuration

  • MYSQL_ROOT_PASSWORD, MYSQL_DATABASE, etc.: These variables control the database access, defining the root password, user credentials, and even allowing for an empty password. This flexibility provides different levels of security based on your environment needs. Out of the box, Laravel uses environment variables with the DB_ prefix.
  • Ports: Allows communication with the database from the host system.
  • Volumes: Ensures data persistence across container restarts.
  • Healthcheck: Provides a mechanism to check if the database is running properly.

smtp

The SMTP server, implemented here using Mailhog, allows for the sending of test email messages. This aids in developing and testing email functionalities within the Laravel application without the risk of accidentally sending test messages outside the local environment to real people.

Configuration

  • Ports: Exposes SMTP server and web UI for interaction and inspection.

mockApiServer

The Mock API server allows for mimicking interactions with third-party applications, without the need to interact with real production servers. It helps in testing and developing features that rely on external APIs.

Configuration

  • Ports: Maps the internal port to allow interactions from the host system.
  • Environment: Sets up specific properties like time zones and paths to configurations. For example, mockserver-initializer.json is where you configure mock responses that would normally go to third-party production REST APIs.

COMPOSE_PROJECT_NAME

The variable 'COMPOSE_PROJECT_NAME' is used to customize the naming of Docker containers, networks, and volumes, providing a way to make the Docker compose file more portable and reusable. It affects the prefixes and network name, helping to avoid conflicts and facilitate organization.

The .env File

Located in the same folder as the docker-compose file, the .env file is a powerful way to manage environment-specific settings.


COMPOSE_PROJECT_NAME=my_project

DB_CONNECTION=mysql
DB_HOST=mariadb
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=sail
DB_PASSWORD=password
...

Conclusion

This generic Docker compose file for Laravel 10 projects not only provides a seamless local development environment but also makes it easily adaptable across various projects. By encapsulating complex setups like SSL, test databases, Mock API servers, and email handling, it offers a robust platform that can be tailored to specific needs without unnecessary complexity. Future articles may delve into each server's functionality, providing readers with even more insights into this powerful configuration.

Please let me know in the comments section to tell me about your experiences with using Laravel in Docker. What kinds of challenges have you faced? What problems and solutions have you found? Are there other Docker containers that might be useful for other developers to consider (like Redis)? Would you like additional articles focused on individual servers?

No comments: