[
  {
    "path": ".gitattributes",
    "content": "/docs export-ignore\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: markshust\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Description**\n\n\n**Steps To Reproduce**\n1. \n\n**Expected Result**\n\n\n**Actual Result**\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: github-actions\n    directory: /\n    schedule:\n      interval: daily\n"
  },
  {
    "path": ".github/workflows/build-elasticsearch-7-16.yml",
    "content": "name: build-elasticsearch-7-16\n\non: workflow_dispatch\n\njobs:\n  elasticsearch-7-17:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4 \n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/elasticsearch/7.17\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-elasticsearch:7.16\n            markoshust/magento-elasticsearch:7.16-0\n"
  },
  {
    "path": ".github/workflows/build-elasticsearch-7-17.yml",
    "content": "name: build-elasticsearch-7-17\n\non: workflow_dispatch\n\njobs:\n  elasticsearch-7-17:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4 \n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/elasticsearch/7.17\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-elasticsearch:7.17\n            markoshust/magento-elasticsearch:7.17-1\n"
  },
  {
    "path": ".github/workflows/build-elasticsearch-8-11.yml",
    "content": "name: build-elasticsearch-8-11\n\non: workflow_dispatch\n\njobs:\n  elasticsearch-8-5:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/elasticsearch/8.11\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-elasticsearch:8.11\n            markoshust/magento-elasticsearch:8.11-0\n"
  },
  {
    "path": ".github/workflows/build-elasticsearch-8-13.yml",
    "content": "name: build-elasticsearch-8-13\n\non: workflow_dispatch\n\njobs:\n  elasticsearch-8-5:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/elasticsearch/8.13\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-elasticsearch:8.13\n            markoshust/magento-elasticsearch:8.13-0\n"
  },
  {
    "path": ".github/workflows/build-elasticsearch-8-4.yml",
    "content": "name: build-elasticsearch-8-4\n\non: workflow_dispatch\n\njobs:\n  elasticsearch-8-4:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/elasticsearch/8.4\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-elasticsearch:8.4\n            markoshust/magento-elasticsearch:8.4-0\n"
  },
  {
    "path": ".github/workflows/build-elasticsearch-8-5.yml",
    "content": "name: build-elasticsearch-8-5\n\non: workflow_dispatch\n\njobs:\n  elasticsearch-8-5:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/elasticsearch/8.5\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-elasticsearch:8.5\n            markoshust/magento-elasticsearch:8.5-0\n"
  },
  {
    "path": ".github/workflows/build-elasticsearch-8-7.yml",
    "content": "name: build-elasticsearch-8-7\n\non: workflow_dispatch\n\njobs:\n  elasticsearch-8-5:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/elasticsearch/8.7\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-elasticsearch:8.7\n            markoshust/magento-elasticsearch:8.7-0\n"
  },
  {
    "path": ".github/workflows/build-nginx-1-18.yml",
    "content": "name: build-nginx-1-18\n\non: workflow_dispatch\n\njobs:\n  nginx-1-18:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4 \n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/nginx/1.18\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-nginx:1.18\n            markoshust/magento-nginx:1.18-8\n"
  },
  {
    "path": ".github/workflows/build-nginx-1-22.yml",
    "content": "name: build-nginx-1-22\n\non: workflow_dispatch\n\njobs:\n  nginx-1-18:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4 \n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/nginx/1.22\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-nginx:1.22\n            markoshust/magento-nginx:1.22-0\n"
  },
  {
    "path": ".github/workflows/build-nginx-1-24.yml",
    "content": "name: build-nginx-1-24\n\non: workflow_dispatch\n\njobs:\n  nginx-1-18:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4 \n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/nginx/1.24\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-nginx:1.24\n            markoshust/magento-nginx:1.24-1\n"
  },
  {
    "path": ".github/workflows/build-opensearch-1-2.yml",
    "content": "name: build-opensearch-1-2\n\non: workflow_dispatch\n\njobs:\n  opensearch-1-2:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/opensearch/1.2\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-opensearch:1.2\n            markoshust/magento-opensearch:1.2-0\n"
  },
  {
    "path": ".github/workflows/build-opensearch-2-12.yml",
    "content": "name: build-opensearch-2-12\n\non: workflow_dispatch\n\njobs:\n  opensearch-2-5:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/opensearch/2.12\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-opensearch:2.12\n            markoshust/magento-opensearch:2.12-0\n"
  },
  {
    "path": ".github/workflows/build-opensearch-2-5.yml",
    "content": "name: build-opensearch-2-5\n\non: workflow_dispatch\n\njobs:\n  opensearch-2-5:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/opensearch/2.5\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-opensearch:2.5\n            markoshust/magento-opensearch:2.5-1\n"
  },
  {
    "path": ".github/workflows/build-php-8-1.yml",
    "content": "name: build-php-8-1\n\non: workflow_dispatch\n\njobs:\n  php-8-1:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/php/8.1\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-php:8.1-fpm\n            markoshust/magento-php:8.1-fpm-8\n"
  },
  {
    "path": ".github/workflows/build-php-8-2.yml",
    "content": "name: build-php-8-2\n\non: workflow_dispatch\n\njobs:\n  php-8-2:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/php/8.2\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-php:8.2-fpm\n            markoshust/magento-php:8.2-fpm-7\n"
  },
  {
    "path": ".github/workflows/build-php-8-3.yml",
    "content": "name: build-php-8-3\n\non: workflow_dispatch\n\njobs:\n  php-8-3:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/php/8.3\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-php:8.3-fpm\n            markoshust/magento-php:8.3-fpm-5\n"
  },
  {
    "path": ".github/workflows/build-php-8-4.yml",
    "content": "name: build-php-8-4\n\non: workflow_dispatch\n\njobs:\n  php-8-3:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/php/8.4\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-php:8.4-fpm\n            markoshust/magento-php:8.4-fpm-0\n"
  },
  {
    "path": ".github/workflows/build-rabbitmq-3-11.yml",
    "content": "name: build-rabbitmq-3-11\n\non: workflow_dispatch\n\njobs:\n  rabbitmq-3-11:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/rabbitmq/3.11\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-rabbitmq:3.11\n            markoshust/magento-rabbitmq:3.11-1\n"
  },
  {
    "path": ".github/workflows/build-rabbitmq-3-12.yml",
    "content": "name: build-rabbitmq-3-12\n\non: workflow_dispatch\n\njobs:\n  rabbitmq-3-11:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/rabbitmq/3.12\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-rabbitmq:3.12\n            markoshust/magento-rabbitmq:3.12-0\n"
  },
  {
    "path": ".github/workflows/build-rabbitmq-3-13.yml",
    "content": "name: build-rabbitmq-3-13\n\non: workflow_dispatch\n\njobs:\n  rabbitmq-3-11:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/rabbitmq/3.13\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-rabbitmq:3.13\n            markoshust/magento-rabbitmq:3.13-0\n"
  },
  {
    "path": ".github/workflows/build-rabbitmq-3-9.yml",
    "content": "name: build-rabbitmq-3-9\n\non: workflow_dispatch\n\njobs:\n  rabbitmq-3-9:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4 \n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/rabbitmq/3.9\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-rabbitmq:3.9\n            markoshust/magento-rabbitmq:3.9-0\n"
  },
  {
    "path": ".github/workflows/build-rabbitmq-4-1.yml",
    "content": "name: build-rabbitmq-4-1\n\non: workflow_dispatch\n\njobs:\n  rabbitmq-4-1:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/rabbitmq/4.1\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            markoshust/magento-rabbitmq:4.1\n            markoshust/magento-rabbitmq:4.1-0\n"
  },
  {
    "path": ".github/workflows/build-ssh.yml",
    "content": "name: build-ssh\n\non: workflow_dispatch\n\njobs:\n  ssh:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: release/next\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v4\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v4\n      -\n        name: Login to DockerHub\n        uses: docker/login-action@v4\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      -\n        name: Build and push\n        id: docker_build\n        uses: docker/build-push-action@v7\n        with:\n          context: images/php/8.2\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: markoshust/ssh\n"
  },
  {
    "path": ".github/workflows/claude.yml",
    "content": "name: Claude PR Assistant\n\non:\n  issue_comment:\n    types: [created]\n  pull_request_review_comment:\n    types: [created]\n  issues:\n    types: [opened, assigned]\n  pull_request_review:\n    types: [submitted]\n\njobs:\n  claude-code-action:\n    if: |\n      (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||\n      (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||\n      (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||\n      (github.event_name == 'issues' && contains(github.event.issue.body, '@claude'))\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n      pull-requests: read\n      issues: read\n      id-token: write\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n        with:\n          fetch-depth: 1\n\n      - name: Run Claude PR Action\n        uses: anthropics/claude-code-action@beta\n        with:\n          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}\n          timeout_minutes: \"60\"\n"
  },
  {
    "path": ".github/workflows/shellcheck.yml",
    "content": "name: ShellCheck\n\non:\n  push:\n    paths:\n      - \"compose/bin/**\"\n    branches:\n      - master\n  pull_request:\n    paths:\n      - \"compose/bin/**\"\n\njobs:\n  shellcheck:\n    name: shellcheck\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n      - name: Run ShellCheck\n        uses: ludeeus/action-shellcheck@master\n        id: check\n        env:\n          SHELLCHECK_OPTS: \"-x -e SC2181 -P compose/bin -P compose/env\"\n        with:\n          check_together: true\n          scandir: \"./compose/bin\"\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)\nand this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).\n\n## [52.1.0] - 2025-10-21\n\n### Added\n- Added `bin/init` script to initialize development environment with sample data and dev-related modules [PR #1377](https://github.com/markshust/docker-magento/pull/1377)\n- Added support for multiple files or directories as arguments in `bin/copytocontainer` [PR #1384](https://github.com/markshust/docker-magento/pull/1384)\n\n### Updated\n- Updated Magento version to 2.4.8-p3 in README installation instructions\n\n### Fixed\n- Fixed CDPATH from corrupting directory paths in copy scripts by redirecting output to /dev/null [PR #1374](https://github.com/markshust/docker-magento/pull/1374)\n\n## [52.0.2] - 2025-07-01\n\n### Fixed\n- Increase retrieves to prevent OpenSearch from failing to start on Linux [PR #1352](https://github.com/markshust/docker-magento/pull/1352)\n\n## [52.0.1] - 2025-05-12\n\n### Fixed\n- Remove UseSVE from Java Options which caused OpenSearch to fail [PR #1341](https://github.com/markshust/docker-magento/pull/1341)\n\n## [52.0.0] - 2025-04-18\n\nThis release adds support for the latest message broker and database technologies required for Magento 2.4.8, optimizes container health checks, and fixes OpenSearch issues on Linux.\n\n### Added\n- Added support for Valkey 8.1 (Redis successor) for Magento 2.4.8 compatibility [PR #1327](https://github.com/markshust/docker-magento/pull/1327)\n- Added RabbitMQ 4.1 support for Magento 2.4.8 compatibility [PR #1326](https://github.com/markshust/docker-magento/pull/1326)\n- Added documentation for OpenSearch ARM64/Apple M-series compatibility workaround [PR #1316](https://github.com/markshust/docker-magento/issues/1316)\n\n### Updated\n- Updated MariaDB to version 11.4 [PR #1325](https://github.com/markshust/docker-magento/pull/1325)\n- Updated MySQL configuration for 8.4 compatibility [PR #1324](https://github.com/markshust/docker-magento/pull/1324)\n- Optimized container health checks with YAML anchors for consistency across services [PR #1330](https://github.com/markshust/docker-magento/pull/1330)\n- Added `log_bin_trust_function_creators=1` flag to both MariaDB and MySQL configurations [PR #1329](https://github.com/markshust/docker-magento/pull/1329)\n\n### Fixed\n- Fixed OpenSearch startup issues on Linux [PR #1316](https://github.com/markshust/docker-magento/issues/1316)\n- Fixed PHP 8.4 tag reference in README documentation [PR #1328](https://github.com/markshust/docker-magento/pull/1328)\n\n### Removed\n- Dropped support for RabbitMQ 3.8 [PR #1326](https://github.com/markshust/docker-magento/pull/1326)\n\n## [51.0.0] - 2025-04-08\n\nThis release provides full support for Magento 2.4.8 (released same day), includes multiple Docker image updates, fixes important bugs, and adds several new utilities for improved developer experience.\n\n### Added\n- New `bin/docker-start` helper script to automatically start Docker Desktop or OrbStack environments [PR #956](https://github.com/markshust/docker-magento/pull/956)\n- Enhanced cron management that maintains state between container restarts [PR #1309](https://github.com/markshust/docker-magento/pull/1309)\n- Compatibility settings for Elasticsearch and OpenSearch on ARM64/Apple M-series chips [PR #1307](https://github.com/markshust/docker-magento/pull/1307)\n- Relocated Selenium service configuration to `compose.dev.yaml` for better organization [PR #913](https://github.com/markshust/docker-magento/pull/913)\n- Firefox Developer Edition support for SSL certificates [PR #830](https://github.com/markshust/docker-magento/pull/830)\n\n### Updated\n- Upgraded Node.js to version 22.x across all PHP images [PR #1305](https://github.com/markshust/docker-magento/pull/1305)\n- Upgraded PHP extensions: Redis to 6.2.0, Swoole to 6.0.2, Xdebug to 3.4.2 [PR #1305](https://github.com/markshust/docker-magento/pull/1305)\n- Updated Composer to 2.8.6 in PHP 8.2, 8.3, and 8.4 images [PR #1305](https://github.com/markshust/docker-magento/pull/1305)\n- Updated SPX PHP profiler to version 0.4.18 [PR #1305](https://github.com/markshust/docker-magento/pull/1305)\n- Increased client max body size limit to 100M in nginx configuration [PR #1307](https://github.com/markshust/docker-magento/pull/1307)\n- Improved SSL certificate handling for multi-domain setups [PR #1300](https://github.com/markshust/docker-magento/pull/1300)\n\n### Fixed\n- OpenSearch and Elasticsearch container failures on ARM64/Apple Silicon devices [PR #1307](https://github.com/markshust/docker-magento/pull/1307)\n- Cron service unexpectedly failing to restart after being enabled [PR #1309](https://github.com/markshust/docker-magento/pull/1309)\n- Multiple domain support in SSL certificate generation [PR #1257](https://github.com/markshust/docker-magento/pull/1257)\n- Typo in README documentation [PR #1296](https://github.com/markshust/docker-magento/pull/1296)\n- Reorganized backend access documentation for better visibility [PR #1306](https://github.com/markshust/docker-magento/pull/1306)\n\n## [50.0.0] - 2024-01-31\n\n### Added\n- Added `generated` and `var` folders as mounted directories in `compose.dev.yaml` for easier debugging [PR #1284](https://github.com/markshust/docker-magento/pull/1284)\n- Added options to `php.ini` to allow for automatic Xdebug profiling [PR #1284](https://github.com/markshust/docker-magento/pull/1284)\n\n### Updated\n- Mailcatcher tagged to version 0.10.0 [PR #912](https://github.com/markshust/docker-magento/pull/912)\n- Xdebug to version 3.4.1 [PR #1285](https://github.com/markshust/docker-magento/pull/1285)\n- Swoole to version 6.0.0 [PR #1285](https://github.com/markshust/docker-magento/pull/1285)\n\n## [49.0.0] - 2024-01-15\n\n### Updated\n- Enhanced `bin/xdebug` script with more comprehensive mode management and validation, supporting all Xdebug modes (off, develop, coverage, debug, gcstats, profile, trace) and combinations [PR #1276](https://github.com/markshust/docker-magento/pull/1276)\n\n## [48.0.1] - 2024-12-07\n\n### Fixed\n- Unit test scripts [PR #1263](https://github.com/markshust/docker-magento/pull/1263)\n\n## [48.0.0] - 2024-11-27\n\nThis release introduces significant enhancements to the development environment, including a new PHP 8.4 Docker image for early adopters and developers wanting to test future compatibility. The MageOS support has been substantially improved, and a new RabbitMQ 3.13 image has been added. Several quality-of-life improvements have been implemented, such as better unit testing tools, enhanced SSL generation for multi-site setups, and comprehensive documentation updates. A notable breaking change is the shift in the download command syntax - it now expects the edition type before the version number (ex: `bin/download community 2.4.7-p3` instead of the previous `bin/download 2.4.7 community`). Additionally, all Docker images have been updated to maintain parity with current Magento version requirements.\n\n### Added\n- New PHP 8.4 Docker image for development purposes [PR #1252](https://github.com/markshust/docker-magento/pull/1252)\n- New RabbitMQ 3.13 Docker image [PR #1252](https://github.com/markshust/docker-magento/pull/1252)\n- Backend login credentials and 2FA setup instructions to README [PR #1205](https://github.com/markshust/docker-magento/pull/1205)\n- PHP FTP extension to Docker setup [PR #1210](https://github.com/markshust/docker-magento/pull/1210)\n- PhpMyAdmin credentials to README [PR #1212](https://github.com/markshust/docker-magento/pull/1212)\n- `bin/test` helper scripts to execute unit tests [PR #1157](https://github.com/markshust/docker-magento/pull/1157)\n- `bin/ece-patches` command [PR #1171](https://github.com/markshust/docker-magento/pull/1171)\n- rsync to PHP images for Deployer support [PR #1163](https://github.com/markshust/docker-magento/pull/1163)\n- PhpMyAdmin for Linux [PR #1177](https://github.com/markshust/docker-magento/pull/1177)\n\n### Updated\n- Improved MageOS support [PR #1246](https://github.com/markshust/docker-magento/pull/1246)\n- System requirements helper script overhauled for easier use and maintenance [PR #1242](https://github.com/markshust/docker-magento/pull/1242)\n- Supported versions in `bin/check-dependencies` script [PR #1175](https://github.com/markshust/docker-magento/pull/1175)\n- Docker images for Magento version parity [PR #1252](https://github.com/markshust/docker-magento/pull/1252)\n- Bumped docker/build-push-action from 5 to 6 [PR #1174](https://github.com/markshust/docker-magento/pull/1174)\n- GitHub Actions to use release/next branch [PR #1254](https://github.com/markshust/docker-magento/pull/1254)\n- Speed improvement for `bin/xdebug` command [PR #1245](https://github.com/markshust/docker-magento/pull/1245)\n\n### Fixed\n- Code duplication [PR #1141](https://github.com/markshust/docker-magento/pull/1141)\n- Empty directory check moved to top of scripts [PR #1143](https://github.com/markshust/docker-magento/pull/1143)\n- Elasticsearch container issues [PR #1166](https://github.com/markshust/docker-magento/pull/1166)\n- Multi-site SSL generation support [PR #1200](https://github.com/markshust/docker-magento/pull/1200)\n- Various typos in files [PR #1238](https://github.com/markshust/docker-magento/pull/1238)\n\n## [47.0.1] - 2024-04-25\n\n### Fixed\n- \"The current directory is not empty\" message appearing on new install [PR #1141](https://github.com/markshust/docker-magento/pull/1141).\n\n## [47.0.0] - 2024-04-25\n\n### Added\n- Check to ensure directory does not already exist in project directory [PR #1127](https://github.com/markshust/docker-magento/pull/1127).\n\n### Updated\n- Remove obsolete version directive from docker compose files [PR #1125](https://github.com/markshust/docker-magento/pull/1125).\n- Predefined version from 2.4.6-p4 to 2.4.7 [PR #1128](https://github.com/markshust/docker-magento/pull/1128).\n- Integration testing configuration to use OpenSearch [PR #1131](https://github.com/markshust/docker-magento/pull/1131).\n\n### Fixed\n- SSL cert generation when domain has a port included [PR #1136](https://github.com/markshust/docker-magento/pull/1136).\n- OpenSearch container fails to start due to memory heap size configuration [PR #1137](https://github.com/markshust/docker-magento/pull/1137).\n\n## [46.1.1] - 2024-04-16\n\n### Fixed\n- Xdebug 3.3.1 and Blackfire PHP extension incompatibility [PR #1122](https://github.com/markshust/docker-magento/pull/1122).\n\n## [46.1.0] - 2024-04-13\n\n### Added\n- New `bin/blackfire` script to enable, disable, or check status of Blackfire extension [PR #1115](https://github.com/markshust/docker-magento/pull/1115).\n- Swool PHP extension to all PHP Docker images to support Adobe Commerce GraphQL Application Layer [PR #1114](https://github.com/markshust/docker-magento/pull/1114).\n\n### Updated\n- Supported versions in the `bin/check-dependencies` script [PR #1112](https://github.com/markshust/docker-magento/pull/1112).\n\n### Fixed\n- Random 502 Bad Gateway errors when Xdebug is enabled [PR #1085](https://github.com/markshust/docker-magento/pull/1085), [PR #1116](https://github.com/markshust/docker-magento/pull/1116).\n\n## [46.0.0] - 2024-04-09\n\n### Added\n- New `bin/check-dependencies` script which provides helpful recommendations for dependencies tailored to the chosen Magento version [PR #1018](https://github.com/markshust/docker-magento/pull/1018/files).\n- New `nginx` Docker images for versions 1.22, 1.24 [PR #1019](https://github.com/markshust/docker-magento/pull/1109).\n- New `php-fpm` 8.3 Docker image for Magento 2.4.7 support [PR #1019](https://github.com/markshust/docker-magento/pull/1109).\n- New `opensearch` 2.12 Docker image for Magento 2.4.7 support [PR #1019](https://github.com/markshust/docker-magento/pull/1109).\n- New `elasticsearch` 7.16 and 8.11 Docker images for previous Magento versions support [PR #1019](https://github.com/markshust/docker-magento/pull/1109).\n- New `elasticsearch` 8.13 Docker image for Magento 2.4.7 support [PR #1019](https://github.com/markshust/docker-magento/pull/1109).\n- New `rabbitmq` 3.8 Docker image for previous Magento versions support [PR #1019](https://github.com/markshust/docker-magento/pull/1109).\n- New `rabbitmq` 3.12 Docker image for Magento 2.4.7 support [PR #1019](https://github.com/markshust/docker-magento/pull/1109).\n\n### Updated\n- Link `php-fpm` Docker images to officially compatible Composer versions [PR #1019](https://github.com/markshust/docker-magento/pull/1109).\n\n## [45.1.0] - 2024-03-19\n\n### Added\n- New `bin/configure-linux` helper script to assist with easier Linux setup [PR #1016](https://github.com/markshust/docker-magento/pull/1016).\n- Linux dependencies to README [PR #1050](https://github.com/markshust/docker-magento/pull/1050).\n- Added `bin/create-user` script to allow for easy creation of Magento admin user & customer [PR #1040](https://github.com/markshust/docker-magento/pull/1040).\n- Descriptions for all missing helper scripts to README and Makefile [PR #1096](https://github.com/markshust/docker-magento/pull/1096).\n\n### Updated\n- `bin/docker-stats` to simplified output [PR #1083](https://github.com/markshust/docker-magento/pull/1083).\n- Pinned Composer version for increased compatibility with latest Magento versions [PR #1090](https://github.com/markshust/docker-magento/pull/1090).\n\n## [45.0.0] - 2024-02-25\n\n### Added\n- New PHP images based on bookworm, pegging pecl libraries for more predictability [PR #1071](https://github.com/markshust/docker-magento/pull/1071).\n- New PHP 8.3 image [PR #1071](https://github.com/markshust/docker-magento/pull/1071).\n- PHP SPX profiler to enhance performance monitoring capabilities [PR #533](https://github.com/markshust/docker-magento/pull/533).\n- Support for the `strace` command, providing developers with powerful tools for diagnosing and troubleshooting [PR #1033](https://github.com/markshust/docker-magento/pull/1033).\n- Ability for xdebug to listen to Magento CLI commands [PR #846](https://github.com/markshust/docker-magento/pull/846).\n- Abstraction of setup script into two scripts [PR #874](https://github.com/markshust/docker-magento/pull/874).\n- New Docker image for OpenSearch 2.4 [PR #858](https://github.com/markshust/docker-magento/pull/858).\n- Mage-OS mirror support [PR #835](https://github.com/markshust/docker-magento/pull/835).\n- New `bin/log` command to view Magento logs in real-time [PR #1060](https://github.com/markshust/docker-magento/pull/1060).\n- New `bin/docker-stats` command for container monitoring [PR #533](https://github.com/markshust/docker-magento/pull/533).\n- New `bin/setup-pwa-studio-sampledata` command to install Magento PWA Studio sample data, facilitating easier PWA development setups [#1045](https://github.com/markshust/docker-magento/pull/1045).\n- New `bin/deploy` script to deply Magento in pipeline [PR #926](https://github.com/markshust/docker-magento/pull/926).\n- New `bin/magento-version` script which outputs current Magento version [PR #931](https://github.com/markshust/docker-magento/pull/931).\n- New `bin/spx` script to enable or disable SPX [PR #1074](https://github.com/markshust/docker-magento/pull/1074).\n\n### Updated\n- Node.js to version 20.x LTS [PR #1071](https://github.com/markshust/docker-magento/pull/1071).\n- Support for Magento 2.4.6-p4, updating the default Magento version in the Docker setup to align with the latest Magento release [PR #1063](https://github.com/markshust/docker-magento/pull/1063).\n- Continuous integration and deployment processes were refined to include updates and to maintain dependencies through GitHub Actions and Dependabot, ensuring that the project's dependencies remain up to date and secure [PR #1032](https://github.com/markshust/docker-magento/pull/1032).\n- Rework docker compose script to allow future extensibility [PR #1002](https://github.com/markshust/docker-magento/pull/1002).\n- Replaced phpmyadmin Docker image with amd64-compatible image [PR #939](https://github.com/markshust/docker-magento/pull/939).\n- Set default Magento 2.4.6 search engine to OpenSearch [PR #937](https://github.com/markshust/docker-magento/pull/937).\n- Use `/usr/bin/env` to discover bash location [PR #879](https://github.com/markshust/docker-magento/pull/879).\n\n### Fixed\n- Execution rights in scripts [PR #1039](https://github.com/markshust/docker-magento/pull/1039).\n- Bug with Elasticsearch documentation [PR #1014](https://github.com/markshust/docker-magento/pull/1014).\n- Elasticsearch JAVA OPTS issue with containers not starting at startup [PR #938](https://github.com/markshust/docker-magento/pull/938).\n- Unexpected Ubuntu 18.04 startup failure [PR #310](https://github.com/markshust/docker-magento/pull/310).\n- Failing `npm install` of puppeteer due to missing Chromium [PR #848](https://github.com/markshust/docker-magento/pull/848).\n\n## [44.0.0] - 2022-12-05\n\n### Added\n- Allow more variables for the PhpStan analyse script [PR #789](https://github.com/markshust/docker-magento/pull/789).\n- New bin/docker-compose script to abstract away calls to docker-compose [PR #787](https://github.com/markshust/docker-magento/pull/787).\n- Support for Docker Compose V2 (\"docker compose\" and backwards-compatibility for \"docker-compose\") [PR #787](https://github.com/markshust/docker-magento/pull/787).\n- New Docker Compose healthcheck [PR #384](https://github.com/markshust/docker-magento/pull/384).\n- MageOS support [4591b68c](https://github.com/markshust/docker-magento/commit/4591b68c46667d4015e728392b813ec42939ae67).\n- Documentation to recover from failed install [#816](https://github.com/markshust/docker-magento/issues/816).\n- OpenSearch support [PR #680](https://github.com/markshust/docker-magento/pull/680).\n- New build for Elasticsearch 7.17 [c45f05c3](https://github.com/markshust/docker-magento/commit/c45f05c370fe1347afa35117511794f736710f71).\n\n### Updated\n- Rename docker-compose.yml to compose.yaml (preferred) [PR #799](https://github.com/markshust/docker-magento/pull/799).\n- Readme file with new info on configuring Xdebug in WSL2 environments [PR #810](https://github.com/markshust/docker-magento/pull/810).\n\n### Fixed\n- Lowered RAM check on setup [#720](https://github.com/markshust/docker-magento/issues/720).\n\n### Removed\n- Deprecated PHP 7.4 due to all versions < Magento 2.4.4 reaching EOL [3a64324e](https://github.com/markshust/docker-magento/commit/3a64324e08f3d15e3c3ce86b5c0f5e7ebb635a75).\n\n## [43.2.0] - 2022-09-13\n\n### Added\n- Added phpmyadmin to docker-compose.dev.yml file [PR #772](https://github.com/markshust/docker-magento/pull/772).\n\n## [43.1.0] - 2022-09-13\n\n### Added\n- Support for Grunt + LiveReload [#430](https://github.com/markshust/docker-magento/issues/430).\n\n## [43.0.0] - 2022-05-26\n\n### Added\n- Fall back to PHP 7.4 for Magento versions older than 2.4.4 [PR #685](https://github.com/markshust/docker-magento/pull/685) [PR #710](https://github.com/markshust/docker-magento/pull/710).\n- Checksum flag to rsync in `bin/update` [PR #707](https://github.com/markshust/docker-magento/pull/707).\n- New `bin/analyse` command to statically analyse code with PHPStan [8601c2f7](https://github.com/markshust/docker-magento/commit/8601c2f73cc6f1d2534f017c8f31eec49b0e00fc).\n- `node` & `npm` to PHP images [#694](https://github.com/markshust/docker-magento/issues/694).\n\n### Updated\n- Magento download to default to 2.4.4 [151dc09a](https://github.com/markshust/docker-magento/commit/151dc09ae95a5cff75598c366f3d77efa58098d5)\n- Prevent domain duplication in `/etc/hosts` [PR #693](https://github.com/markshust/docker-magento/pull/693).\n- Replace buster images with bullseye to properly fix Apple M1 5-sec delay [#636](https://github.com/markshust/docker-magento/issues/636).\n\n## [42.0.0] - 2022-04-14\n\nThis release brings streamlined PHP Docker images (saving 300MB on previous images), a brand new PHP 8.1 image with full support for Magento 2.4.4, a proper Elasticsearch health check during setup, and ability to detect memory assigned to Docker on startup (which will prevent failed installations). Elasticsearch, Redis & RabbitMQ Docker images have also all been updated to their recently supported Magento versions.\n\n### Added\n- New Docker image for PHP 8.1 [903f9867](https://github.com/markshust/docker-magento/commit/903f9867aa130100267290feaa03b1b48b157337).\n- New Docker image for Elasticsearch 7.16 [f70a1565](https://github.com/markshust/docker-magento/commit/f70a1565bddd56a3abe8df52d4122dbcdc85d98a).\n- New Docker image for RabbitMQ 3.9 [7711365c](https://github.com/markshust/docker-magento/commit/7711365cb73aab685859e3e34fc23774937a4e2a).\n- Elasticsearch health check timeout when installing Magento [#675](https://github.com/markshust/docker-magento/pull/675).\n- Ability to detect if memory usage is too low [#527](https://github.com/markshust/docker-magento/issues/527).\n\n### Updated\n- PHP 7.4 Docker image for parity with PHP 8.1 image [481097b3](https://github.com/markshust/docker-magento/commit/481097b3f9184d19deb102b901b43af906ebb256).\n\n### Removed\n- ionCube support from PHP 7 image in order to retain Docker image parity between versions, to slim down image size, and because I no longer want to support encrypted or obfuscated code in my open source projects. Feel free to pull, fork or modify if you still need ionCube in your projects.\n\n## [41.1.0] - 2022-03-28\n\n### Fixed\n- Increased RabbitMQ sleep timeout to prevent errors on startup [#426](https://github.com/markshust/docker-magento/issues/426).\n- RabbitMQ connection issues on Windows/WSL2 [#426](https://github.com/markshust/docker-magento/issues/426).\n- Problem with elasticsearch & unexpected character [#597](https://github.com/markshust/docker-magento/issues/597).\n- Issue with extra_hosts host.docker.internal for Xdebug on Linux [#595](https://github.com/markshust/docker-magento/issues/595).\n- Reverted Xdebug/magerun code refactor which caused issues [#595](https://github.com/markshust/docker-magento/pull/545).\n- Composer auth.json auth required message shows after authenticating [#587](https://github.com/markshust/docker-magento/issues/587).\n- Failing shellchecks [08206e6d](https://github.com/markshust/docker-magento/commit/08206e6d6a48fdb3c1c3adc8f52b146609ba771c), [53d9b858](https://github.com/markshust/docker-magento/commit/53d9b8585733f8f78a5dcaedce53a83863a1b634).\n- Firefox SSL cert fails on first-time install [2695fe2e](https://github.com/markshust/docker-magento/commit/2695fe2e508098906103dd442767d50e9f6011c0).\n- Some commands including bin/xdebug not working on Windows + Docker Desktop 4.4.3 [#619](https://github.com/markshust/docker-magento/issues/619).\n\n### Updated\n- Redis 5.0 to 6.0 [6653d787](https://github.com/markshust/docker-magento/commit/6653d78722fb8d1d76cc2433a89227456e48514f).\n- `bin/setup` script so it can run completely automated [PR #633](https://github.com/markshust/docker-magento/pull/633).\n- PHP 8 image to 8.1.4, last version before tagging final release [86093b70](https://github.com/markshust/docker-magento/commit/86093b70c9ee7f0ed3c62e84460b7e53926d033c).\n\n### Added\n- `bin/stopall` script to stop all running containers [#599](https://github.com/markshust/docker-magento/pull/599).\n- New PHP image to enable WebP support in GD [PR #651](https://github.com/markshust/docker-magento/pull/651).\n- Ability to configure custom user/group ID in Nginx image [PR #658](https://github.com/markshust/docker-magento/pull/658).\n\n### Removed\n- PHP 7.3 images have been deprecated due to 7.3's EOL.\n- EXPOSE statement from PHP image (unneeded) [790e2fe0](https://github.com/markshust/docker-magento/commit/790e2fe0293feb12455d7f9ed2593aa97ad6df99).\n\n## [41.0.2] - 2021-12-09\n\n### Fixed\n- Disable \"Composer is slower because of Xdebug\" message [1990d84](https://github.com/markshust/docker-magento/commit/1990d84).\n- Updated verbiage in setup on how to start cron [c3ba47d](https://github.com/markshust/docker-magento/commit/1990d84).\n- Fixed \"The input device is not a TTY\" error during setup [8aada97](https://github.com/markshust/docker-magento/commit/8aada97).\n- Expose port 9003 on PHP Docker image for Xdebug [263e40d](https://github.com/markshust/docker-magento/commit/263e40d).\n- Disable Xdebug by default for PHP 7.3 [263e40d](https://github.com/markshust/docker-magento/commit/263e40d).\n\n### Updated\n- Updated PHP 8.1 image to use official GA version [263e40d](https://github.com/markshust/docker-magento/commit/263e40d).\n\n## [41.0.1] - 2021-11-09\n\n### Fixed\n- Fixed additional issue of waiting for Elasticsearch/RabbitMQ connection on Mac [#442](https://github.com/markshust/docker-magento/issues/442).\n\n## [41.0.0] - 2021-11-08\n\nThere has been an ongoing issue with Docker for Mac + M1 chips (Apple Silicon) which causes a 5-second delay in network requests (see [#5626](https://github.com/docker/for-mac/issues/5626)). A fix has been implemented in this release that works around this issue, adding `extra_hosts` directives in the `docker-compose.yml` file. This update should be backwards-compatible, but will break existing setups that use custom Docker networks (this is an uncommon scenario). See notes at the top of `docker-compose.yml` for how to configure this project for custom Docker networks.\n\n### Added\n- Added Imagick PHP extension [#530](https://github.com/markshust/docker-magento/issues/530).\n\n### Fixed\n- Fixed issue with onelinesetup script failing on download [92b803c](https://github.com/markshust/docker-magento/commit/92b803c) [67c76b4](https://github.com/markshust/docker-magento/commit/67c76b4).\n- Fix Shellcheck failures for bin/setup-ssl-ca [#558](https://github.com/markshust/docker-magento/issues/558).\n- Fix wrong `sendmail_path` in php.ini [#556](https://github.com/markshust/docker-magento/issues/556).\n- Ensure .composer directory isn't created by root [#562](https://github.com/markshust/docker-magento/issues/562).\n- Fixed `bin/devconsole` command not working [646f617](https://github.com/markshust/docker-magento/commit/646f617).\n- Fixed `bin/setup-composer-auth` does not persist auth creds [#567](https://github.com/markshust/docker-magento/issues/567).\n- Fixed documentation around Xdebug port on Linux [90af7fa](https://github.com/markshust/docker-magento/commit/90af7fa).\n- Fixed waiting for Elasticsearch/RabbitMQ connection on Mac [#442](https://github.com/markshust/docker-magento/issues/442).\n\n### Updated\n- Updated info about MySQL backups and existing projects in README [86faa70](https://github.com/markshust/docker-magento/commit/86faa70).\n- Updated README for Xdebug + PhpStorm [b1fe812](https://github.com/markshust/docker-magento/commit/b1fe812).\n\n## [40.1.0] - 2021-10-29\n\n### Fixed\n- Fixed issues with onelinesetup script [#564](https://github.com/markshust/docker-magento/issues/564).\n- Fixed Shellcheck failures for bin/setup-ssl-ca [#558](https://github.com/markshust/docker-magento/issues/558).\n- Fixed php.ini possible wrong smtp-addr [#556](https://github.com/markshust/docker-magento/issues/556).\n- Ensure files are created so Docker doesn't create them as root [#562](https://github.com/markshust/docker-magento/issues/562).\n- Added additional time for Elasticsearch container to get initialized during setup.\n\n## [40.0.2] - 2021-10-20\n\n### Fixed\n- Fixed Selenium configuration for MFTF [PR #554](https://github.com/markshust/docker-magento/pull/554).\n\n## [40.0.1] - 2021-10-20\n\n### Fixed\n- Fixed PHP image `8.0-fpm-develop` for Magento 2.4.4 support (note: still has `-develop` tag).\n\n### Updated\n- Moved `~/.ssh` volume mount references to `docker-compose.yml` to ease maintenance.\n\n## [40.0.0] - 2021-10-15\n\nThis is one of the biggest releases of docker-magento 💥! This major update includes support for Apple Silicon (M1/M1X) chips, as well as SSH support for fully native filesystem speed.\n\nAll the images are now multi-arch builds, meaning they can install on both AMD & ARM chipsets. Additionally, by setting up your IDE to connect to Docker over SSH/SFTP to avoid selective filesystem syncing.\n\nThe docker-compose configuration files have also been streamlined & simplified, with dedicated files for both SSH and Linux setups. Read more about these updates at https://github.com/markshust/docker-magento#ssh and https://github.com/markshust/docker-magento#linux respectively.\n\nMany issues have been resolved, and long-standing pull requests have been merged. A special thanks to [@drpayyne](https://github.com/drpayyne) for multi-arch support, [@rangerz](https://github.com/rangerz) for their massive contributions, as well as many others for their continued work & pull requests submitted to this project.\n\n### Updated\n- Updated `onelinesetup` script to use version `2.4.3-p1` by default.\n- Updated `bin/cache-clean` with improved logic [PR #400](https://github.com/markshust/docker-magento/pull/400).\n- Simplified `docker-compose.dev.yml` file to only contain volume mounting information.\n\n### Added\n- Added new `mailcatcher` image to replace `mailhog` for multi-arch support [#511](https://github.com/markshust/docker-magento/issues/511).\n- Added `docker-compose.dev-ssh.xml` to streamline SSH setup.\n- Added `docker-compose.dev-linux.xml` to streamline Linux setup.\n- Added GitHub workflows for multi-arch build support [#396](https://github.com/markshust/docker-magento/issues/396).\n- Added multi-arch support for Nginx [PR #515](https://github.com/markshust/docker-magento/pull/515).\n- Added multi-arch support for PHP [PR #516](https://github.com/markshust/docker-magento/pull/516).\n- Added new `bin/setup-domain` script [PR #429](https://github.com/markshust/docker-magento/pull/429).\n- Added Basic MFTP Setup information [PR #269](https://github.com/markshust/docker-magento/pull/269).\n- Make uid & gid of app user configurable [#520](https://github.com/markshust/docker-magento/pull/520).\n- Added Makefile with list of available commands [#399](https://github.com/markshust/docker-magento/pull/399).\n- Xdebug 3 support for `bin/n98-magerun2` [#545](https://github.com/markshust/docker-magento/pull/545).\n\n### Fixed\n- Fixed SSL setup failing on Linux [#222](https://github.com/markshust/docker-magento/issues/222).\n- Fixed locale code for `bin/setup-grunt` [#484](https://github.com/markshust/docker-magento/pull/484).\n- Fixed cron not working [#540](https://github.com/markshust/docker-magento/issues/540).\n\n## [39.1.0] - 2021-09-21\n\n### Updated\n- Replace MailHog with Mailcatcher for multi-arch compatibility [#511](https://github.com/markshust/docker-magento/issues/511).\n\n## [39.0.2] - 2021-09-21\n\n### Fixed\n- Fixed placement of enabling developer mode within bin/setup.\n\n## [39.0.1] - 2021-09-21\n\n### Fixed\n- Connection to Redis fails without php-redis extension [#474](https://github.com/markshust/docker-magento/issues/474).\n\n## [39.0.0] - 2021-09-21\n\n### Added\n- New Elasticsearch Docker images `7.9`, `7.9.3-0` [#488](https://github.com/markshust/docker-magento/issues/488).\n\n### Updated\n- Replace Percona DB with MariaDB 10.4 [#514](https://github.com/markshust/docker-magento/issues/514).\n- Updated RabbitMQ image to 3.8.\n\n### Fixed\n- Resolve cron install script not in bin/setup [#420](https://github.com/markshust/docker-magento/issues/420).\n- Update Elasticsearch settings to fix catalog search index error [#488](https://github.com/markshust/docker-magento/issues/488).\n\n## [38.0.0] - 2021-07-27\n\n### Added\n- Composer 2 support [#409](https://github.com/markshust/docker-magento/issues/409).\n\n### Fixed\n- Composer `auth.json` not properly set after installation [#42](https://github.com/markshust/docker-magento/issues/42).\n- `bin/remove` not removing containers in newer versions of Docker Compose.\n- Invalid template error with Docker 3.5.1 [#486](https://github.com/markshust/docker-magento/issues/486).\n\n## [37.0.2] - 2021-02-17\n\n### Added\n- New `bin/setup-composer-auth` file to setup Composer auth creds.\n\n## [37.0.1] - 2021-02-15\n\n### Fixed\n- Fix onelinesetup script bug.\n\n## [37.0.0] - 2021-02-14\n\n### Added\n- Official support for Xdebug 3 [#390](https://github.com/markshust/docker-magento/issues/390). The new PHP images are `7.3-fpm-12` & `7.4-fpm-5`.\n- If you need to still use Xdebug 2, update your docker-compose.yml files to instead look at PHP image `7.3-fpm-11` or `7.4-fpm-4`. These images are exactly the same other than being pegged to Xdebug 2.\n\n## [36.0.2] - 2021-02-14\n\n### Updated\n- Reverted Xdebug to version 2 for backwards-compatible support [#390](https://github.com/markshust/docker-magento/issues/390).\n\n## [36.0.1] - 2021-02-04\n\n### Updated\n- Reverted DB image back to `percona:5.7` until issues with MySQL 8.0 image are resolved.\n\n## [36.0.0] - 2021-02-04\n\n### Added\n- New Elasticsearch Docker images `7.7`, `7.7.1-0` [#392](https://github.com/markshust/docker-magento/issues/392).\n- SpellCheck GitHub Action for continuous integration checks of shell scripts [#387](https://github.com/markshust/docker-magento/pull/387), [#388](https://github.com/markshust/docker-magento/pull/388).\n\n### Fixed\n- Support filesystem paths with spaces [e5f22e56](https://github.com/markshust/docker-magento/commit/e5f22e56fcd382b8339d5804a9d236dd6b238a3d).\n- Added missing `bin/cache-clean` file [f0e57202](https://github.com/markshust/docker-magento/commit/f0e5720281cd9f536f163bd5bdfe5bd66a956dc6).\n\n### Updated\n- Updated PHP images to NodeJS version 14 LTS [4a81f2b8](https://github.com/markshust/docker-magento/commit/4a81f2b8c61674b261ee7b42752e21fc8d5e945d).\n- Changed `db` service to use MySQL 8.0 Docker image.\n\n## [35.0.0] - 2021-01-29\n\n### Added\n- Automatically purge caches for a better dev experience [#380](https://github.com/markshust/docker-magento/issues/380).\n- Stop script execution on error [#363](https://github.com/markshust/docker-magento/pull/363/).\n- Make xdebug command understand partials [#371](https://github.com/markshust/docker-magento/pull/371).\n- Extended functionality for `bin/xdebug`, including new `status` and `toggle` commands [#332](https://github.com/markshust/docker-magento/pull/332).\n- Check Elasticsearch connection before setup:install [#326](https://github.com/markshust/docker-magento/pull/326).\n\n### Updated\n- The onelinesetup now accepts a `community` or `enterprise` param to pick version to install [b2399ff1](https://github.com/markshust/docker-magento/commit/ad573f6f3c8d2f7066034cbde936a86eb2399ff1).\n- Fix bin/start for macOS Big Sur [#355](https://github.com/markshust/docker-magento/pull/355/).\n\n## [34.2.0] - 2020-10-15\n\n### Updated\n- Updated Composer to version `1.10.15` to avoid nag update messages in new PHP Docker images `7.3-fpm-9`, `7.4-fpm-2`.\n\n## [34.1.0] - 2020-10-15\n\n### Added\n- HTTP/2 added to Nginx image `1.18-4`\n\n### Updated\n- `bin/download` falls back to using Composer if archive download fails or is not found.\n\n## [34.0.0] - 2020-10-11\n\n### Added\n- New `bin/setup-integration-tests` script to setup integration tests [3c021ff](https://github.com/markshust/docker-magento/commit/3c021ff6c92e49fad669deed0805cceae26bdccf).\n- Added `MYSQL_HOST` environment variable to `env/db.env` file.\n- New Nginx `1.18-3` Docker images uses Alpine as base image [PR #306](https://github.com/markshust/docker-magento/pull/306).\n\n### Updated\n- Prevent containers from starting if volume mapping doesn't exist, validate volumes to avoid empty folder creation [PR #256](https://github.com/markshust/docker-magento/pull/256).\n- Setup script uses MySQL `env/db.env` file for database connection credentials [PR #302](https://github.com/markshust/docker-magento/pull/302).\n- Increased MySQL's `max_allowed_packet` to `64M` in `docker-compose.yml` file [PR #303](https://github.com/markshust/docker-magento/pull/303).\n- `docker-compose.yml` now uses Alpine images for Redis and RabbitMQ [#305](https://github.com/markshust/docker-magento/pull/305).\n- `docker-compose.yml` file now uses new Alpine images for Redis, RabbitMQ & Nginx.\n- `bin/setup` script updated to use Redis for cache and session directly in installer script [PR #304](https://github.com/markshust/docker-magento/pull/304).\n- `bin/setup` script sets Admin URL to `/admin` [PR #304](https://github.com/markshust/docker-magento/pull/304).\n- Enabling/disabling Xdebug now only restarts `phpfpm` container rather than all containers [PR #314](https://github.com/markshust/docker-magento/pull/314).\n- `bin/setup` script moves `.vscode` directory to `src` after install [846d02c](https://github.com/markshust/docker-magento/commit/846d02c12c5af8005fe0cbb0b167b97f501db0c9).\n\n### Fixed\n- Exception while running integration tests [#292](https://github.com/markshust/docker-magento/pull/292).\n- Nested files not copying in copytocontainer script [#295](https://github.com/markshust/docker-magento/pull/295) [#296](https://github.com/markshust/docker-magento/pull/295).\n- Ubuntu unable to start because of missing volumes [#309](https://github.com/markshust/docker-magento/issues/309).\n\n## [33.0.0] - 2020-07-30\n\n### Added\n- The `php:7.4-fpm` Docker image has been setup with full support for Magento 2.4 (see [images/php/7.4](https://github.com/markshust/docker-magento/tree/master/images/php/7.4)).\n- Added easy way to mount an SSH key to the container (see [#89](https://github.com/markshust/docker-magento/issues/89)).\n- The `bin/download` script now falls back to Hypernode's Magento Download mirror in the event the archive doesn't exist or fails to download from Nexcess.\n\n### Updated\n- All Docker volumes now use `:cached` rather than `:delegated`. The `delegated` volume functionality is changing in a future version of Docker for Mac to use Mutagen volumes, and the implementation is very buggy & awkward. Using the `cached` flag retains the current functionality we've been using in `delegated` without any changes (confirmed in [docker/for-mac#1592](https://github.com/docker/for-mac/issues/1592#issuecomment-662504816)).\n- Updated `bin/setup-ssl-ca` so SSL generation works on Linux ([#222](https://github.com/markshust/docker-magento/issues/222))\n- Updated `php` Docker images to use most recent version of Composer (1.10.9).\n- The `bin/setup` script now runs `composer update` rather than `composer install`. There was an error happening with `composer install`, and with the start of the project it's best to just get the most recent Composer packages anyway.\n- The `bin/setup` script now sets Elasticsearch 7 as the default catalog search engine directly when executing `bin/magento setup:install`.\n\n### Removed\n- All `latest` tags have been removed on all Docker images. It is bad practice to not use a specific version. The `latest` tag will no longer be recompiled when new images are released.\n- The `php:7.2` Docker images have been deprecated, as that version is no longer supported in Magento.\n- The `elasticsearch:6` Docker images have been deprecated, as those versions are no longer supported in Magento.\n- Removed invalid checksum hack fix in `bin/setup` for `google-shopping-api` package, as that is only applicable to older versions of Magento.\n\n## [32.0.1] - 2020-05-12\n\n### Fixed\n- Backed out last Elasticsearch update with elasticsearch.yml, caused issues with startup.\n\n## [32.0.0] - 2020-05-11\n\n### Fixed\n- Updated `bin/dev-urn-catalog-generate` to account for new versions of PHPStorm (simplified).\n- Indexing error with possible ElasticSearch modules ([#262](https://github.com/markshust/docker-magento/issues/262)).\n\n### Updated\n- Updated ElasticSearch 6 to version 6.8.\n\n## [31.0.2] - 2020-04-30\n\n### Fixed\n- Fixed typo in last build image, new version is `magento-nginx:1.18-2`.\n\n## [31.0.1] - 2020-04-30\n\n### Fixed\n- Reverted old SSL cert, it needs to exist as default cert until new certs are generated.\n\n## [31.0.0] - 2020-04-30\n\n### Added\n- New `magento-nginx:1.18` Docker image.\n- New `magento-elasticsearch:7.6` Docker image.\n- Documentation to install Magento directly with sample data (using `with-samples-` prefix (thanks Nexcess!).\n\n### Updated\n- The `bin/setup` helper script to enable Elasticsearch 7 and automatically reindex during installation.\n- The `docker-compose.yml` file now references the `magento-nginx:1.18-0` and `magento-elasticsearch:7.6.2-0` Docker images.\n- The `docker-compose.yml` adds the new environment variable `\"discovery.type=single-node\"` for compatibility with Elasticsearch 7.\n- The new `nginx:1.18` Docker image sets `fastcgi_buffer_size 64k;` and `fastcgi_buffers 8 128k;` directives for Magento 2.3.5 compatibility.\n\n### Removed\n- Old SSL cert being generated directly on Nginx image (deprecated).\n- References to Nginx 1.13 images (deprecated).\n\n## [30.0.3] - 2020-04-25\n\n### Updated\n- Reverted disabling Temando_Shipping module in bin/magento for sample data installation. <a href=\"https://github.com/markshust/docker-magento/issues/250\">#250</a>\n\n## [30.0.2] - 2020-04-17\n\n### Fixed\n- The `Temando_Shipping` module conflicts with sample data installation. Added fix to `bin/magento` helper script to disable this module, install sample data, then re-enable it.\n\n### Added\n- Added a `--remove-orphans` flag to `bin/start` script to remove orphaned containers (applicable to cron service).\n\n## [30.0.1] - 2020-03-18\n\n### Updated\n- Increased php.ini `memory_limit` to `4G` to get PHPUnit tests to pass\n- Increased php.ini `upload_max_filesize` and `post_max_size` to `100M` just to prevent issues from being filed in the future\n\n### Added\n- New PHP image tags `7.2-fpm-9`, `7.3-fpm-6`\n\n## [30.0.0] - 2020-03-09\n\n### Added\n- Added new CLI to connect to MySQL\n\n### Updated\n- Updated readme with new bin/mysql documentation\n- n98-magerun2 to install on exec of `bin/n98-magerun2` instead of `bin/setup` script\n- Increased `max_input_vars` to `10000` to prevent Invalid Form Post submission errors\n\n### Fixed\n- Fixed PHP ioncube module missing ioncube.so file\n- Disable TTY on `bin/setup-ssl-ca script`\n- Fixed `bin/copytocontainer` script not copying files to proper directory\n\n## [29.0.0] - 2020-01-31\n\n### Fixed\n- Fixed implementation of grunt. The grunt-cli is now installed globally on the image and doesn't depend on contents of the `vendor` directory.\n\n## [28.0.0] - 2020-01-31\n\n### Updated\n- Upgraded NodeJS to 10.x, as 8.x was failing to install npm due to source repository updates <a href=\"https://github.com/markshust/docker-magento/issues/210\">#210</a>\n\n### Removed\n- Removed PHP 7.1 image from filesystem as it has been deprecated. If you need to reference the last version of these images, they are available at <a href=\"https://github.com/markshust/docker-magento/tree/27.2.0/images/php/7.1\">https://github.com/markshust/docker-magento/tree/27.2.0/images/php/7.1</a>\n\n## [27.2.0] - 2020-01-22\n\n### Added\n- Support for RabbitMQ <a href=\"https://github.com/markshust/docker-magento/pull/212\">PR #212</a>\n\n## [27.1.0] - 2020-01-20\n\n### Added\n- New `bin/setup-ssl` script to generate valid SSL certificates <a href=\"https://github.com/markshust/docker-magento/issues/211\">#211</a>\n- New `markoshust/magento-nginx:1.13-8` image containing mkcert script\n\n### Updated\n- Updated `bin/setup` to use new `bin/setup-ssl` script\n\n## [27.0.0] - 2020-01-01\n\nHappy new year! 🎉\n\n### Updated\n- Updated the PHP base images from Debian Stretch to Buster\n- Updated PHP libsodium package to `1.0.17` to support `HASH_VERSION_ARGON2ID13` <a href=\"https://github.com/markshust/docker-magento/issues/193\">#193</a>\n\n### Added\n- Built-in support for Blackfire.io\n- New PHP image tags `7.2-fpm-5`, `7.3-fpm-2`\n\n## [26.0.0] - 2019-12-30\n\n### Added\n- Ability for `src` directory to be a symlink\n\n### Fixed\n- Fixed Magento2 setup script with n98-magerun2.phar\n- Fixed dev-urn-catalog-generate script\n\n### Removed\n- All Windows-specific setup and helper scripts. This involved changing directory structure of `compose` folder, there is no longer specific `magento-2` and `magento-2-windows` specific folders. Windows support works on Docker with WSL.\n- Support for PHP 7.1 (EOL)\n\n## [25.0.0] - 2019-10-22\n\n### Added\n- Full parity with [Magento Cloud PHP extensions](https://devdocs.magento.com/guides/v2.3/cloud/project/project-conf-files_magento-app.html#php-extensions)\n\n### Updated\n- Optimized Dockerfile install order and layer usage for all PHP images (7.1, 7.2 & 7.3)\n- Updated few lib dependencies in Dockerfiles with new versions\n- Pegged Composer to version 1.9.0 for predictability, moved to lower layer so updating version doesn't require full rebuild of all layers\n\n## [24.2.0] - 2019-10-18\n\n### Fixed\n- Fixed logic of `bin/copyfromcontainer` and `bin/copytocontainer` so subdirectories are now properly copied from and to the container\n\n### Added\n- The `bin/fixowns` script now includes the ability to fix ownerships at the subdirectory level\n- The `bin/copyfromcontainer` and `bin/copytocontainer` scripts now fixes permissions and ownerships of just the subdirectories that are copied\n\n## [24.1.2] - 2019-10-15\n\n### Fixed\n- Fixed `bin/copyfromcontainer` and `bin/copytocontainer` referencing incorrect destination file locations\n\n## [24.1.1] - 2019-10-11\n\n### Fixed\n- Added missing `bin/pwa-studio` and `bin/setup-pwa-studio` bash scripts\n\n## [24.1.0] - 2019-10-10\n\n### Added\n- Documented in README how to retrieve `bin/update` file for previous versions that did not include it\n- Added `hirak/prestissimo` composer package to `bin/setup` helper script for much faster composer installs\n- Downloaded archive installs are now cached on the user's machine, so subsequent installs of Magento will no longer re-download the archive if previously downloaded. Downloaded archives are stored in the `~/.docker-magento` folder.\n\n### Fixed\n- There is an invalid checksum reference in the Nexcess archive of 2.3.3, replaced checksum reference in `bin/setup` to resolve the error\n\n### Removed\n- The previous CHANGELOG for `24.0.0` referenced `vertex/module-tax` being removed but for some reason it was not removed, now it is\n\n## [24.0.0] - 2019-10-09\n\n### Added\n- New PHP docker image version `7.3-fpm-0` for Magento 2.3.3 support\n- New Elasticsearch docker image `markoshust/magento-elasticsearch:6.5.4-0` which comes bundled with icu and phonetic plugins. The initial `6.5` version is for parity with Magento Cloud.\n- New `bin/update` helper script that updates your docker-magento setup to the latest version\n- Added `.gitignore` file to project root to ignore `src` directory. It is recommended to keep your root docker config files in one repository, and your Magento code setup in another. This ensures the Magento base path lives at the top of one specific repository, which makes automated build pipelines and deployments easy to manage, and maintains compatibility with projects such as Magento Cloud.\n- Install n98-magerun2 when setup is executed, and added related `bin/n98-magerun` and `bin/devconsole` helper scripts.\n- Added `bin/setup-pwa-studio` (BETA) helper script to easily install PWA Studio, usage accepts a single parameter being the site URL you wish PWA Studio to connect to (ex. `bin/setup-pwa-studio magento2.test`)\n- Added `bin/pwa-studio` (BETA) helper script to easily run the PWA Studio NodeJS web server\n\n### Fixed\n- The `bin/dev-urn-catalog-generate` helper script has been updated for compatibility with more recent versions of PHPStorm\n\n### Removed\n- The `vertex/module-tax` Composer package installs correctly as of 2.3.0, so the line within the `bin/setup` script which prevented it from being installed was removed. If one is having issues installing an older version of Magento 2, add the following line to your `composer.json` file to prevent this package from being installed:\n\n  `{\"replace\": { \"vertex/module-tax\": \"*\" }}`\n\n## [23.2.3] - 2019-07-20\n\n### Fixed\n- The `php` base Docker image changed from Debian Stretch to Buster and broke a lot of packages, which caused a failed build for `7.1-fpm-12` & `7.2-fpm-3` tags. This update pegs the `php` Docker image to Debian Stretch.\n\n## [23.2.2] - 2019-07-17\n\n### Fixed\n- Xdebug breakpoints not triggering\n\n### Added\n- New PHP docker image versions `7.1-fpm-12`, `7.2-fpm-3`\n\n## [23.2.1] - 2019-07-11\n\n### Fixed\n- Mailhog container doesn't stop when running bin/stop\n\n## [23.2.0] - 2019-07-07\n\n### Added\n- View emails sent locally through Mailhog by visiting [http://{yourdomain}:8025](http://{yourdomain}:8025)\n\n## [23.1.1] - 2019-07-01\n\n### Updated\n- Make Dockerfile consistent between versions\n- Move Docker layers to bottom for smaller downloads, useful for those using previous versions\n- Same Docker version tag, so just remove Docker image locally and re-pull to use\n\n## [23.1.0] - 2019-06-27\n\n### Added\n- `libsodium-dev` package and `sodium` PHP extension for Magento 2.3.2 support.\n- New PHP docker versions `7.1-fpm-10`, `7.2-fpm-1`\n\n## [23.0.0] - 2019-04-02\n\n### Added\n- Allow setup without SSH credentials.\n- Documentation for connecting to MySQL.\n- `bin/status` to check container status.\n\n### Updated\n- Readme for existing installs.\n- `bin/dev-urn-catalog-generate` to look at `src` folder as project root.\n\n### Fixed\n- Readme usage of pasting command into non-standard terminal.\n\n## [22.0.0] - 2019-02-14\n\n### Added\n- Host bind mount `var/log` folder in `docker-compose.dev.yml` for debugging purposes.\n- Redis is now the default storage engine for cache and session. Massively improved performance for local dev! 🚀\n- Added commented-out line in `docker-compose.dev.yml` file to easily mount `auth.json` file, with updated usage in README\n\n### Fixed\n- Cron not working correctly\n\n## [21.1.2] - 2019-02-04\n\n### Fixed\n- Helper script `bin/fixowns` now fixes permissions on `/var/www` instead of `/var/www/html` folder.\n- Removed superfluous mounting of `~/.composer` directory in `docker-compose.dev.yml` file.\n\n## [21.1.1] - 2018-12-27\n\n### Fixed\n- Helper script `bin/copytocontainer` now calls `bin/fixowns` afterwards to ensure correct file ownerships are set.\n\n## [21.1.0] - 2018-12-26\n\n### Added\n- Helper script `bin/removevolumes` to remove docker volumes easily.\n- Added removal of `vendor` folder and force of composer install to `bin/setup` script. When installed from zip, it's possible Magento isn't installing all deps properly and assigning wrong permissions in Docker. Forcing a reinstall fixes this issue.\n- Force deploy of static content when running `bin/setup` to speed up initial requests.\n\n### Fixed\n- Fixed helper script `bin/dev-urn-catalog-generate` to copy file to host.\n\n## [21.0.0] - 2018-12-24\n\n🎅 Santa Shust wishes you a very Merry Christmas!\n\n### Changed\n- 💯 performance improvements (14 second load times now take 7 seconds!)\n  - The `bin/start` helper script no longer copies docker volumes introduced in version 18.0.0. The `docker-compose.yml` setup has been updated to only reference native Docker volumes. A new `docker-compose.dev.yml` file has been added to reference development-specific settings, including host bind mounts. Only `.composer`, `app/code`, `app/design`, `app/etc`, `composer.json`, `composer.lock`, and `nginx.conf` filesystem locations are host bind mounted. Being very specific in which files and folders are being mounted leads to drastically faster response times. The main culprit in performance penalties before was mounting `generated` and `var` folders as host bind mounts. These directories are considered \"caching\" folders and should never be host bind mounted.\n  - If you need access to specific files that are created within the container and are not host bind mounted, you can use `bin/cli` or `bin/bash` commands to go into the container to access the files. You can also use the new `bin/copyfromcontainer` and `bin/copytocontainer` bin helper scripts to copy files & folders from or to containers.\n  - If you need to host bind mount files or folders, feel free to do so within the `docker-compose.dev.yml` file! Just be aware there is a performance penalty for doing so.\n- Updated `nginx` Docker image to look for `nginx.conf` file instead of `nginx.conf.sample` file. This will now require copying the `nginx.conf.sample` file to `nginx.conf`, or using a host bind mount. This location allows overrides that aren't overridden when you upgrade Magento, and allow customizations for projects. Tagged new image as `markoshust/magento-nginx:1.13-7`.\n- The `bin/setup` helper script uses only the `docker-compose.yml` file, with only native docker volume mounts.\n- The `bin/start` helper script uses both `docker-compose.yml` and `docker-compose.dev.yml` files. Development-only specifications should now be placed within `docker-compose.dev.yml`, such as host bind volume mounts.\n- The `docker-compose.yml` file now uses a `sockdata` volume mount to mount the `/sock` directory. You may need to delete the `appdata` volume mount (`docker volume rm NAME`) and rebuild it with `bin/copytocontainer --all`.\n- Removed call to `bin/fixperms` within `bin/setup` to speed up initial installation.\n\n### Added\n- Added `bin/copyfromcontainer` and `bin/copytocontainer` helper scripts to copy folders or files from or to containers. Specify the `--all` option to copy entire web directory structure.\n- Added `bin/rootnotty` to run root commands with no TTY (needed for unassisted one-line setup with new volume setup).\n- Added `bin/fixowns` to fix filesystem ownerships within the Docker container.\n- Added `docker-compose.dev.yml` file for development-only specifications.\n\n### Removed\n- The Magento 1 version of this development environment has been deprecated and is no longer supported. PHP 5 was used as it's base, and that version has reached end-of-life. If you still wish to use this setup, please reference [compose/magento-1 on tag 20.1.1](https://github.com/markshust/docker-magento/tree/master/compose/magento-1), but please be aware these images are no longer maintained.\n- The PHP 5.6 and 7.0 images have been deprecated, as both of these versions have reached end-of-life. These versions have been removed from the README and are no longer maintained. If you still wish to use these images, please reference the [README on tag 20.1.1](https://github.com/markshust/docker-magento/blob/master/README.md), but please be aware these images are no longer maintained.\n- Removed `bin/copydir` and `bin/copydirall` helper scripts.\n\n## [20.1.1] - 2018-12-10\n\n### Fixed\n- Fixed typo in docker-compose.yml for linux\n\n## [20.1.0] - 2018-12-03\n\n### Added\n- Official support for Elasticsearch. Go to Admin > Stores > Configuration > Catalog > Catalog > Catalog Search, and select \"Elasticsarch 5.0+\" from the list of options. Keep all defaults the same, but set Elasticsearch Server Hostname to `elasticsearch`. Save, clear the cache, and run `bin/magento indexer:reindex` to enable.\n\n## [20.0.0] - 2018-11-27\n\n### Added\n- Official support for Magento 2.3 & PHP 7.2. Officially tagging `7.2-fpm-0` php image.\n\n### Updated\n- Various updates to README, including references now being made to Magento 2.3.\n- Added comments to docker-compose for fixes needed on Linux machines (volume mounts and host.docker.internal fix).\n\n### Fixed\n- Volume mount issues on linux. Updated `bin/start` to ignore call to `bin/copydirall` when ran on Linux.\n\n## [19.0.0] - 2018-10-08\n\n### Added\n- Added SSL support and made it enabled by default in the nginx config. All http requests will also be forwarded to https.\n\n## [18.1.1] - 2018-10-08\n\n### Updated\n- Magento 2 nginx configuration now includes `nginx.conf.sample` file from root installation directory for configuration, instead of having standalone configuration.\n\n## [18.0.1] - 2018-10-08\n\n### Fixed\n- Reverted old `bin/cli` usage and created `bin/clinotty` for non-tty sessions. Updated calls in `bin/setup` and other scripts where appropriate to `bin/clinotty`.\n\n## [18.0.0] - 2018-10-06\n\n### Changed\n- Changed the way bind mounts work with Docker compose and Magento 2.\n    - Note that `bin/start` now includes a call to `bin/copydirall` after the containers start. This helper script runs a `docker cp` command of all Magento directories from the container to the host. There is still a bind mount setup to `./src` root directory.\n    - There is a condition/bug within Docker that when named volumes overlap with bind mounts, the named volumes automatically sync back to the host once a `docker cp` command runs, while retaining their named volume status within the Docker container.\n    - We're tapping into this very odd bug and taking advantage of this as long as we can. Since data is still fetched from within the Docker container as a named volume, this should also allow not-so-performant computers to now run this Docker setup, as it provides near or truly native filesystem performance, since requests to these directories are still fetched through the named volume as far as Docker is concerned.\n- `bin/start` now runs in daemon mode, as we also need to run `bin/copydirall` immediately after starting containers so data syncs back to the host (and vice versa). This also eliminates the need to to have a terminal window open all the time for keeping containers running.\n\n### Added\n- Added back support for Magento 1 and PHP 5.6 containers. Magento 1 EOL will not be until 2020, so we should support these images and Docker Compose setup indefinitely for the time being.\n- Added new `bin/restart` helper script to stop and start all containers.\n- Added new `bin/remove` helper script to remove all containers.\n- Added new `bin/copydir` which copies whichever folder you wish from the container to the host.\n- Added new `bin/copydirall` which copies all Magento folders from the container to the host.\n- Added `lib/template` and `lib/onelinesetup` for much easier installation methods.\n- Added automatic Xdebug support for VS Code - no setup needed!\n\n### Removed\n- Removed `bin/initloopback` along with any references to `10.254.254.254` ip address. This may break existing Xdebug setups. Note that this ip address has been replaced with `host.docker.internal`, which should automatically resolve back to the host machine.\n\n## [17.0.1] - 2018-10-06\n\n### Removed\n- Removed bind mount of vendor folder introduced in 16.2.0 due to inconsistency issues. Update coming soon that will implement new method of bind mounting.\n\n## [17.0.0] - 2018-09-06\n\n### Removed\n- Removed idekey setting from php.ini config.\n\n### Changed\n- Simplified Xdebug configuration for PHPStorm. This will require configuration updates for all users using Xdebug within PHPStorm.\n\n### Added\n- Added support for Xdebug and VS Code.\n\n## [16.2.0] - 2018-08-29\n\n### Changed\n- Updated docker-compose.yml file to volume mount vendor folder for 50% performance increase\n\n## [16.1.0] - 2018-08-23\n\n### Added\n- Added php ssh2 extension\n\n### Deprecated\n- The PHP 5.6 release will no longer be maintained, the last released version is 16.0.0\n\n## [16.0.0] - 2018-08-22\n\n### Changed\n- Moved `dev/auth.json` to `dev/composer/auth.json`\n- Added `client_max_body_size 20M` to nginx.conf\n- Added `upload_max_filesize = 20M` and `post_max_size = 20M` to php.ini\n\n## [15.0.1] - 2018-08-03\n\n### Fixed\n- Bugs with npm permissions.\n\n## [15.0.0] - 2018-08-03\n\n### Added\n- NodeJS 8 and npm 5 added to the PHP images!\n- New PHP 7.2 image. Be aware that this hasn't yet been fully tested.\n- New helper scripts bin/grunt, bin/node, bin/npm and bin/stop.\n\n### Changed\n- All bin helper script calls from ./bin/name to bin/name.\n- Updated bin scripts for Windows, possible breaking updates.\n\n## [14.0.1] - 2018-07-28\n\n### Fixed\n- Magento 2.2.5 requires username and password to be different values. Updated to dummy \"John Smith\" user persona with username `john.smith` and password `password123`.\n\n## [14.0.0] - 2018-07-21\n\n### Added\n- New `dev/auth.json` file used instead of `~/.composer/auth.json` file, so each project can have different auth credentials.\n\n### Changed\n- The `cron` service is now disabled by default. This services uses higher CPU and should probably only be enabled when working on cron-related tasks (or on production).\n"
  },
  {
    "path": "LICENSE.md",
    "content": "MIT License\n\nCopyright (c) 2016 Mage Inferno\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<h1 align=\"center\">markshust/docker-magento</h1>\n\n<div align=\"center\">\n  <p>Mark Shust's Docker Configuration for Magento</p>\n  <img src=\"https://img.shields.io/badge/magento-2.X-brightgreen.svg?logo=magento&longCache=true\" alt=\"Supported Magento Versions\" />\n  <a href=\"https://hub.docker.com/r/markoshust/magento-php/\" target=\"_blank\"><img src=\"https://img.shields.io/docker/pulls/markoshust/magento-php.svg?label=php%20docker%20pulls\" alt=\"Docker Hub Pulls - PHP\" /></a>\n  <a href=\"https://hub.docker.com/r/markoshust/magento-nginx/\" target=\"_blank\"><img src=\"https://img.shields.io/docker/pulls/markoshust/magento-nginx.svg?label=nginx%20docker%20pulls\" alt=\"Docker Hub Pulls - Nginx\" /></a>\n  <a href=\"https://github.com/markshust/docker-magento/graphs/commit-activity\" target=\"_blank\"><img src=\"https://img.shields.io/badge/maintained%3F-yes-brightgreen.svg\" alt=\"Maintained - Yes\" /></a>\n  <img src=\"https://img.shields.io/badge/apple%20silicon%20support-yes-brightgreen\" alt=\"Apple Silicon Support\" />\n  <a href=\"https://opensource.org/licenses/MIT\" target=\"_blank\"><img src=\"https://img.shields.io/badge/license-MIT-blue.svg\" /></a>\n</div>\n\n## Table of contents\n\n- [Docker Hub](#docker-hub)\n- [Free Course](#free-course)\n- [Usage](#usage)\n- [Prerequisites](#prerequisites)\n- [Setup](#setup)\n- [Updates](#updates)\n- [Custom CLI Commands](#custom-cli-commands)\n- [Misc Info](#misc-info)\n- [Known Issues](#known-issues)\n- [Alternatives](#alternatives)\n- [Credits](#credits)\n- [License](#license)\n\n## Docker Hub\n\nView Dockerfiles for the latest tags:\n\n- [markoshust/magento-nginx (Docker Hub)](https://hub.docker.com/r/markoshust/magento-nginx/)\n  - [`1.18`, `1.18-8`](images/nginx/1.18)\n  - [`1.22`, `1.22-0`](images/nginx/1.22)\n  - [`1.24`, `1.24-0`](images/nginx/1.24)\n- [markoshust/magento-php (Docker Hub)](https://hub.docker.com/r/markoshust/magento-php/)\n  - [`8.1-fpm`, `8.1-fpm-7`](images/php/8.1)\n  - [`8.2-fpm`, `8.2-fpm-6`](images/php/8.2)\n  - [`8.3-fpm`, `8.3-fpm-4`](images/php/8.3)\n  - [`8.4-fpm`, `8.4-fpm-0`](images/php/8.4)\n- [markoshust/magento-opensearch (Docker Hub)](https://hub.docker.com/r/markoshust/magento-opensearch/)\n  - [`1.2`, `1.2-0`](images/opensearch/1.2)\n  - [`2.5`, `2.5-1`](images/opensearch/2.5)\n  - [`2.12`, `2.12-0`](images/opensearch/2.12)\n- [markoshust/magento-elasticsearch (Docker Hub)](https://hub.docker.com/r/markoshust/magento-elasticsearch/)\n  - [`7.16`, `7.16-0`](images/elasticsearch/7.16)\n  - [`7.17`, `7.17-1`](images/elasticsearch/7.17)\n  - [`8.4`, `8.4-0`](images/elasticsearch/8.4)\n  - [`8.5`, `8.5-0`](images/elasticsearch/8.5)\n  - [`8.7`, `8.7-0`](images/elasticsearch/8.7)\n  - [`8.11`, `8.11-0`](images/elasticsearch/8.11)\n  - [`8.13`, `8.13-0`](images/elasticsearch/8.13)\n- [markoshust/magento-rabbitmq (Docker Hub)](https://hub.docker.com/r/markoshust/magento-rabbitmq/)\n  - [`3.9`, `3.9-0`](images/rabbitmq/3.9)\n  - [`3.11`, `3.11-1`](images/rabbitmq/3.11)\n  - [`3.12`, `3.12-0`](images/rabbitmq/3.12)\n  - [`4.1`, `4.1-0`](images/rabbitmq/4.1)\n- [markoshust/ssh (Docker Hub)](https://hub.docker.com/r/markoshust/magento-ssh/)\n  - [`latest`](images/ssh)\n\n## Free Course\n\nThis course is sponsored by <a href=\"https://m.academy\" target=\"_blank\">M.academy</a>, the simplest way to learn Magento.\n\n<a href=\"https://m.academy\" target=\"_blank\"><img src=\"docs/macademy-logo.png\" alt=\"M.academy\"></a>\n\nA free screencast course is available (which was fully refreshed in December 2021), which details the basic usage of this project:\n\n<a href=\"https://m.academy/courses/set-up-magento-2-development-environment-docker\" target=\"_blank\">\n<img src=\"docs/set-up-magento-2-development-environment-docker-og.png\" alt=\"Set Up a Magento 2 Development Environment with Docker\" width=\"400\"><br/>\nSet Up a Magento 2 Development Environment with Docker\n</a>\n\n### Course Curriculum\n\n#### Intro\n\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/36738848\" target=\"_blank\">Quick hi & welcome from Mark!</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/36738860\" target=\"_blank\">About the course format</a>\n\n#### Initial Project Setup\n\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/9205849\" target=\"_blank\">Install Docker Desktop & configure preferences</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/8974570\" target=\"_blank\">Set up Magento with the automated onelinesetup script</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/9064259\" target=\"_blank\">Set up Magento manually from a custom Git branch</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/9283467\" target=\"_blank\">Set up Docker for an existing Magento project</a>\n\n#### The Basics of docker-magento\n\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/9064258\" target=\"_blank\">Execute docker-magento helper scripts</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/9331008\" target=\"_blank\">Start, stop, restart and check container status</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/9064269\" target=\"_blank\">Execute bin/magento and composer within Docker containers</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/36150902\" target=\"_blank\">Install Magento sample data</a>\n\n#### Docker Filesystem & Data Volumes\n\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/9064334\" target=\"_blank\">Understand Docker volumes & host bind mounts</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/9064338\" target=\"_blank\">Manage files & folders within Docker containers</a>\n\n#### PhpStorm\n\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/9748834\" target=\"_blank\">Set up a docker-magento project in PhpStorm</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/9763893\" target=\"_blank\">Set up the Magento PhpStorm plugin</a>\n\n#### Code Quality Tools\n\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/52640115\" target=\"_blank\">Configure PHPCS (PHP CodeSniffer) for Magento</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/52642491\" target=\"_blank\">Configure PHPCSF (PHP CodeSniffer Fixer) for Magento</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/52643314\" target=\"_blank\">Configure PHPMD (PHP Mess Detector) for Magento</a>\n\n#### Xdebug\n\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/9064478\" target=\"_blank\">Install the Xdebug helper browser plugin for Chrome & PhpStorm</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/9064482\" target=\"_blank\">Enable disable check the status of Xdebug</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/9064615\" target=\"_blank\">Configure PhpStorm for Xdebug connections</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/9064617\" target=\"_blank\">Trigger an Xdebug breakpoint in PhpStorm</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/36677538\" target=\"_blank\">Trigger an Xdebug breakpoint for CLI commands in PhpStorm</a>\n\n#### Customize Server Configurations\n\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/36702830\" target=\"_blank\">Understand the docker-compose application structure</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/36702861\" target=\"_blank\">Increase the PHP memory limit in php.ini</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/9064349\" target=\"_blank\">Increase the Nginx request timeout in nginx.conf</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/36703258\" target=\"_blank\">Increase the MySQL buffer pool size with command or in my.cnf</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/9064350\" target=\"_blank\">Install a new PHP extension by building a custom Docker image</a>\n- <a href=\"https://courses.m.academy/courses/set-up-magento-2-development-environment-docker/lectures/14780970\" target=\"_blank\">Configure multi-store instances in Docker with Nginx</a>\n\n## Usage\n\nThis configuration is intended to be used as a Docker-based development environment for Magento 2.\n\nFolders:\n\n- `images`: Docker images for nginx and php\n- `compose`: sample setups with Docker Compose\n\n> The Magento 1 version of this development environment has been deprecated and is no longer supported. PHP 5 was used as it's base, and that version has reached end-of-life. If you still wish to use this setup, please reference [compose/magento-1 on tag 20.1.1](https://github.com/markshust/docker-magento/tree/20.1.1/compose/magento-1), but please be aware these images are no longer maintained.\n\n## Prerequisites\n\nThis setup assumes you are running Docker on a computer with at least 6GB of RAM allocated to Docker, a dual-core, and an SSD hard drive. [Download & Install Docker Desktop](https://www.docker.com/products/docker-desktop).\n\nThis configuration has been tested on Mac & Linux. Windows is supported through the use of Docker on WSL.\n\n## Setup\n\n### Automated Setup (New Project)\n\n```bash\n# Create your project directory then go into it:\nmkdir -p ~/Sites/magento\ncd $_\n\n# Run this automated one-liner from the directory you want to install your project.\ncurl -s https://raw.githubusercontent.com/markshust/docker-magento/master/lib/onelinesetup | bash -s -- magento.test community 2.4.8-p3\n```\n\nThe `magento.test` above defines the hostname to use, `community` is the Magento edition, and the `2.4.8-p3` defines the Magento version to install. Note that since we need a write to `/etc/hosts` for DNS resolution, you will be prompted for your system password during setup.\n\nAfter the one-liner above completes running, you should be able to access your site at `https://magento.test`.\n\n#### Install sample data and development modules\n\nAfter the above installation is complete, you can initialize the development environment with sample data and dev-related modules with:\n\n```bash\nbin/init\n```\n\n### Manual Setup\n\nSame result as the one-liner above. Just replace `magento.test` references with the hostname that you wish to use.\n\n#### New Projects\n\n```bash\n# Create your project directory then go into it:\nmkdir -p ~/Sites/magento\ncd $_\n\n# Download the Docker Compose template:\ncurl -s https://raw.githubusercontent.com/markshust/docker-magento/master/lib/template | bash\n\n# Download the version of Magento you want to use with:\nbin/download community 2.4.8-p3\n# You can specify the edition (community, enterprise, mageos) and version (2.4.7-p3, 1.0.5, etc.)\n# If no arguments are passed in, the edition defaults to \"community\"\n# If no version is specified, it defaults to the most recent version defined in `bin/download`\n\n# or for Magento core development:\n# bin/start --no-dev\n# bin/setup-composer-auth\n# bin/cli git clone git@github.com:magento/magento2.git .\n# bin/cli git checkout 2.4-develop\n# bin/composer install\n\n# Run the setup installer for Magento:\nbin/setup magento.test\n\n# Initialize development environment with sample data and dev-related modules:\nbin/init\n\nopen https://magento.test\n```\n\n#### Existing Projects\n\n```bash\n# Create your project directory then go into it:\nmkdir -p ~/Sites/magento\ncd $_\n\n# Download the Docker Compose template:\ncurl -s https://raw.githubusercontent.com/markshust/docker-magento/master/lib/template | bash\n\n# Take a backup of your existing database:\nbin/mysqldump > ~/Sites/existing/magento.sql\n\n# Replace with existing source code of your existing Magento instance:\ncp -R ~/Sites/existing src\n# or: git clone git@github.com:myrepo.git src\n\n# Start some containers, copy files to them and then restart the containers:\nbin/start --no-dev\nbin/copytocontainer --all ## Initial copy will take a few minutes...\n\n# If your vendor directory was empty, populate it with:\nbin/composer install\n\n# Import existing database:\nbin/mysql < ../existing/magento.sql\n\n# Update database connection details to use the above Docker MySQL credentials:\n# Also note: creds for the MySQL server are defined at startup from env/db.env\n# vi src/app/etc/env.php\n\n# Import app-specific environment settings:\nbin/magento app:config:import\n\n# Create a DNS host entry and setup Magento base url\nbin/setup-domain yoursite.test\n\nbin/restart\n\nopen https://magento.test\n```\n\n### Elasticsearch vs OpenSearch\nOpenSearch is set as the default search engine when setting up this project. Follow the instructions below if you want to use Elasticsearch instead:\n1. Comment out or remove the `opensearch` container in both the [`compose.yaml`](https://github.com/markshust/docker-magento/blob/master/compose/compose.yaml#L69-L84) and [`compose.healthcheck.yaml`](https://github.com/markshust/docker-magento/blob/master/compose/compose.healthcheck.yaml#L36-L41) files\n2. Uncomment the `elasticsearch` container in both the [`compose.yaml`](https://github.com/markshust/docker-magento/blob/master/compose/compose.yaml#L86-L106) and [`compose.healthcheck.yaml`](https://github.com/markshust/docker-magento/blob/master/compose/compose.healthcheck.yaml#L43-L48) files\n3. Update the `bin/setup-install` command to use the Elasticsearch rather than OpenSearch. Change:\n\n```\n--opensearch-host=\"$OPENSEARCH_HOST\" \\\n--opensearch-port=\"$OPENSEARCH_PORT\" \\\n```\n\nto:\n\n```\n--elasticsearch-host=\"$ES_HOST\" \\\n--elasticsearch-port=\"$ES_PORT\" \\\n\n```\n\n## Updates\n\nTo update your project to the latest version of `docker-magento`, run:\n\n```\nbin/update\n```\n\nWe recommend keeping your docker config files in version control, so you can monitor the changes to files after updates. After reviewing the code updates and ensuring they updated as intended, run `bin/restart` to restart your containers to have the new configuration take effect.\n\nIt is recommended to keep your root docker config files in one repository, and your Magento code setup in another. This ensures the Magento base path lives at the top of one specific repository, which makes automated build pipelines and deployments easy to manage, and maintains compatibility with projects such as Magento Cloud.\n\n## Custom CLI Commands\n\n- `bin/analyse`: Run `phpstan analyse` within the container to statically analyse code, passing in directory to analyse. Ex. `bin/analyse app/code`\n- `bin/bash`: Drop into the bash prompt of your Docker container. The `phpfpm` container should be mainly used to access the filesystem within Docker.\n- `bin/blackfire`: Disable or enable Blackfire. Accepts argument `disable`, `enable`, or `status`. Ex. `bin/blackfire enable`\n- `bin/cache-clean`: Access the [cache-clean](https://github.com/mage2tv/magento-cache-clean) CLI. Note the watcher is automatically started at startup in `bin/start`. Ex. `bin/cache-clean config full_page`\n- `bin/check-dependencies`: Provides helpful recommendations for dependencies tailored to the chosen Magento version.\n- `bin/cli`: Run any CLI command without going into the bash prompt. Ex. `bin/cli ls`\n- `bin/clinotty`: Run any CLI command with no TTY. Ex. `bin/clinotty chmod u+x bin/magento`\n- `bin/cliq`: The same as `bin/cli`, but pipes all output to `/dev/null`. Useful for a quiet CLI, or implementing long-running processes.\n- `bin/composer`: Run the composer binary. Ex. `bin/composer install`\n- `bin/configure-linux`: Adds the Docker container's IP address to the system's `/etc/hosts` file if it's not already present. Additionally, it prompts the user to open port 9003 for Xdebug if desired.\n- `bin/copyfromcontainer`: Copy folders or files from container to host. Ex. `bin/copyfromcontainer vendor`\n- `bin/copytocontainer`: Copy folders or files from host to container. Ex. `bin/copytocontainer --all`\n- `bin/create-user`: Create either an admin user or customer account.\n- `bin/cron`: Start or stop the cron service. Ex. `bin/cron start`\n- `bin/debug-cli`: Enable Xdebug for bin/magento, with an optional argument of the IDE key. Defaults to PHPSTORM Ex. `bin/debug-cli enable PHPSTORM`\n- `bin/deploy`: Runs the standard Magento deployment process commands. Pass extra locales besides `en_US` via an optional argument. Ex. `bin/deploy nl_NL`\n- `bin/dev-test-run`: Facilitates running PHPUnit tests for a specified test type (e.g., integration). It expects the test type as the first argument and passes any additional arguments to PHPUnit, allowing for customization of test runs. If no test type is provided, it prompts the user to specify one before exiting.\n- `bin/dev-urn-catalog-generate`: Generate URN's for PhpStorm and remap paths to local host. Restart PhpStorm after running this command.\n- `bin/devconsole`: Alias for `bin/n98-magerun2 dev:console`\n- `bin/docker-compose`: Support V1 (`docker-compose`) and V2 (`docker compose`) docker compose command, and use custom configuration files, such as `compose.yml` and `compose.dev.yml`\n- `bin/docker-start`: Start the Docker application (either Orbstack or Docker Desktop)\n- `bin/docker-stats`: Display container name and container ID, status for CPU, memory usage(in MiB and %), and memory limit of currently-running Docker containers.\n- `bin/download`: Download specific Magento version from Composer to the container, with optional arguments of the type (\"community\" [default], \"enterprise\", or \"mageos\") and version ([default] is defined in `bin/download`). Ex. `bin/download mageos` or `bin/download enterprise 2.4.8`\n- `bin/ece-patches`: Run the Cloud Patches CLI. Ex: `bin/ece-tools apply`\n- `bin/fixowns`: This will fix filesystem ownerships within the container.\n- `bin/fixperms`: This will fix filesystem permissions within the container.\n- `bin/grunt`: Run the grunt binary. Ex. `bin/grunt exec`\n- `bin/init`: Initialize development environment with sample data and dev-related modules.\n- `bin/install-php-extensions`: Install PHP extension in the container. Ex. `bin/install-php-extensions sourceguardian`\n- `bin/log`: Monitor the Magento log files. Pass no params to tail all files. Ex. `bin/log debug.log`\n- `bin/magento`: Run the Magento CLI. Ex: `bin/magento cache:flush`\n- `bin/magento-version`: Determine the Magento version installed in the current environment.\n- `bin/mftf`: Run the Magento MFTF. Ex: `bin/mftf build:project`\n- `bin/mysql`: Run the MySQL CLI with database config from `env/db.env`. Ex. `bin/mysql -e \"EXPLAIN core_config_data\"` or`bin/mysql < magento.sql`\n- `bin/mysqldump`: Backup the Magento database. Ex. `bin/mysqldump > magento.sql`\n- `bin/n98-magerun2`: Access the [n98-magerun2](https://github.com/netz98/n98-magerun2) CLI. Ex: `bin/n98-magerun2 dev:console`\n- `bin/node`: Run the node binary. Ex. `bin/node --version`\n- `bin/npm`: Run the npm binary. Ex. `bin/npm install`\n- `bin/phpcbf`: Auto-fix PHP_CodeSniffer errors with Magento2 options. Ex. `bin/phpcbf <path-to-extension>`\n- `bin/phpcs`: Run PHP_CodeSniffer with Magento2 options. Ex. `bin/phpcs <path-to-extension>`\n- `bin/phpcs-json-report`: Run PHP_CodeSniffer with Magento2 options and save to `report.json` file. Ex. `bin/phpcs-json-report <path-to-extension>`\n- `bin/pwa-studio`: (BETA) Start the PWA Studio server. Note that Chrome will throw SSL cert errors and not allow you to view the site, but Firefox will.\n- `bin/redis`: Run a command from the redis container. Ex. `bin/redis redis-cli monitor`\n- `bin/remove`: Remove all containers.\n- `bin/removeall`: Remove all containers, networks, volumes, and images, calling `bin/stopall` before doing so.\n- `bin/removenetwork`: Remove a network associated with the current directory's name.\n- `bin/removevolumes`: Remove all volumes.\n- `bin/restart`: Stop and then start all containers.\n- `bin/root`: Run any CLI command as root without going into the bash prompt. Ex `bin/root apt-get install nano`\n- `bin/rootnotty`: Run any CLI command as root with no TTY. Ex `bin/rootnotty chown -R app:app /var/www/html`\n- `bin/setup`: Run the Magento setup process to install Magento from the source code, with optional domain name. Defaults to `magento.test`. Ex. `bin/setup magento.test`\n- `bin/setup-composer-auth`: Setup authentication credentials for Composer.\n- `bin/setup-domain`: Setup Magento domain name. Ex: `bin/setup-domain magento.test`\n- `bin/setup-grunt`: Install and configure Grunt JavaScript task runner to compile .less files\n- `bin/setup-install`: Automates the installation process for a Magento instance.\n- `bin/setup-integration-tests`: Script to set up integration tests.\n- `bin/setup-pwa-studio`: (BETA) Install PWA Studio (requires NodeJS and Yarn to be installed on the host machine). Pass in your base site domain, otherwise the default `master-7rqtwti-mfwmkrjfqvbjk.us-4.magentosite.cloud` will be used. Ex: `bin/setup-pwa-studio magento.test`.\n- `bin/setup-pwa-studio-sampledata`: This script makes it easier to install Venia sample data. Pass in your base site domain, otherwise the default `master-7rqtwti-mfwmkrjfqvbjk.us-4.magentosite.cloud` will be used. Ex: `bin/setup-pwa-studio-sampledata magento.test`.\n- `bin/setup-ssl`: Generate an SSL certificate for one or more domains. Ex. `bin/setup-ssl magento.test foo.test`\n- `bin/setup-ssl-ca`: Generate a certificate authority and copy it to the host.\n- `bin/spx`: Disable or enable output compression to enable or disable SPX. Accepts params `disable` (default) or `enable`. Ex. `bin/spx enable`\n- `bin/start`: Start all containers, good practice to use this instead of `docker-compose up -d`, as it may contain additional helpers.\n- `bin/status`: Check the container status.\n- `bin/stop`: Stop all project containers.\n- `bin/stopall`: Stop all docker running containers\n- `bin/test/unit`: Run unit tests for a specific path. Ex. `bin/test/unit my-dir`\n- `bin/test/unit-coverage`: Generate unit tests coverage reports, saved to the folder `dev/tests/unit/report`. Ex. `bin/test/unit-coverage my-dir`\n- `bin/test/unit-xdebug`: Run unit tests with Xdebug. Ex. `bin/test/unit-xdebug my-dir`\n- `bin/update`: Update your project to the most recent version of `docker-magento`.\n- `bin/xdebug`: Set a custom xdebug.mode (Ex. `bin/xdebug debug`) or check the current status and get all available modes (Ex. `bin/xdebug`)\n\n## Misc Info\n\n### Install fails because project directory is not empty\n\nThe most common issue with a failed docker-magento install is getting this error:\n\n```\nProject directory \"/var/www/html/.\" is not empty error\n```\n\nThis message occurs when _something_ fails to execute correctly during an install, and a subsequent install is re-attempted. Unfortunately, when attempting a second (or third) install, it's possible the `src` directory is no longer empty. This prevents Composer from creating the new project because it needs to create new projects within an empty directory.\n\nThe workaround to this is that once you have fixed the issue that was initially preventing your install from completing, you will need to completely remove the assets from the previously attempted install before attempting a subsequent install.\n\nYou can do this by running:\n\n```\nbin/removeall\ncd ..\nrm -rf yourproject\n```\n\nThen, create your new project directory again so you can attempt the install process again. The `bin/removeall` command removes all previous Docker containers & volumes related to the specific project directory you are within. You can then attempt the install process again.\n\n### Accessing the Magento Backend\n\nAfter successfully installing the Magento environment, you can access the backend by following these steps:\n\n1. Open your web browser and go to the following URL: `https://magento.test/admin/`.\n\n2. Use the following default credentials to log in:\n- **Username:** `john.smith`\n- **Password:** `password123`\n\n3. Upon logging in, you might be prompted to configure Two-Factor Authentication (2FA). This emails you a code to log in with (which you can check with Mailcatcher by visiting `http://{yourdomain}:1080`). By default, the email address used for this purpose is:\n- **Email:** `john.smith@gmail.com`\n\nIf you are testing in a local development environment and wish to disable 2FA, you can do so by installing [Mark's DisableTwoFactorAuth module](https://github.com/markshust/magento2-module-disabletwofactorauth).\n\n### Caching\n\nFor an improved developer experience, caches are automatically refreshed when related files are updated, courtesy of [cache-clean](https://github.com/mage2tv/magento-cache-clean). This means you can keep all of the standard Magento caches enabled, and this script will only clear the specific caches needed, and only when necessary.\n\nTo disable this functionality, uncomment the last line in the `bin/start` file to disable the watcher.\n\n### Database\n\nThe hostname of each service is the name of the service within the `compose.yaml` file. So for example, MySQL's hostname is `db` (not `localhost`) when accessing it from within a Docker container. Elasticsearch's hostname is `elasticsearch`.\n\nTo connect to the MySQL CLI tool of the Docker instance, run:\n\n```\nbin/mysql\n```\n\nYou can use the `bin/mysql` script to import a database, for example a file stored in your local host directory at `magento.sql`:\n\n```\nbin/mysql < magento.sql\n```\n\nYou also can use `bin/mysqldump` to export the database. The file will appear in your local host directory at `magento.sql`:\n\n```\nbin/mysqldump > magento.sql\n```\n\n> Getting an \"Access denied, you need (at least one of) the SUPER privilege(s) for this operation.\" message when running one of the above lines? Try running it as root with:\n> ```\n> bin/clinotty mysql -hdb -uroot -pmagento magento < src/backup.sql\n> ```\n> You can also remove the DEFINER lines from the MySQL backup file with:\n> ```\n> sed 's/\\sDEFINER=`[^`]*`@`[^`]*`//g' -i src/backup.sql\n> ```\n\n### Composer Authentication\n\nFirst setup Magento Marketplace authentication (details in the [DevDocs](https://experienceleague.adobe.com/en/docs/commerce-operations/installation-guide/prerequisites/authentication-keys)).\n\nCopy `src/auth.json.sample` to `src/auth.json`. Then, update the username and password values with your Magento public and private keys, respectively. Finally, copy the file to the container by running `bin/copytocontainer auth.json`.\n\n### Email / Mailcatcher\n\nView emails sent locally through Mailcatcher by visiting [http://{yourdomain}:1080](http://{yourdomain}:1080). In order to use mailcatcher, set the mailserver host to `mailcatcher` and set port to `1025`. Note that this port (`1025`) is different from the mailcatcher interface to read the emails (`1080`).\n\n### Redis\n\nRedis is now the default cache and session storage engine, and is automatically configured & enabled when running `bin/setup` on new installs.\n\nUse the following lines to enable Redis on existing installs:\n\n**Enable for Cache:**\n\n`bin/magento setup:config:set --cache-backend=redis --cache-backend-redis-server=redis --cache-backend-redis-db=0`\n\n**Enable for Full Page Cache:**\n\n`bin/magento setup:config:set --page-cache=redis --page-cache-redis-server=redis --page-cache-redis-db=1`\n\n**Enable for Session:**\n\n`bin/magento setup:config:set --session-save=redis --session-save-redis-host=redis --session-save-redis-log-level=4 --session-save-redis-db=2`\n\nYou may also monitor Redis by running: `bin/redis redis-cli monitor`\n\nFor more information about Redis usage with Magento, <a href=\"https://devdocs.magento.com/guides/v2.4/config-guide/redis/redis-session.html\" target=\"_blank\">see the DevDocs</a>.\n\n### PhpMyAdmin\n\nPhpMyAdmin is built into the `compose.dev.yaml` file. Simply open `http://localhost:8080` in a web browser.\n\nThese credentials can be used to log in to PhpMyAdmin:\n\n- **Username:** `magento`\n- **Password:** `magento`\n\n### Xdebug & VS Code\n\nInstall and enable the PHP Debug extension from the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=felixfbecker.php-debug).\n\nOtherwise, this project now automatically sets up Xdebug support with VS Code. If you wish to set this up manually, please see the [`.vscode/launch.json`](https://github.com/markshust/docker-magento/blame/master/compose/.vscode/launch.json) file.\n\n### Xdebug & VS Code in a WSL2 environment\n\nInstall and enable the PHP Debug extension from the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=felixfbecker.php-debug).\n\nOtherwise, this project now automatically sets up Xdebug support with VS Code. If you wish to set this up manually, please see the [`.vscode/launch.json`](https://github.com/markshust/docker-magento/blame/master/compose/.vscode/launch.json) file.\n\n1. In VS Code, make sure that it's running in a WSL window, rather than in the default window.\n2. Install the [`PHP Debug`](https://marketplace.visualstudio.com/items?itemName=xdebug.php-debug) extension on VS Code.\n3. Create a new configuration file inside the project. Go to the `Run and Debug` section in VS Code, then click on `create a launch.json file`.\n4. Attention to the following configs inside the file:\n    * The port must be the same as the port on the xdebug.ini file.\n    ```bash\n      bin/cli cat /usr/local/etc/php/php.ini\n    ```\n    ```bash\n      memory_limit = 4G\n      max_execution_time = 1800\n      zlib.output_compression = On\n      cgi.fix_pathinfo = 0\n      date.timezone = UTC\n\n      xdebug.mode = debug\n      xdebug.client_host = host.docker.internal\n      xdebug.idekey = PHPSTORM\n      xdebug.client_port=9003\n      #You can uncomment the following line to force the debug with each request\n      #xdebug.start_with_request=yes\n\n      upload_max_filesize = 100M\n      post_max_size = 100M\n      max_input_vars = 10000\n    ```\n    * The pathMappings should have the same folder path as the project inside the Docker container.\n    ```json\n      {\n          \"version\": \"0.2.0\",\n          \"configurations\": [\n              {\n                  \"name\": \"Listen for XDebug\",\n                  \"type\": \"php\",\n                  \"request\": \"launch\",\n                  \"port\": 9003,\n                  \"pathMappings\": {\n                      \"/var/www/html\": \"${workspaceFolder}\"\n                  },\n                  \"hostname\": \"localhost\"\n              }\n          ]\n      }\n    ```\n5. Run the following command in the Windows Powershell. It allows WSL through the firewall, otherwise breakpoints might not be hitten.\n    ```powershell\n    New-NetFirewallRule -DisplayName \"WSL\" -Direction Inbound  -InterfaceAlias \"vEthernet (WSL)\"  -Action Allow\n    ```\n\n### Xdebug & PhpStorm\n\n1.  First, install the [Chrome Xdebug helper](https://chrome.google.com/webstore/detail/xdebug-helper/eadndfjplgieldjbigjakmdgkmoaaaoc). After installed, right click on the Chrome icon for it and go to Options. Under IDE Key, select PhpStorm from the list to set the IDE Key to \"PHPSTORM\", then click Save.\n\n2.  Next, enable Xdebug debugging in the PHP container by running: `bin/xdebug enable`.\n\n3.  Then, open `PhpStorm > Preferences > PHP` and configure:\n\n    * `CLI Interpreter`\n        * Create a new interpreter from the `From Docker, Vagrant, VM...` list.\n        * Select the Docker Compose option.\n        * For Server, select `Docker`. If you don't have Docker set up as a server, create one and name it `Docker`.\n        * For Configuration files, add both the `compose.yaml` and `compose.dev.yaml` files from your project directory.\n        * For Service, select `phpfpm`, then click OK.\n        * Name this CLI Interpreter `phpfpm`, then click OK again.\n\n    * `Path mappings`\n        * There is no need to define a path mapping in this area.\n\n4. Open `PhpStorm > Preferences > PHP > Debug` and ensure Debug Port is set to `9000,9003`.\n\n5. Open `PhpStorm > Preferences > PHP > Servers` and create a new server:\n\n    * For the Name, set this to the value of your domain name (ex. `magento.test`).\n    * For the Host, set this to the value of your domain name (ex. `magento.test`).\n    * Keep port set to `80`.\n    * Check the \"Use path mappings\" box and map `src` to the absolute path of `/var/www/html`.\n\n6. Go to `Run > Edit Configurations` and create a new `PHP Remote Debug` configuration.\n\n    * Set the Name to the name of your domain (ex. `magento.test`).\n    * Check the `Filter debug connection by IDE key` checkbox, select the Server you just setup.\n    * For IDE key, enter `PHPSTORM`. This value should match the IDE Key value set by the Chrome Xdebug Helper.\n    * Click OK to finish setting up the remote debugger in PHPStorm.\n\n7. Open up `pub/index.php` and set a breakpoint near the end of the file.\n\n    * Start the debugger with `Run > Debug 'magento.test'`, then open up a web browser.\n    * Ensure the Chrome Xdebug helper is enabled by clicking on it and selecting Debug. The icon should turn bright green.\n    * Navigate to your Magento store URL, and Xdebug should now trigger the debugger within PhpStorm at the toggled breakpoint.\n\n### SSH\n\nSince version `40.0.0`, this project supports connecting to Docker with SSH/SFTP. This means that if you solely use either PhpStorm or VSCode, you no longer need to selectively mount host volumes in order to gain bi-directional sync capabilities from host to container. This will enable full speed in the native filesystem, as all files will be stored directly in the `appdata` container volume, rather than being synced from the host. This is especially useful if you'd like to sync larger directories such as `generated`, `pub` & `vendor`.\n\nCopy `compose.dev-ssh.yaml` to `compose.dev.yaml` before installing Magento to take advantage of this setup. Then, create an SFTP connection at  Preferences -> Build, Execution, Deployment -> Deployment. Connect to `localhost` and use `app` for the username & password. You can set additional options for working with Magento in PhpStorm at Preferences -> Build, Execution, Deployment -> Deployment -> Options.\n\nNote that you must use your IDE's SSH/SFTP functionality, otherwise changes will not be synced. To re-sync your host environment at any time, run:\n\n```\nbin/copyfromcontainer --all\n```\n\n### Linux\n\nRunning Docker on Linux should be pretty straight-forward. Note that you need to run some [post install commands](https://docs.docker.com/install/linux/linux-postinstall/) as well as [installing Docker Compose](https://docs.docker.com/compose/install/) before continuing. These steps are taken care of automatically with Docker Desktop, but not on Linux.\n\nCopy `compose.dev-linux.yaml` to `compose.dev.yaml` before installing Magento to take advantage of this setup.\n\n#### Install necessary dependencies\n\nTo ensure proper functionality, the docker-magento setup requires a few system dependencies to be installed on Linux. To install these dependencies, please execute the following command from the terminal:\n\n```\nsudo apt install curl libnss3-tools unzip rsync\n```\n\n#### The host.docker.internal hostname\n\nThe `host.docker.internal` hostname is used on Docker for Mac/Windows to reference the Docker daemon. On Linux, this hostname does not exist.\n\nThis hostname is [hard-coded in the php.ini file](images/php/8.1/conf/php.ini#L8). To make this hostname resolve, add `\"host.docker.internal:172.17.0.1\"` to the `app.extra_hosts` parameter of `compose.yaml`, replacing `172.17.0.1` with the result of:\n\n```\ndocker run --rm alpine ip route | awk 'NR==1 {print $3}'\n```\n\nYou must also create a new entry in your `/etc/hosts` file using the same IP:\n\n```\n172.17.0.1 host.docker.internal\n```\n\n#### Extra settings\n\nTo enable Xdebug on Linux, you may also need to open port 9003 on the firewall by running:\n\n```\nsudo iptables -A INPUT -p tcp --dport 9003 -j ACCEPT\n```\n\nYou may also have to increase a virtual memory map count on the host system which is required by [Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/current/vm-max-map-count.html).\n\nAdd the following line to the `/etc/sysctl.conf` file on your host:\n\n```\nvm.max_map_count=262144\n```\n\n### Blackfire.io\n\nThese docker images have built-in support for Blackfire.io. To use it, first register your server ID and token with the Blackfire agent:\n\n```\nbin/root blackfire-agent --register --server-id={YOUR_SERVER_ID} --server-token={YOUR_SERVER_TOKEN}\n```\n\nNext, open up the `bin/start` helper script and uncomment the line:\n\n```\n#bin/root /etc/init.d/blackfire-agent start\n```\n\nFinally, restart the containers with `bin/restart`. After doing so, everything is now configured and you can use a browser extension to profile your Magento store with Blackfire.\n\n### Cloudflare Tunnel\n\nThese docker images have built-in support for Cloudflare Tunnel. It can be useful for testing implementations that require some third-party integrations involving allow-listing domains. Since your local app cannot be allow-listed by other services, you can use Cloudflare Tunnel to get a public hostname that can be allow-listed on the other service.\n\nTo use it:\n\n- First, create a tunnel in Cloudflare Zero Trust and add the token to `env/cloudflare.env`.\n- Next, uncomment Cloudflare Tunnel section in main `compose.yaml`.\n- Finally, restart the containers with `bin/restart`.\n\nIn Cloudflare Tunnel configuration, configure the service URL to use type `HTTPS` and a URL of `{name of app container}:{HTTPS port of app container}`. For examplem, `demo-app-1:8443`. Enable the `No TLS Verify` option, since our local certificates are self-signed. You should now be able to access your app via the public hostname defined in Cloudflare Tunnel.\n\nNOTE: Do not leave instances with Cloudflare Tunnel enabled running long-term, as your instance is publicly available to the world. You should ideally turn off tunnel container once testing is finished.\n\n### MFTF\n\nTo work with MFTF you will need to first enable the `selenium` image in the `compose.dev.yaml` file. Then, you will need to run the following.\n\n1. Run mftf build process `bin/mftf build:project`. This should build the basic setup for mftf in your project.\n2. Update the `extra_host` values to match your Magento URL and IP in `compose.dev.yaml`.\n3. Update the values in `src/dev/tests/acceptance/.env`, including adding the new line `SELENIUM_HOST=selenium` to define the host Codeception should connect to.\n4. Run a sample test `bin/mftf run:test AdminLoginSuccessfulTest`.\n5. Update your `nginx.conf` file to allow access to the dev section with the following, before the final `deny all` section:\n\n```\nlocation ~* ^/dev/tests/acceptance/utils($|/) {\n    root $MAGE_ROOT;\n    location ~ ^/dev/tests/acceptance/utils/command.php {\n        fastcgi_pass   fastcgi_backend;\n        fastcgi_index  index.php;\n        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;\n        include        fastcgi_params;\n    }\n}\n```\n\nFor debugging, you can connect to the selenium image using a VCN client.\n\n- Connect with the VCN option and `127.0.0.1:5900`, (default password: `secret`)\n- Run `bin/mftf doctor` to validate all sections are setup correctly.\n\nFind more info [here](https://devdocs.magento.com/mftf/docs/getting-started.html) about mftf configuration.\n\n### Grunt + LiveReload for Frontend Development\n\n#### Create a new theme and make it active\n\nCreate your new theme at `app/design/frontend/VendorName/theme-name`, with the related `composer.json`, `registration.php` and `theme.xml` files.\n\nMake your new theme active at Admin > Content > Design > Configuration. Click the Edit button next to Global Scope, and set the Applied Theme to your new theme name, and click Save Configuration.\n\n#### Load the LiveReload client file\n\nTo create a connection to LiveReload, you'll need to insert the LiveReload script into your theme. You can do this by creating a file in your theme at `Magento_Theme/layout/default_head_blocks.xml` with the contents:\n\n```xml\n<?xml version=\"1.0\"?>\n<page xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"urn:magento:framework:View/Layout/etc/page_configuration.xsd\">\n    <head>\n        <script defer=\"true\" src=\"/livereload.js?port=443\" src_type=\"url\"/>\n    </head>\n</page>\n```\n\nThe \"?port=443\" parameter is important, otherwise the `livereload.js` script won't work.\n\nWhile we're at it, let's also create an initial LESS file so we have something to test. Create a new file in your theme at `web/css/source/_extend.less` with the contents:\n\n```css\nbody {\n    background: white;\n}\n```\n\nYou'll need to clear the Magento cache to enable your module, and make sure this layout XML update is properly loaded.\n\nYour new theme should now be active at `https://yourdomain.test`. Since this is a new theme, it should appear the same as the parent theme defined in your theme.xml file, which is usually Blank.\n\n#### Set up Grunt\n\nRun `bin/setup-grunt`. This will set up the Grunt configuration files for your new theme. It's important to run this step after setting up your new theme, not before.\n\n#### Start the Grunt watcher\n\nGrunt can watch for filesystem changes by running `bin/grunt watch`. You can optionally pass in the `--verbose` or `-v` flag to toggle verbose mode on. This will let you know what's going on under the hood, so you can be sure it is compiling & watching the correct files, and updating them as changes are made.\n\n#### LiveReload Browser extension\n\nRunning the `grunt watch` process also spawns the LiveReload server. Your browser needs to connect to this server, and this is done by installing the [LiveReload browser extension](https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei?hl=en).\n\nIn your browser, be sure to also open the Google Chrome Dev Tools, go to the Network tab, and click \"Disable cache\". This will ensure the browser does not long-cache static file assets, such as JavaScript & CSS files, which is important during development.\n\nEnsure the LiveReload browser icon has been toggled on, and refresh the page. We can confirm the LiveReload script is loaded by going to the Network tab and ensuring the `livereload.js` file is loaded, and that it also spawns off a new websocket request to `/livereload`.\n\n#### Test LiveReload\n\nSince this is all set, let's update the CSS file to a different background color:\n\n```css\nbody {\n    background: blue;\n}\n```\n\nUpon saving this file, we will see the Grunt watcher detect the changes, and your browser should automatically load the new style without you needing to refresh the page, and without a full browser refresh.\n\n### PHP-SPX\n\nThe images also have additional profiler-tracers built-in to the <a href=\"https://github.com/NoiseByNorthwest/php-spx/tree/master#web-ui\" target=\"_blank\">Web UI.</a>\n\nTo access the control panel, just open the following URL: `https://magento.test/?SPX_UI_URI=/`\n\n**Suggested Configuration**\n\n- Enabled: Checked\n- Automatic start: Checked\n- Profile internal functions: Unchecked\n- Sampling: 5ms\n- Max profiling depth: Unlimited\n- Additional metrics: Unselected\n\nChanging any options on this page set cookies for the domain for these settings. After then visiting a page on the frontend, you can navigate back to the GUI and scroll to the bottom of the page, and click the related request to view the trace of the request & response.\n\nProfiling is also possible via command line, or curl:\n\n```\nSPX_REPORT=full SPX_ENABLED=1 SPX_SAMPLING_PERIOD=5000 bin/magento {command_name}\ncurl --cookie \"SPX_REPORT=full; SPX_ENABLED=1; SPX_SAMPLING_PERIOD=5000\" https://magento.test/\n```\n\nAdditional information of how to work with SPX is available at https://www.youtube.com/watch?v=xk-JiBLsKfA\n\n## Known Issues\n\nThere are currently no large known issues or workarounds needed to use docker-magento with your Magento project. If you find any, please [report them](https://github.com/markshust/docker-magento/issues)!\n\n## Alternatives\n\n### Mappia\n\nIf you love using `docker-magento` for local development and are starting to think about how to run Magento in production, [Mappia](https://www.mappia.io/) may be a great next step.\n\n[Mappia](https://www.mappia.io/) is a production-grade tool for deploying Magento onto Kubernetes. It takes the same container-first approach you’re already using locally and extends it to scalable, secure, and repeatable deployments in the cloud—without forcing you to re-architect your application.\n\nIf `docker-magento` helps you build Magento locally, [Mappia](https://www.mappia.io/) helps you operate it confidently in production—using the same container mindset, just at production scale.\n\n## Credits\n\n### M.academy\n\nThis course is sponsored by <a href=\"https://m.academy\" target=\"_blank\">M.academy</a>, the simplest way to learn Magento.\n\n<a href=\"https://m.academy\" target=\"_blank\"><img src=\"docs/macademy-logo.png\" alt=\"M.academy\"></a>\n\n### Mark Shust\n\nMy name is Mark Shust and I'm the creator of this repo. I'm a <a href=\"https://www.credly.com/users/mark-shust/badges\" target=\"_blank\">6X Adobe Commerce Certified Developer</a> and have been involved with Magento since the early days (v0.8!). I create technical education courses full-time for my company, <a href=\"https://m.academy\" target=\"_blank\">M.academy</a>.\n\n- <a href=\"https://m.academy/courses\" target=\"_blank\">🖥️ See my Magento lessons & courses</a>\n- <a href=\"https://m.academy/articles\" target=\"_blank\">📖 Read my technical articles</a>\n- <a href=\"https://youtube.com/markshust\" target=\"_blank\">🎥 Watch my YouTube videos</a>\n- <a href=\"https://www.linkedin.com/in/MarkShust/\" target=\"_blank\">🔗 Connect on LinkedIn</a>\n- <a href=\"https://twitter.com/MarkShust\" target=\"_blank\">🐦 Follow me on X</a>\n- <a href=\"mailto:mark@m.academy\">💌 Contact me</a>\n\n## License\n\n[MIT](https://opensource.org/licenses/MIT)\n"
  },
  {
    "path": "compose/.gitignore",
    "content": "src/\n"
  },
  {
    "path": "compose/.vscode/launch.json",
    "content": "{\n  \"configurations\": [\n    {\n      \"name\": \"Listen for XDebug\",\n      \"type\": \"php\",\n      \"request\": \"launch\",\n      \"pathMappings\": {\n        \"/var/www/html\": \"${workspaceFolder}\"\n      },\n      \"port\": 9003,\n    }\n  ]\n}\n"
  },
  {
    "path": "compose/Makefile",
    "content": "SHELL := /usr/bin/env bash\n\nargs = `arg=\"$(filter-out $(firstword $(MAKECMDGOALS)),$(MAKECMDGOALS))\" && echo $${arg:-${1}}`\n\ngreen  = $(shell printf \"\\e[32;01m$1\\e[0m\")\nyellow = $(shell printf \"\\e[33;01m$1\\e[0m\")\nred    = $(shell printf \"\\e[33;31m$1\\e[0m\")\n\nformat = $(shell printf \"%-40s %s\" \"$(call green,bin/$1)\" $2)\n\ncomma:= ,\n\n.DEFAULT_GOAL:=help\n\n%:\n\t@:\n\nhelp:\n\t@echo \"\"\n\t@echo \"$(call yellow,Use the following CLI commands:)\"\n\t@echo \"$(call red,===============================)\"\n\t@echo \"$(call format,analyse,'Run \\`phpstan analyse\\` within the container to statically analyse code$(comma) passing in directory to analyse.')\"\n\t@echo \"$(call format,bash,'Drop into the bash prompt of your Docker container.')\"\n\t@echo \"$(call format,blackfire,'Disable or enable Blackfire. Accepts argument \\`disable\\`$(comma) \\`enable\\`$(comma) or \\`status\\`.')\"\n\t@echo \"$(call format,cache-clean,'Access the cache-clean CLI.')\"\n\t@echo \"$(call format,check-dependencies,'Provides helpful recommendations for dependencies.')\"\n\t@echo \"$(call format,cli,'Run any CLI command without going into the bash prompt.')\"\n\t@echo \"$(call format,clinotty,'Run any CLI command with no TTY.')\"\n\t@echo \"$(call format,cliq,'Run any CLI command but pipe all output to /dev/null.')\"\n\t@echo \"$(call format,composer,'Run the composer binary.')\"\n\t@echo \"$(call format,configure-linux,'Adds the Docker container IP address to /etc/hosts if not already present. Optionally enables port 9003 for Xdebug.')\"\n\t@echo \"$(call format,copyfromcontainer,'Copy folders or files from container to host.')\"\n\t@echo \"$(call format,copytocontainer,'Copy folders or files from host to container.')\"\n\t@echo \"$(call format,create-user,'Create either an admin user or customer account.')\"\n\t@echo \"$(call format,cron,'Start or stop the cron service.')\"\n\t@echo \"$(call format,debug-cli,'Enable Xdebug for bin/magento$(comma) with an optional argument of the IDE key. Defaults to PHPSTORM.')\"\n\t@echo \"$(call format,deploy,'Runs the standard Magento deployment process commands. Pass extra locales besides \\`en_US\\` via an optional argument.')\"\n\t@echo \"$(call format,dev-test-run,'Facilitates running PHPUnit tests for a specified test type.')\"\n\t@echo \"$(call format,dev-urn-catalog-generate,'Generate URNs for PHPStorm and remap paths to local host.')\"\n\t@echo \"$(call format,devconsole,'Alias for n98-magerun2 dev:console.')\"\n\t@echo \"$(call format,docker-compose,'Support V1 (\\`docker-compose\\`) and V2 (\\`docker compose\\`) docker compose command$(comma) and use custom configuration files.')\"\n\t@echo \"$(call format,docker-start,'Start the Docker application (either Orbstack or Docker Desktop).')\"\n\t@echo \"$(call format,docker-stats,'Display status for CPU$(comma) memory usage$(comma) and memory limit of currently-running Docker containers.')\"\n\t@echo \"$(call format,download,'Download & extract specific Magento version to the src directory.')\"\n\t@echo \"$(call format,ece-patches,'Run the Cloud Patches CLI.')\"\n\t@echo \"$(call format,fixowns,'This will fix filesystem ownerships within the container.')\"\n\t@echo \"$(call format,fixperms,'This will fix filesystem permissions within the container.')\"\n\t@echo \"$(call format,grunt,'Run the grunt binary.')\"\n\t@echo \"$(call format,init,'Initialize development environment with sample data and dev-related modules.')\"\n\t@echo \"$(call format,install-php-extensions,'Install PHP extension in the container.')\"\n\t@echo \"$(call format,log,'Monitor the Magento log files. Pass no params to tail all files.')\"\n\t@echo \"$(call format,magento,'Run the Magento CLI.')\"\n\t@echo \"$(call format,magento-version,'Determine the Magento version installed in the current environment.')\"\n\t@echo \"$(call format,mftf,'Run the Magento MFTF.')\"\n\t@echo \"$(call format,mysql,'Run the MySQL CLI with database config from env/db.env.')\"\n\t@echo \"$(call format,mysqldump,'Backup the Magento database.')\"\n\t@echo \"$(call format,n98-magerun2,'Access the n98-magerun2 CLI.')\"\n\t@echo \"$(call format,node,'Run the node binary.')\"\n\t@echo \"$(call format,npm,'Run the npm binary.')\"\n\t@echo \"$(call format,phpcbf,'Auto-fix PHP_CodeSniffer errors with Magento2 options.')\"\n\t@echo \"$(call format,phpcs,'Run PHP_CodeSniffer with Magento2 options.')\"\n\t@echo \"$(call format,phpcs-json-report,'Run PHP_CodeSniffer with Magento2 options and save to \\`report.json\\` file.')\"\n\t@echo \"$(call format,pwa-studio,'(BETA) Start the PWA Studio server.')\"\n\t@echo \"$(call format,redis,'Run a command from the redis container.')\"\n\t@echo \"$(call format,remove,'Remove all containers.')\"\n\t@echo \"$(call format,removeall,'Remove all containers$(comma) networks$(comma) volumes and images.')\"\n\t@echo \"$(call format,removenetwork,'Remove a network associated with the current directory name.')\"\n\t@echo \"$(call format,removevolumes,'Remove all volumes.')\"\n\t@echo \"$(call format,restart,'Stop and then start all containers.')\"\n\t@echo \"$(call format,root,'Run any CLI command as root without going into the bash prompt.')\"\n\t@echo \"$(call format,rootnotty,'Run any CLI command as root with no TTY.')\"\n\t@echo \"$(call format,setup,'Run the Magento setup process$(comma) with optional domain name.')\"\n\t@echo \"$(call format,setup-composer-auth,'Setup authentication credentials for Composer.')\"\n\t@echo \"$(call format,setup-domain,'Setup Magento domain name.')\"\n\t@echo \"$(call format,setup-grunt,'Install and configure Grunt JavaScript task runner.')\"\n\t@echo \"$(call format,setup-install,'Automates the installation process for a Magento instance.')\"\n\t@echo \"$(call format,setup-integration-tests,'Script to set up integration tests.')\"\n\t@echo \"$(call format,setup-pwa-studio,'(BETA) Install PWA Studio.')\"\n\t@echo \"$(call format,setup-pwa-studio-sampledata,'This script makes it easier to install Venia sample data.')\"\n\t@echo \"$(call format,setup-ssl,'Generate an SSL certificate for one or more domains.')\"\n\t@echo \"$(call format,setup-ssl-ca,'Generate a certificate authority and copy it to the host.')\"\n\t@echo \"$(call format,spx,'Disable or enable output compression to enable or disable SPX.')\"\n\t@echo \"$(call format,start,'Start all containers.')\"\n\t@echo \"$(call format,status,'Check the container status.')\"\n\t@echo \"$(call format,stop,'Stop all project containers.')\"\n\t@echo \"$(call format,stopall,'Stop all docker running containers.')\"\n\t@echo \"$(call format,test,'Run unit tests for a specific path.')\"\n\t@echo \"$(call format,update,'Update your project to the latest version of docker-magento.')\"\n\t@echo \"$(call format,xdebug,'Set a custom xdebug.mode$(comma) or check the current status and get all available modes . Accepts optional argument of mode \\`off\\`$(comma) \\`debug\\`$(comma) etc.')\"\n\n\nanalyse:\n\t@./bin/analyse $(call args)\n\nbash:\n\t@./usr/bin/env bash\n\ncache-clean:\n\t@./bin/cache-clean $(call args)\n\t\ncheck-dependencies:\n\t@./bin/check-dependencies\n\ncli:\n\t@./bin/cli $(call args)\n\nclinotty:\n\t@./bin/clinotty $(call args)\n\ncliq:\n\t@./bin/cliq $(call args)\n\ncomposer:\n\t@./bin/composer $(call args)\n\nconfigure-linux:\n\t@./bin/configure-linux\n\ncopyfromcontainer:\n\t@./bin/copyfromcontainer $(call args)\n\ncopytocontainer:\n\t@./bin/copytocontainer $(call args)\n\ncron:\n\t@./bin/cron $(call args)\n\ndebug-cli:\n\t@./bin/debug-cli $(call args)\n\t\ndeploy:\n\t@./bin/deploy $(call args)\n\t\ndev-test-run:\n\t@./bin/dev-test-run\n\t\ndev-urn-catalog-generate:\n\t@./bin/dev-urn-catalog-generate\n\ndevconsole:\n\t@./bin/devconsole\n\ndocker-compose:\n\t@./bin/docker-compose\n\t\ndocker-stats:\n\t@./bin/docker-stats\n\t\ndownload:\n\t@./bin/download $(call args)\n\nfixowns:\n\t@./bin/fixowns $(call args)\n\nfixperms:\n\t@./bin/fixperms $(call args)\n\t\ngrunt:\n\t@./bin/grunt $(call args)\n\ninstall-php-extensions:\n\t@./bin/install-php-extensions $(call args)\n\t\nlog:\n\t@./bin/log $(call args)\n\t\nmagento:\n\t@./bin/magento $(call args)\n\t\nmagento-version:\n\t@./bin/magento-version\n\nmftf:\n\t@./bin/mftf $(call args)\n\nmysql:\n\t@./bin/mysql $(call args)\n\nmysqldump:\n\t@./bin/mysqldump $(call args)\n\nn98-magerun2:\n\t@./bin/n98-magerun2 $(call args)\n\nnode:\n\t@./bin/node $(call args)\n\nnpm:\n\t@./bin/npm $(call args)\n\t\nphpcbf:\n\t@./bin/phpcbf $(call args)\n\t\nphpcs:\n\t@./bin/phpcs $(call args)\n\t\nphpcs-json-report:\n\t@./bin/phpcs-json-report $(call args)\n\npwa-studio:\n\t@./bin/pwa-studio\n\nredis:\n\t@./bin/redis $(call args)\n\nremove:\n\t@./bin/remove\n\nremoveall:\n\t@./bin/removeall\n\nremovenetwork:\n\t@./bin/removenetwork\n\t\nremovevolumes:\n\t@./bin/removevolumes\n\nrestart:\n\t@./bin/restart $(call args)\n\nroot:\n\t@./bin/root $(call args)\n\nrootnotty:\n\t@./bin/rootnotty $(call args)\n\nsetup:\n\t@./bin/setup $(call args)\n\nsetup-composer-auth:\n\t@./bin/setup-composer-auth\n\nsetup-domain:\n\t@./bin/setup-domain $(call args)\n\t\nsetup-grunt:\n\t@./bin/setup-grunt\n\t\nsetup-install:\n\t@./bin/setup-install $(call args)\n\nsetup-integration-tests:\n\t@./bin/setup-integration-tests\n\t\nsetup-pwa-studio:\n\t@./bin/setup-pwa-studio $(call args)\n\nsetup-pwa-studio-sampledata:\n\t@./bin/setup-pwa-studio-sampledata $(call args)\n\t\nsetup-ssl:\n\t@./bin/setup-ssl $(call args)\n\nsetup-ssl-ca:\n\t@./bin/setup-ssl-ca\n\nspx:\n\t@./bin/spx $(call args)\n\t\nstart:\n\t@./bin/start $(call args)\n\nstatus:\n\t@./bin/status\n\nstop:\n\t@./bin/stop $(call args)\n\nstopall:\n\t@./bin/stopall $(call args)\n\t\nupdate:\n\t@./bin/update\n\nxdebug:\n\t@./bin/xdebug $(call args)\n"
  },
  {
    "path": "compose/bin/analyse",
    "content": "#!/usr/bin/env bash\nbin/cli vendor/bin/phpstan analyse \"$@\"\n"
  },
  {
    "path": "compose/bin/bash",
    "content": "#!/usr/bin/env bash\nbin/cli bash\n"
  },
  {
    "path": "compose/bin/blackfire",
    "content": "#!/usr/bin/env bash\n\nS=$(bin/clinotty cat /usr/local/etc/php/conf.d/blackfire.ini | grep -iGc '\\;extension=blackfire.so');\n\nblackfire_status() {\n    if [[ $S == 1 ]]; then\n        echo \"Blackfire is disabled.\"\n    else\n        echo \"Blackfire is enabled.\"\n    fi\n}\n\nblackfire_toggle() {\n    if [[ $S == 1 ]]; then\n        blackfire_enable\n    else\n        blackfire_disable\n    fi\n}\n\nblackfire_enable() {\n    if [[ $S == 1 ]]; then\n        bin/root sed -i -e 's/^;extension=blackfire.so/extension=blackfire.so/g' /usr/local/etc/php/conf.d/blackfire.ini\n        sleep 1\n        bin/restart phpfpm\n        echo \"Blackfire has been enabled.\"\n    else\n        echo \"Blackfire is already enabled.\"\n    fi\n}\n\nblackfire_disable() {\n    if [[ $S == 0 ]]; then\n        bin/root sed -i -e 's/^extension=blackfire.so/;extension=blackfire.so/g' /usr/local/etc/php/conf.d/blackfire.ini\n        sleep 1\n        bin/restart phpfpm\n        echo \"Blackfire has been disabled.\"\n    else\n        echo \"Blackfire is already disabled.\"\n    fi\n}\n\nfirstArgLetter=\"$(echo \"$1\" | head -c 1)\"\n\nif [[ $firstArgLetter == \"d\" ]]; then\n    blackfire_disable\nelif [[ $firstArgLetter == \"e\" ]]; then\n    blackfire_enable\nelif [[ $firstArgLetter == \"t\" ]]; then\n    blackfire_toggle\nelif [[ $firstArgLetter == \"s\" ]]; then\n    blackfire_status\nelse\n    printf \"Please specify either 'disable', 'enable', 'status' or 'toggle' as an argument.\\nEx: bin/blackfire status\\n\"\nfi\n"
  },
  {
    "path": "compose/bin/cache-clean",
    "content": "#!/usr/bin/env bash\nCOMPOSER_GLOBAL=/var/www/.composer-global\nCACHE_CLEAN=${COMPOSER_GLOBAL}/vendor/bin/cache-clean.js\n\nif ! bin/cliq ls $CACHE_CLEAN; then\n  echo \"Installing devtools metapackage, just a moment...\"\n  bin/cliq mkdir -p ${COMPOSER_GLOBAL}\n  bin/composer require --working-dir=${COMPOSER_GLOBAL} --quiet markshust/magento2-metapackage-devtools-cli:^1.0\n  echo \"Devtools installed.\"\nfi\n\nif [ \"$1\" == \"--watch\" ]; then\n  # Kill duplicate watch process\n  WATCH_PID=$(bin/clinotty ps -eaf | grep \"$CACHE_CLEAN --quiet --watch\" | grep -v grep | awk '{print $2}')\n  if [[ \"\" !=  \"$WATCH_PID\" ]]; then\n    bin/cliq kill -9 \"$WATCH_PID\"\n  fi\n\n  # Run watch mode in the background\n  bin/cliq $CACHE_CLEAN --quiet --watch &\nelse\n  bin/cli $CACHE_CLEAN \"$@\"\nfi\n"
  },
  {
    "path": "compose/bin/check-dependencies",
    "content": "#!/usr/bin/env bash\n\n# Define colors for formatting\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nYELLOW='\\033[0;33m'\nBLUE='\\033[0;34m'\nNC='\\033[0m' # No Color\n\n# Function to display the script header\nshow_header() {\n    echo -e \"${GREEN}============================================${NC}\"\n    echo -e \"${GREEN}   Magento 2 System Requirements Checker${NC}\"\n    echo -e \"${GREEN}============================================${NC}\"\n    echo\n}\n\n# Function to display version groups\nshow_version_groups() {\n    echo -e \"${BLUE}Available Magento version groups:${NC}\"\n    echo \"1) 2.4.7.x (2.4.7, 2.4.7-p1, 2.4.7-p2, 2.4.7-p3)\"\n    echo \"2) 2.4.6.x (2.4.6 through 2.4.6-p8)\"\n    echo \"3) 2.4.5.x (2.4.5 through 2.4.5-p10)\"\n    echo \"4) 2.4.4.x (2.4.4 through 2.4.4-p11)\"\n    echo \"5) 2.4.3.x (2.4.3-p3)\"\n    echo \"6) 2.4.2.x (2.4.2-p2)\"\n    echo\n}\n\n# Function to display requirements for a specific version group\nshow_requirements() {\n    local version_group=$1\n    echo -e \"${GREEN}System Requirements for Magento ${version_group}:${NC}\"\n    echo -e \"${YELLOW}Required Components:${NC}\"\n    \n    case $version_group in\n        \"2.4.7.x\")\n            echo \"• PHP: 8.3, 8.2\"\n            echo \"• Composer: 2.7\"\n            echo \"• Database:\"\n            echo \"  - MySQL: 8.0\"\n            echo \"  - MariaDB: 10.6\"\n            echo \"• Search: \"\n            echo \"  - Elasticsearch: 8.11\"\n            echo \"  - OpenSearch: 2.12\"\n            echo \"• Cache/Session:\"\n            echo \"  - Redis: 7.2\"\n            echo \"• Message Queue:\"\n            echo \"  - RabbitMQ: 3.13\"\n            echo \"• Web Server:\"\n            echo \"  - Apache: 2.4\"\n            echo \"  - Nginx: 1.24\"\n            echo \"• Varnish: 7.5\"\n            echo -e \"${BLUE}Supported AWS Services:${NC}\"\n            echo \"• Aurora (MySQL): 8.0\"\n            echo \"• S3: ✔️\"\n            echo \"• MQ: 3.11.20\"\n            echo \"• ElastiCache: Redis7.0\"\n            echo \"• OpenSearch: 2.11\"\n            ;;\n        \"2.4.6.x\")\n            echo \"• PHP: 8.2, 8.1\"\n            echo \"• Composer: 2.2\"\n            echo \"• Database:\"\n            echo \"  - MySQL: 8.0\"\n            echo \"  - MariaDB: 10.6\"\n            echo \"• Search: \"\n            echo \"  - Elasticsearch: 8.11, 7.17\"\n            echo \"  - OpenSearch: 2.12\"\n            echo \"• Cache/Session:\"\n            echo \"  - Redis: 7.0\"\n            echo \"• Message Queue:\"\n            echo \"  - RabbitMQ: 3.13\"\n            echo \"• Web Server:\"\n            echo \"  - Apache: 2.4\"\n            echo \"  - Nginx: 1.24\"\n            echo \"• Varnish: 7.5\"\n            echo -e \"${BLUE}Supported AWS Services:${NC}\"\n            echo \"• Aurora (MySQL): 8.0\"\n            echo \"• S3: ✔️\"\n            echo \"• MQ: 3.9.16\"\n            echo \"• ElastiCache: Redis6.2\"\n            echo \"• OpenSearch: 1.2\"\n            ;;\n        \"2.4.5.x\")\n            echo \"• PHP: 8.1\"\n            echo \"• Composer: 2.2\"\n            echo \"• Database:\"\n            echo \"  - MySQL: 8.0\"\n            echo \"  - MariaDB: 10.4\"\n            echo \"• Search: \"\n            echo \"  - Elasticsearch: 7.17\"\n            echo \"  - OpenSearch: 1.2\"\n            echo \"• Cache/Session:\"\n            echo \"  - Redis: 6.2\"\n            echo \"• Message Queue:\"\n            echo \"  - RabbitMQ: 3.11, 3.9\"\n            echo \"• Web Server:\"\n            echo \"  - Apache: 2.4\"\n            echo \"  - Nginx: 1.24\"\n            echo \"• Varnish: 7.3\"\n            echo -e \"${BLUE}Supported AWS Services:${NC}\"\n            echo \"• Aurora (MySQL): 8.0\"\n            echo \"• S3: ✔️\"\n            echo \"• MQ: 3.9.13\"\n            echo \"• ElastiCache: Redis6\"\n            echo \"• OpenSearch: 1.2\"\n            ;;\n        \"2.4.4.x\")\n            echo \"• PHP: 8.1\"\n            echo \"• Composer: 2.2\"\n            echo \"• Database:\"\n            echo \"  - MySQL: 8.0\"\n            echo \"  - MariaDB: 10.4\"\n            echo \"• Search: \"\n            echo \"  - Elasticsearch: 7.17\"\n            echo \"  - OpenSearch: 1.2\"\n            echo \"• Cache/Session:\"\n            echo \"  - Redis: 6.2\"\n            echo \"• Message Queue:\"\n            echo \"  - RabbitMQ: 3.9\"\n            echo \"• Web Server:\"\n            echo \"  - Apache: 2.4\"\n            echo \"  - Nginx: 1.24\"\n            echo \"• Varnish: 7.3\"\n            echo -e \"${YELLOW}NOTE: Supports MySQL 8.0.0 through 8.0.28 only${NC}\"\n            echo -e \"${BLUE}Supported AWS Services:${NC}\"\n            echo \"• Aurora (MySQL): 8.0\"\n            echo \"• S3: ✔️\"\n            echo \"• MQ: 3.9.13\"\n            echo \"• ElastiCache: Redis6\"\n            echo \"• OpenSearch: 1.2\"\n            ;;\n        \"2.4.3.x\")\n            echo \"• PHP: 7.4\"\n            echo \"• Composer: 1\"\n            echo \"• Database:\"\n            echo \"  - MySQL: 8.0\"\n            echo \"  - MariaDB: 10.4\"\n            echo \"• Search: \"\n            echo \"  - Elasticsearch: 7.16\"\n            echo \"  - OpenSearch: 1.2\"\n            echo \"• Cache/Session:\"\n            echo \"  - Redis: 6.0\"\n            echo \"• Message Queue:\"\n            echo \"  - RabbitMQ: 3.8\"\n            echo \"• Web Server:\"\n            echo \"  - Apache: 2.4\"\n            echo \"  - Nginx: 1.18\"\n            echo \"• Varnish: 6.5\"\n            echo -e \"${BLUE}Supported AWS Services:${NC}\"\n            echo \"• Aurora (MySQL): 5.7\"\n            echo \"• S3: ✔️\"\n            echo \"• MQ: 3.8.11\"\n            echo \"• ElastiCache: Redis6\"\n            echo \"• Elasticsearch: 7.9\"\n            ;;\n        \"2.4.2.x\")\n            echo \"• PHP: 7.4\"\n            echo \"• Composer: 1\"\n            echo \"• Database:\"\n            echo \"  - MySQL: 8.0\"\n            echo \"  - MariaDB: 10.4\"\n            echo \"• Search: \"\n            echo \"  - Elasticsearch: 7.9\"\n            echo \"• Cache/Session:\"\n            echo \"  - Redis: 6.0\"\n            echo \"• Message Queue:\"\n            echo \"  - RabbitMQ: 3.8\"\n            echo \"• Web Server:\"\n            echo \"  - Apache: 2.4\"\n            echo \"  - Nginx: 1.18\"\n            echo \"• Varnish: 6.4\"\n            echo -e \"${BLUE}Supported AWS Services:${NC}\"\n            echo \"• S3: ✔️\"\n            echo \"• Elasticsearch: 7.9\"\n            ;;\n        *)\n            echo -e \"${RED}Version group not found${NC}\"\n            ;;\n    esac\n}\n\n# Function to show additional information\nshow_additional_info() {\n    echo -e \"${BLUE}Additional Information:${NC}\"\n    echo \"• Full system requirements documentation: https://experienceleague.adobe.com/docs/commerce-operations/installation-guide/system-requirements.html\"\n    echo \"• Magento DevDocs: https://developer.adobe.com/commerce/docs/\"\n    echo \"• Security Best Practices: https://experienceleague.adobe.com/docs/commerce-operations/implementation-playbook/best-practices/security/overview.html\"\n}\n\n# Main script execution\nclear\nshow_header\n\nwhile true; do\n    show_version_groups\n    echo -e \"${YELLOW}Options:${NC}\"\n    echo \"1-6) Select version group\"\n    echo \"i) Additional Information\"\n    echo \"q) Quit\"\n    echo\n    read -r -p \"Enter your choice: \" choice\n    \n    case $choice in\n        q|Q) \n            echo -e \"${GREEN}Thank you for using the Magento System Requirements Checker!${NC}\"\n            exit 0\n            ;;\n        i|I)\n            clear\n            show_additional_info\n            ;;\n        1) \n            clear\n            show_requirements \"2.4.7.x\"\n            ;;\n        2)\n            clear\n            show_requirements \"2.4.6.x\"\n            ;;\n        3)\n            clear\n            show_requirements \"2.4.5.x\"\n            ;;\n        4)\n            clear\n            show_requirements \"2.4.4.x\"\n            ;;\n        5)\n            clear\n            show_requirements \"2.4.3.x\"\n            ;;\n        6)\n            clear\n            show_requirements \"2.4.2.x\"\n            ;;\n        *)\n            echo -e \"${RED}Invalid choice. Please try again.${NC}\"\n            ;;\n    esac\n    \n    echo\n    read -r -p \"Press Enter to continue...\"\n    clear\ndone\n"
  },
  {
    "path": "compose/bin/cli",
    "content": "#!/usr/bin/env bash\n[ -z \"$1\" ] && echo \"Please specify a CLI command (ex. ls)\" && exit\nbin/docker-compose exec phpfpm \"$@\"\n"
  },
  {
    "path": "compose/bin/clinotty",
    "content": "#!/usr/bin/env bash\n[ -z \"$1\" ] && echo \"Please specify a CLI command (ex. ls)\" && exit\n# -T: Disable pseudo-tty allocation\nbin/docker-compose exec -T phpfpm \"$@\"\n"
  },
  {
    "path": "compose/bin/cliq",
    "content": "#!/usr/bin/env bash\n[ -z \"$1\" ] && echo \"Please specify a CLI command (ex. ls)\" && exit\n# Without stdout and stderr\nbin/clinotty \"$@\" >/dev/null 2>&1\n"
  },
  {
    "path": "compose/bin/composer",
    "content": "#!/usr/bin/env bash\nbin/cli composer \"$@\"\n"
  },
  {
    "path": "compose/bin/configure-linux",
    "content": "#!/usr/bin/env bash\n\nif [ \"$(uname)\" == \"Darwin\" ]; then\n    echo \"This script is designed for Linux and will not work properly on macOS.\"\nelse\n    # Get the IP address from the Docker container\n    docker_ip=$(docker run --rm alpine ip route | awk 'NR==1 {print $3}')\n\n    # Check if the IP address already exists in /etc/hosts\n    if grep -q \"$docker_ip host.docker.internal\" /etc/hosts; then\n        echo \"The entry already exists in /etc/hosts. No action needed.\"\n    else\n        # Add a new entry to /etc/hosts\n        echo \"$docker_ip host.docker.internal\" | sudo tee -a /etc/hosts\n        echo \"A new entry in the /etc/hosts file has been created\"\n    fi\n\n    # Ask the user whether to execute the iptables command\n    read -r -p \"Do you want to open port 9003 for Xdebug? (y/n): \" choice\n    if [ \"$choice\" == \"y\" ]; then\n        sudo iptables -A INPUT -p tcp --dport 9003 -j ACCEPT\n        echo \"Port 9003 has been opened for xdebug.\"\n    fi\n\n    echo \"Tasks completed successfully\"\nfi\n"
  },
  {
    "path": "compose/bin/copyfromcontainer",
    "content": "#!/usr/bin/env bash\n[ -z \"$1\" ] && echo \"Please specify a directory or file to copy from container (ex. vendor, --all)\" && exit\n\nCONTAINER_ID=$(bin/docker-compose ps -q phpfpm | awk '{print $1}')\nREAL_SRC=$(cd -P \"src\" >/dev/null && pwd)\nif [ ! -d \"$REAL_SRC\" ]; then\n  mkdir -p \"$REAL_SRC\"\nfi\n\nif [ \"$1\" == \"--all\" ]; then\n  docker cp \"$CONTAINER_ID\":/var/www/html/./ \"$REAL_SRC/\"\n  echo \"Completed copying all files from container to host\"\nelse\n  if [ -f \"$1\" ] ; then\n    docker cp \"$CONTAINER_ID\":/var/www/html/\"$1\" \"$REAL_SRC/$1\"\n  else\n    docker cp \"$CONTAINER_ID\":/var/www/html/\"$1\" \"$REAL_SRC/$(dirname \"$1\")\"\n  fi\n  echo \"Completed copying $1 from container to host\"\nfi\n"
  },
  {
    "path": "compose/bin/copytocontainer",
    "content": "#!/usr/bin/env bash\n[ $# -eq 0 ] && echo \"Please specify one or more directories/files to copy to container (ex. vendor, --all)\" && exit 1\n\nCONTAINER_ID=$(bin/docker-compose ps -q phpfpm | awk '{print $1}')\nREAL_SRC=$(cd -P \"src\" >/dev/null && pwd)\n\nfor ARG in \"$@\"; do\n  if [ \"$ARG\" == \"--all\" ]; then\n    docker cp \"$REAL_SRC/./\" \"$CONTAINER_ID\":/var/www/html/\n    echo \"Completed copying all files from host to container\"\n    bin/fixowns\n    bin/fixperms\n  else\n    if [ -f \"$REAL_SRC/$ARG\" ]; then\n      docker cp \"$REAL_SRC/$ARG\" \"$CONTAINER_ID\":/var/www/html/\"$ARG\"\n    else\n      docker cp \"$REAL_SRC/$ARG\" \"$CONTAINER_ID\":/var/www/html/\"$(dirname \"$ARG\")\"\n    fi\n    echo \"Completed copying $ARG from host to container\"\n    bin/fixowns \"$ARG\"\n    bin/fixperms \"$ARG\"\n  fi\ndone\n"
  },
  {
    "path": "compose/bin/create-user",
    "content": "#!/usr/bin/env bash\n\nread -r -p \"Create an admin (a) or a customer (c)? [a/c]: \" account_type\n[[ \"$account_type\" == [Aa] ]] && read -r -p \"Username: \" USERNAME\nread -r -p \"Email: \" EMAIL\nread -r -p \"Password (at least 8 characters): \" PASSWORD\nread -r -p \"First Name: \" FIRSTNAME\nread -r -p \"Last Name: \" LASTNAME\n\nif [[ \"$account_type\" == [Aa] ]]; then\n  bin/magento admin:user:create \\\n    --admin-user=\"${USERNAME}\" \\\n    --admin-password=\"${PASSWORD}\" \\\n    --admin-email=\"${EMAIL}\" \\\n    --admin-firstname=\"${FIRSTNAME}\" \\\n    --admin-lastname=\"${LASTNAME}\"\nelif [[ \"$account_type\" == [Cc] ]]; then\n  bin/n98-magerun2 customer:create \"${EMAIL}\" \"${PASSWORD}\" \"${FIRSTNAME}\" \"${LASTNAME}\"\nelse\n    echo \"Invalid option. Please choose either a or c.\"\nfi\n"
  },
  {
    "path": "compose/bin/cron",
    "content": "#!/usr/bin/env bash\n[ -z \"$1\" ] && echo \"Please specify a service operation (start|stop|status|restart|reload|force-reload)\" && exit\n\nif [ \"$1\" == \"start\" ]; then\n  # Create the .cron-enabled file when starting cron\n  bin/cli touch /var/www/html/var/.cron-enabled\nfi\n\nif [ \"$1\" == \"stop\" ]; then\n  # Remove the .cron-enabled file when stopping cron\n  bin/cli rm -f /var/www/html/var/.cron-enabled\nfi\n\nbin/root service cron \"$@\"\nbin/root touch /var/www/html/var/.setup_cronjob_status /var/www/html/var/.update_cronjob_status\nbin/root chown app:app /var/www/html/var/.setup_cronjob_status /var/www/html/var/.update_cronjob_status\n"
  },
  {
    "path": "compose/bin/debug-cli",
    "content": "#!/usr/bin/env bash\nS=$(bin/clinotty cat /usr/local/etc/php/php.ini | grep -iGc 'xdebug.mode = off');\nR=$(grep -c 'XDEBUG_CONFIG=idekey' ./env/phpfpm.env)\n\nif [[ -z \"$2\" ]]\n  then\n    platform=\"PHPSTORM\"\n  else\n    platform=$2\nfi\n\nlocal_debug_status(){\n  if [[ $R != 0 ]]; then\n    echo \"Cli debug enabled\"\n  else\n    echo \"Cli debug disabled\"\n  fi\n}\n\nlocal_debug_toggle() {\n    if [[ $R != 0 ]]; then\n      local_debug_disable\n    else\n      local_debug_enable\n    fi\n}\n\nlocal_debug_enable() {\n  if [[ $S == 1 ]]; then\n    bin/xdebug enable\n  fi\n\n  if [[ $R != 0 ]]; then\n    echo \"Already enabled\"\n    exit 0\n  fi\n\n  echo \"XDEBUG_CONFIG=idekey=$platform\" >> ./env/phpfpm.env\n  sleep 1\n  bin/restart phpfpm\n  echo \"Cli debug enabled\"\n}\n\nlocal_debug_disable() {\n  sed -i '' '/XDEBUG_CONFIG=idekey/d' ./env/phpfpm.env\n  sleep 1\n  bin/restart phpfpm\n  echo \"Cli debug disabled\"\n}\n\nfirstArgLetter=\"$(echo \"$1\" | head -c 1)\"\nif [[ $firstArgLetter == \"d\" ]]; then\n  local_debug_disable\nelif [[ $firstArgLetter == \"e\" ]]; then\n  local_debug_enable\nelif [[ $firstArgLetter == \"t\" ]]; then\n  local_debug_toggle\nelif [[ $firstArgLetter == \"s\" ]]; then\n  local_debug_status\nelse\n    printf \"Please specify either 'disable', 'enable', 'status' or 'toggle' as mandatory argument.\\nSpecify as an optional second argument the platform. Default is PHPSTORM\\nEx: bin/debug-cli enable [PHPSTORM]\\n\"\nfi\n"
  },
  {
    "path": "compose/bin/deploy",
    "content": "#!/usr/bin/env bash\nbin/composer install\nbin/magento maintenance:enable\nbin/cli rm -rf generated/code var/view_preprocessed\nbin/magento cache:flush\nbin/magento setup:upgrade\nbin/magento setup:di:compile\nbin/magento setup:static-content:deploy en_US \"$@\" -f\nbin/magento maintenance:disable\nbin/magento cache:flush\n"
  },
  {
    "path": "compose/bin/dev-test-run",
    "content": "#!/usr/bin/env bash\n\n[ -z \"$1\" ] && echo \"Please specify test type (ex. integration)\" && exit\n\nTEST_TYPE=\"$1\"\nshift\nbin/clinotty bash -c \"cd dev/tests/${TEST_TYPE} && ../../../vendor/bin/phpunit -c phpunit.xml.dist $*\"\n"
  },
  {
    "path": "compose/bin/dev-urn-catalog-generate",
    "content": "#!/usr/bin/env bash\nbin/magento dev:urn-catalog:generate misc.xml\nbin/copyfromcontainer misc.xml\nmkdir -p src/.idea\nmv src/misc.xml src/.idea/misc.xml \n\necho \"URN's have been generated, you may now restart PHPStorm\"\n"
  },
  {
    "path": "compose/bin/devconsole",
    "content": "#!/usr/bin/env bash\nbin/n98-magerun2 dev:console\n"
  },
  {
    "path": "compose/bin/docker-compose",
    "content": "#!/usr/bin/env bash\n\nif docker compose version > /dev/null 2>&1; then\n  DOCKER_COMPOSE=\"docker compose\"\nelse\n  DOCKER_COMPOSE=\"docker-compose\"\nfi\n\nCOMPOSE_FILES=(\"compose.yaml\" \"compose.healthcheck.yaml\")\n\n# If --no-dev is passed to this script, we won't load the compose.dev.yaml file,\n# but this argument should be removed so it isn't passed to docker compose.\nif [ \"$1\" == \"--no-dev\" ]; then\n  # Remove the \"--no-dev\" argument so it isn't passed to docker compose\n  shift 1\nelse\n  # The \"--no-dev\" argument wasn't passed in, so let's load the dev config.\n  COMPOSE_FILES+=(\"compose.dev.yaml\")\nfi\n\n# Loop over the list of compose files, and prefix them with -f.\n# This ensures paths with spaces aren't split when passed as parameters.\nCOMPOSE_FILES_PREFIXED=()\nfor file in \"${COMPOSE_FILES[@]}\"; do\n  COMPOSE_FILES_PREFIXED+=(\"-f\" \"$file\")\ndone\n\n${DOCKER_COMPOSE} \"${COMPOSE_FILES_PREFIXED[@]}\" \"$@\"\n"
  },
  {
    "path": "compose/bin/docker-start",
    "content": "#!/usr/bin/env bash\n\n# Function to check if Docker daemon is running\ndocker_running() {\n  docker stats --no-stream &> /dev/null\n  return $?\n}\n\n# Check if OrbStack is installed and not running\nif [ -d \"/Applications/OrbStack.app\" ]; then\n  echo \"* OrbStack is installed\"\n  \n  if (! docker_running); then\n    echo \"* Starting OrbStack...\"\n    open /Applications/OrbStack.app\n    \n    # Wait until Docker daemon is running via OrbStack\n    while (! docker_running); do\n      echo \"* Waiting for OrbStack to initialize Docker...\"\n      sleep 2\n    done\n    \n    echo \"* Docker is now running via OrbStack\"\n    exit 0\n  else\n    echo \"* Docker is already running (possibly via OrbStack)\"\n    exit 0\n  fi\nfi\n\n# Check if Docker Desktop is installed\nif [ -d \"/Applications/Docker.app\" ]; then\n  echo \"* Docker Desktop is installed\"\n  \n  # Check if Docker is running\n  if (! docker_running); then\n    echo \"* Starting Docker Desktop...\"\n    open /Applications/Docker.app\n    \n    # Wait until Docker daemon is running\n    while (! docker_running); do\n      echo \"* Waiting for Docker Desktop to initialize...\"\n      sleep 2\n    done\n    \n    echo \"* Docker Desktop is now running\"\n  else\n    echo \"* Docker is already running\"\n  fi\nelse\n  echo \"* Docker Desktop is not installed. Please install Docker Desktop or OrbStack.\"\n  exit 1\nfi\n"
  },
  {
    "path": "compose/bin/docker-stats",
    "content": "#!/usr/bin/env bash\n\nstty -echo\n\nINTERVAL=3\n\ntrap 'stty echo; exit' INT EXIT\n\nprint_header() {\n    echo \"+----------------------------------------------------+--------------+----------+----------+------------------------+\"\n    printf \"| %-50s | %-12s | %-8s | %-8s | %-22s |\\n\" \"NAME\" \"CONTAINER ID\" \"CPU %\" \"MEM %\" \"MEM USAGE / MEM LIMIT\"\n    echo \"+----------------------------------------------------+--------------+----------+----------+------------------------+\"\n}\n\nprint_container_info() {\n    local container_info\n    local container_name\n    local container_id\n    local cpu_perc\n    local mem_perc\n    local mem_usage\n\n    container_info=\"$1\"\n    container_name=$(echo \"$container_info\" | cut -f1)\n    container_id=$(echo \"$container_info\" | cut -f2)\n    cpu_perc=$(echo \"$container_info\" | cut -f3)\n    mem_perc=$(echo \"$container_info\" | cut -f4)\n    mem_usage=$(echo \"$container_info\" | cut -f5)\n\n\nprint_container_info() {\n    local container_info\n    local container_name\n    local container_id\n    local cpu_perc\n    local mem_perc\n    local mem_usage\n\n    container_info=\"$1\"\n    container_name=$(echo \"$container_info\" | cut -f1)\n    container_id=$(echo \"$container_info\" | cut -f2)\n    cpu_perc=$(echo \"$container_info\" | cut -f3)\n    mem_perc=$(echo \"$container_info\" | cut -f4)\n    mem_usage=$(echo \"$container_info\" | cut -f5)\n\n    printf \"| %-50s | %-12s | %-8s | %-8s | %-22s |\\n\" \"$container_name\" \"$container_id\" \"$cpu_perc\" \"$mem_perc\" \"$mem_usage\"\n}\n\n}\n\nwhile true; do\n    DOCKER_STATS=$(docker stats --no-stream --format \"{{.Name}}\\t{{.ID}}\\t{{.CPUPerc}}\\t{{.MemPerc}}\\t{{.MemUsage}}\")\n\n    clear\n\n    if [[ -n \"$DOCKER_STATS\" ]]; then\n        print_header\n\n        while IFS= read -r line; do\n            print_container_info \"$(echo \"$line\" | awk '{gsub(/\\//, \" \"); print}')\"\n        done <<< \"$DOCKER_STATS\"\n\n        echo \"+----------------------------------------------------+--------------+----------+----------+------------------------+\"\n    else\n        echo \"No active containers found\"\n        break\n    fi\n\n    sleep $INTERVAL\ndone\n\n"
  },
  {
    "path": "compose/bin/download",
    "content": "#!/usr/bin/env bash\n\nEDITION=${1:-community}\n\n# Define ANSI escape codes for colors\nYELLOW='\\033[0;33m'\nBLUE='\\033[0;34m'\nNC='\\033[0m' # No Color\n\nif [ -d \"./src\" ]; then\n  echo \"Error: The \\\"src\\\" directory is not empty. Please remove all contents within this directory and try again.\"\n  exit 1\nfi\n\nbin/stop\n\nbin/start --no-dev\n[ $? != 0 ] && echo \"Failed to start Docker services\" && exit\n\nbin/setup-composer-auth\n\nbin/fixowns\n\nif [ \"$EDITION\" == \"mageos\" ]; then\n  VERSION=${2:-1.0.5}\n  bin/clinotty composer create-project --repository-url=https://repo.mage-os.org/ mage-os/project-community-edition=\"${VERSION}\" .\nelse\n  VERSION=${2:-2.4.7-p3}\n  bin/clinotty composer create-project --repository=https://repo.magento.com/ magento/project-\"${EDITION}\"-edition=\"${VERSION}\" .\nfi\n\nif [ $? != 0 ]; then\n    echo -e \"${BLUE}Please check the installation guide at ${YELLOW}https://github.com/markshust/docker-magento#install-fails-because-project-directory-is-not-empty${BLUE} for troubleshooting.${NC}\"\nelse\n    bin/clinotty [ ! -f \"./var/composer_home/auth.json\" ] && bin/clinotty mkdir -p ./var/composer_home && bin/clinotty cp /var/www/.composer/auth.json ./var/composer_home/auth.json\nfi\n"
  },
  {
    "path": "compose/bin/ece-patches",
    "content": "#!/usr/bin/env bash\nif ! bin/cliq ls vendor/bin/ece-patches; then\n    echo \"The ece-patches tool is not installed. Please ensure you are using Adobe Commerce Cloud before running this command.\"\nfi\nbin/cli vendor/bin/ece-patches \"$@\"\n"
  },
  {
    "path": "compose/bin/fixowns",
    "content": "#!/usr/bin/env bash\necho \"Fixing filesystem ownerships...\"\n\nif [ -z \"$1\" ]; then\n  bin/rootnotty chown -R app:app /var/www/\nelse\n  bin/rootnotty chown -R app:app /var/www/html/\"$1\"\nfi\n\necho \"Filesystem ownerships fixed.\"\n"
  },
  {
    "path": "compose/bin/fixperms",
    "content": "#!/usr/bin/env bash\necho \"Fixing filesystem permissions...\"\n\nif [ -z \"$1\" ]; then\n  bin/clinotty find var vendor pub/static pub/media app/etc \\( -type f -or -type d \\) -exec chmod u+w {} +;\n  bin/clinotty chmod u+x bin/magento\nelse\n  bin/clinotty find \"$1\" \\( -type f -or -type d \\) -exec chmod u+w {} +;\nfi\n\necho \"Filesystem permissions fixed.\"\n"
  },
  {
    "path": "compose/bin/grunt",
    "content": "#!/usr/bin/env bash\nbin/cli npx grunt \"$@\"\n"
  },
  {
    "path": "compose/bin/init",
    "content": "#!/usr/bin/env bash\n\n# Script to initialize a Magento development environment\n\n# Exit immediately if a command fails\nset -e\n\necho \">>> Deploying Magento sample data...\"\nbin/magento sampledata:deploy\n\n# Sample data requires standalone setup:upgrade exec to trigger activation\necho \">>> Running setup upgrade to activate sample data...\"\nbin/magento setup:upgrade\n\necho \">>> Installing DisableTwoFactorAuth module for dev...\"\nbin/composer require --dev markshust/magento2-module-disabletwofactorauth\nbin/magento module:enable MarkShust_DisableTwoFactorAuth\nbin/magento setup:upgrade\n\necho \">>> Setting long admin session lifetime (1 year)...\"\nbin/magento config:set twofactorauth/general/enable 0\nbin/magento config:set admin/security/session_lifetime 31536000\nbin/magento config:set admin/security/password_lifetime 0\n\necho \">>> Generating URN catalog for IDEs...\"\nbin/dev-urn-catalog-generate\n\necho \">>> Flushing cache to apply all updates...\"\nbin/magento cache:flush\n\necho \">>> Magento development environment initialized successfully! 🎉\"\n"
  },
  {
    "path": "compose/bin/install-php-extensions",
    "content": "#!/usr/bin/env bash\nif ! bin/cliq ls /usr/local/bin/install-php-extensions; then\n  echo \"Downloading install-php-extensions, just a moment...\"\n  bin/rootnotty curl -sSLf \\\n    -o /usr/local/bin/install-php-extensions \\\n    https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions\n  bin/rootnotty chmod +x /usr/local/bin/install-php-extensions\nfi\n\nbin/root install-php-extensions \"$@\"\n"
  },
  {
    "path": "compose/bin/log",
    "content": "#!/usr/bin/env bash\n\nCONTAINER_LOG_PATH=\"/var/www/html/var/log/\";\n\ndisplay_help() {\n  echo -e \"Description:\n  Tail logs from the Magento var/log folder all and specific logs\n\nUsage:\n  bin/log <specific_log_files>\n\nArguments:\n  specific_log_files  If specific_log_files are NOT provided, show all logs. Ex: bin/log system.log cache.log\n\nOptions:\n  -h, --help          Display help message\"\n}\n\ngenerate_logs_file_path() {\n  local container_log_path=\"$1\"\n  shift  # This shifts the positional parameters to the left, so $2 becomes $1, $3 becomes $2, etc.\n  local log_files=(\"$@\")\n  local log_file_paths=()\n\n  for file in \"${log_files[@]}\"; do\n    log_file_paths+=(\"$container_log_path$file\")\n  done\n\n  echo \"${log_file_paths[@]}\"\n}\n\nget_all_logs_file_path() {\n  local logs_location=\"$1\"\n\n  bin/docker-compose exec phpfpm ls -p \"$logs_location\" | grep -v '/$' | sed \"s|^|$logs_location|\"\n}\n\nif [[ $1 == \"-h\" || $1 == \"--help\" ]]; then\n  display_help\nelif [[ -z $1 ]]; then\n  mapfile -t all_logs_file_path < <(get_all_logs_file_path \"$CONTAINER_LOG_PATH\")\n  bin/docker-compose exec phpfpm tail -f \"${all_logs_file_path[@]}\"\nelse\n  mapfile -t logs_file_path < <(generate_logs_file_path \"$CONTAINER_LOG_PATH\" \"$@\")\n  bin/docker-compose exec phpfpm tail -f \"${logs_file_path[@]}\"\nfi\n"
  },
  {
    "path": "compose/bin/magento",
    "content": "#!/usr/bin/env bash\nbin/cli bin/magento \"$@\"\n"
  },
  {
    "path": "compose/bin/magento-version",
    "content": "#!/usr/bin/env bash\n\n# Method 1: Using bin/magento --version\nversion=$(bin/magento --version --no-ansi 2> /dev/null | cut -d\" \" -f 3)\n\nif [[ -z \"$version\" ]]; then\n    # Method 2: Using grep in composer.lock\n    version=$(grep -A 1 \"magento/magento2-base\" ./src/composer.lock | grep \"version\" | awk -F \"\\\"\" '{print $4}')\nfi\n\nif [[ -z \"$version\" ]]; then\n    # Method 3: Using bin/yq in composer.json\n    version=$(bin/yq -oj '.version' ./src/composer.json | sed 's/\"//g')\nfi\n\n# If version is still not obtained, output error message\nif [[ -z \"$version\" ]]; then\n    echo \"Failed to retrieve Magento version.\"\nelse\n    echo \"$version\"\nfi\n"
  },
  {
    "path": "compose/bin/mftf",
    "content": "#!/usr/bin/env bash\nbin/clinotty vendor/bin/mftf \"$@\""
  },
  {
    "path": "compose/bin/mysql",
    "content": "#!/usr/bin/env bash\n\n# shellcheck source=../env/db.env\nsource env/db.env\nif [ -t 0 ]; then\n  # Need tty to run mysql shell\n  bin/cli mysql -h\"${MYSQL_HOST}\" -u\"${MYSQL_USER}\" -p\"${MYSQL_PASSWORD}\" \"${MYSQL_DATABASE}\" \"$@\"\nelse\n  # Read from stdin, ex: bin/mysql < dbdump.sql\n  bin/clinotty mysql -h\"${MYSQL_HOST}\" -u\"${MYSQL_USER}\" -p\"${MYSQL_PASSWORD}\" \"${MYSQL_DATABASE}\" \"$@\"\nfi\n"
  },
  {
    "path": "compose/bin/mysqldump",
    "content": "#!/usr/bin/env bash\nbin/n98-magerun2 db:dump --human-readable --stdout \"$@\"\n"
  },
  {
    "path": "compose/bin/n98-magerun2",
    "content": "#!/usr/bin/env bash\nif ! bin/cliq ls bin/n98-magerun2.phar; then\n  echo \"Downloading n98-magerun2.phar, just a moment...\"\n  bin/clinotty curl -sS -O https://files.magerun.net/n98-magerun2.phar\n  bin/clinotty curl -sS -o n98-magerun2.phar.sha256 https://files.magerun.net/sha256.php?file=n98-magerun2.phar\n  bin/clinotty shasum -a 256 -c n98-magerun2.phar.sha256\n  [ $? != 0 ] && echo \"sha256 checksum do not match!\" && exit\n\n  bin/cliq chmod +x n98-magerun2.phar\n  bin/cliq mkdir -p bin\n  bin/cliq mv n98-magerun2.phar bin\nfi\n\nbin/cli bin/n98-magerun2.phar \"$@\"\n"
  },
  {
    "path": "compose/bin/node",
    "content": "#!/usr/bin/env bash\nbin/cli node \"$@\"\n"
  },
  {
    "path": "compose/bin/npm",
    "content": "#!/usr/bin/env bash\nbin/cli npm \"$@\"\n"
  },
  {
    "path": "compose/bin/phpcbf",
    "content": "#!/usr/bin/env bash\nbin/clinotty vendor/bin/phpcbf --standard=Magento2 --extensions=php,phtml --error-severity=10 --ignore-annotations \"$@\"\n"
  },
  {
    "path": "compose/bin/phpcs",
    "content": "#!/usr/bin/env bash\nbin/clinotty vendor/bin/phpcs --standard=Magento2 --extensions=php,phtml --error-severity=10 --ignore-annotations \"$@\"\n"
  },
  {
    "path": "compose/bin/phpcs-json-report",
    "content": "#!/usr/bin/env bash\nbin/clinotty vendor/bin/phpcs --standard=Magento2 --extensions=php,phtml --error-severity=10 --ignore-annotations --report=json \"$@\" > report.json\n"
  },
  {
    "path": "compose/bin/pwa-studio",
    "content": "#!/usr/bin/env bash\nset -o errexit\n\nif [ ! -d pwa-studio ]; then\n    echo \"PWA studio must first be installed by running bin/setup-pwa-studio\"\n    exit\nfi\n\ncd pwa-studio\nNODE_TLS_REJECT_UNAUTHORIZED=0 yarn run watch:all\n"
  },
  {
    "path": "compose/bin/redis",
    "content": "#!/usr/bin/env bash\nbin/docker-compose exec redis \"$@\"\n"
  },
  {
    "path": "compose/bin/remove",
    "content": "#!/usr/bin/env bash\nbin/docker-compose rm\n"
  },
  {
    "path": "compose/bin/removeall",
    "content": "#!/usr/bin/env bash\nbin/stopall\nbin/remove\nbin/removevolumes\nbin/removenetwork\n"
  },
  {
    "path": "compose/bin/removenetwork",
    "content": "#!/usr/bin/env bash\ncurrent_folder=${PWD##*/}\nvolume_prefix=$(echo \"$current_folder\" | awk '{print tolower($0)}' | sed 's/\\.//g')\ndocker network rm \"$volume_prefix\"_default\n"
  },
  {
    "path": "compose/bin/removevolumes",
    "content": "#!/usr/bin/env bash\ncurrent_folder=${PWD##*/}\nvolume_prefix=$(echo \"$current_folder\" | awk '{print tolower($0)}' | sed 's/\\.//g')\ndocker volume rm \"${volume_prefix}\"_appdata\ndocker volume rm \"${volume_prefix}\"_dbdata\ndocker volume rm \"${volume_prefix}\"_rabbitmqdata\ndocker volume rm \"${volume_prefix}\"_sockdata\ndocker volume rm \"${volume_prefix}\"_ssldata\n"
  },
  {
    "path": "compose/bin/restart",
    "content": "#!/usr/bin/env bash\nbin/stop \"$@\"\nbin/start \"$@\"\n"
  },
  {
    "path": "compose/bin/root",
    "content": "#!/usr/bin/env bash\n[ -z \"$1\" ] && echo \"Please specify a CLI command (ex. ls)\" && exit\nbin/docker-compose exec -u root phpfpm \"$@\"\n"
  },
  {
    "path": "compose/bin/rootnotty",
    "content": "#!/usr/bin/env bash\n[ -z \"$1\" ] && echo \"Please specify a CLI command (ex. ls)\" && exit\nbin/docker-compose exec -u root -T phpfpm \"$@\"\n"
  },
  {
    "path": "compose/bin/setup",
    "content": "#!/usr/bin/env bash\nset -o errexit\nif [ -f \"../env/magento.env\" ]; then\n    source \"../env/magento.env\"\nelse\n    echo \"Warning: magento.env file not found.\"\nfi\n\nMEM_BYTES=$(docker info -f '{{.MemTotal}}')\nMEM_MB=$(( MEM_BYTES / 1000000 ))\n# When Docker Desktop is set to 6GB in the GUI, it is reported as 6227 MB\n(( MEM_MB < 6227 )) && echo \"There must be at least 6GB of RAM allocated to Docker in order to continue.\" && exit\n\nDOMAIN=${1:-magento.test}\n\nbin/stop\n\nbin/start --no-dev\n[ $? != 0 ] && echo \"Failed to start Docker services\" && exit\n\nbin/clinotty chmod u+x bin/magento\nrm -rf src && mkdir src\n\necho \"Adding Magento modules to Composer allow-plugins directive...\"\nbin/clinotty composer config --no-plugins allow-plugins.magento/magento-composer-installer true\nbin/clinotty composer config --no-plugins allow-plugins.magento/inventory-composer-installer true\nbin/clinotty composer config --no-plugins allow-plugins.laminas/laminas-dependency-plugin true\n\necho \"Running, Magento setup:install...\"\nbin/setup-install \"${DOMAIN}\"\n\necho \"Copying files from container to host after install...\"\nbin/copyfromcontainer --all\n\necho \"Forcing deploy of static content to speed up initial requests...\"\nbin/clinotty bin/magento setup:static-content:deploy -f\n\necho \"Re-indexing with Elasticsearch...\"\nbin/clinotty bin/magento indexer:reindex\n\necho \"Setting basic URL and generating SSL certificate...\"\nbin/setup-domain \"${DOMAIN}\"\n\necho \"Fixing owner and permissions...\"\nbin/fixowns\nbin/fixperms\n\necho \"Clearing the cache to apply updates...\"\nbin/clinotty bin/magento cache:flush\n\necho \"Installing cron, run 'bin/cron start' to enable...\"\nbin/clinotty bin/magento cron:install\n\necho \"Turning on developer mode...\"\nbin/clinotty bin/magento deploy:mode:set developer\n\ncp -r .vscode src/\n\necho \"Docker development environment setup complete.\"\necho \"You may now access your Magento instance at https://${DOMAIN}/\"\n\necho \"You may now access your Magento backend instance at https://${DOMAIN}/admin/\"\n\necho \"Use the following default credentials to log in:\"\necho \"Username: $MAGENTO_ADMIN_USER\"\necho \"Password: $MAGENTO_ADMIN_PASSWORD\"\n"
  },
  {
    "path": "compose/bin/setup-composer-auth",
    "content": "#!/usr/bin/env bash\nMAGENTO_USERNAME_PROP=\"http-basic.repo.magento.com.username\"\nMAGENTO_PASSWORD_PROP=\"http-basic.repo.magento.com.password\"\nhash composer 2>/dev/null && IS_COMPOSER_ON_HOST=true\n\nPUBLIC_KEY=\"$(bin/clinotty composer config --global $MAGENTO_USERNAME_PROP 2>/dev/null)\"\nPRIVATE_KEY=\"$(bin/clinotty composer config --global $MAGENTO_PASSWORD_PROP 2>/dev/null)\"\n\nif [ -n \"$PUBLIC_KEY\" ] && [ -n \"$PRIVATE_KEY\" ]; then\n    echo \"Composer auth has already been set up.\"\n    exit 0\nfi\n\nif [ \"$IS_COMPOSER_ON_HOST\" ]; then\n    PUBLIC_KEY=\"$(composer config --global $MAGENTO_USERNAME_PROP 2>/dev/null)\"\n    PRIVATE_KEY=\"$(composer config --global $MAGENTO_PASSWORD_PROP 2>/dev/null)\"\nfi\n\nif [ -z \"$PUBLIC_KEY\" ] || [ -z \"$PRIVATE_KEY\" ]; then\n    exec < /dev/tty\n    echo\n    echo \"Composer authentication required (repo.magento.com public and private keys):\"\n    read -r -p \"    Username: \" PUBLIC_KEY\n    read -r -p \"    Password: \" PRIVATE_KEY\n    echo\n    exec <&-\nfi\n\nif [ -z \"$PUBLIC_KEY\" ] || [ -z \"$PRIVATE_KEY\" ]; then\n    echo \"Please setup Composer auth for repo.magento.com to continue.\" && exit 1\nfi\n\n# Output must be piped otherwise file descriptor errors occur. Carriage returns?\necho \"composer config --global http-basic.repo.magento.com ${PUBLIC_KEY} ${PRIVATE_KEY}\" | bin/clinotty bash -\n\n# Also make sure alternate auth.json is setup (Magento uses this internally)\nbin/clinotty [ -d \"./var/composer_home\" ] && bin/clinotty cp /var/www/.composer/auth.json ./var/composer_home/auth.json\n\necho \"Composer auth has been set up.\"\n"
  },
  {
    "path": "compose/bin/setup-domain",
    "content": "#!/usr/bin/env bash\nset -o errexit\n\n[ -z \"$1\" ] && echo \"Please specify a domain name (ex. magento.test)\" && exit\n\nDOMAIN=$1\n\nif ! grep -q \"$DOMAIN\" /etc/hosts; then\n    echo \"Your system password is needed to add an entry to /etc/hosts...\"\n    echo \"127.0.0.1 ::1 $DOMAIN\" | sudo tee -a /etc/hosts\nfi\n\necho \"Set https://${DOMAIN}/ to web/secure/base_url and web/unsecure/base_url\"\nbin/clinotty bin/magento config:set web/secure/base_url https://\"$DOMAIN\"/\nbin/clinotty bin/magento config:set web/unsecure/base_url https://\"$DOMAIN\"/\n\necho \"Generating SSL certificate...\"\nbin/setup-ssl \"$DOMAIN\"\n"
  },
  {
    "path": "compose/bin/setup-grunt",
    "content": "#!/usr/bin/env bash\necho \"Confirming n98-magerun2 is installed...\"\nbin/n98-magerun2 > /dev/null 2>&1\n\nDEFAULT_THEME_ID=\"select value from core_config_data where path = 'design/theme/theme_id'\"\nTHEME_PATH=\"select theme_path from theme where theme_id in ($DEFAULT_THEME_ID);\"\nVENDOR_THEME=$(bin/n98-magerun2 db:query \"$THEME_PATH\" | sed -n 2p | cut -d$'\\r' -f1)\nTHEME=$(echo \"$VENDOR_THEME\" | cut -d'/' -f2)\nLOCALE_CODE=$(bin/magento config:show general/locale/code | cut -d$'\\r' -f1 | sed 's/ *$//g')\n\n# Generate local-theme.js for custom theme\nread -r -d '' GEN_THEME_JS << EOM\nvar fs = require('fs');\nvar util = require('util');\nvar theme = require('./dev/tools/grunt/configs/themes');\n\ntheme['$THEME'] = {\n    area: 'frontend',\n    name: '$VENDOR_THEME',\n    locale: '$LOCALE_CODE',\n    files: [\n        'css/styles-m',\n        'css/styles-l'\n    ],\n    dsl: 'less'\n};\nfs.writeFileSync('./dev/tools/grunt/configs/local-themes.js', '\"use strict\"; module.exports = ' + util.inspect(theme), 'utf-8');\nEOM\n\nif [ -z \"$VENDOR_THEME\" ] || [ -z \"$THEME\" ]; then\n    echo \"Using Magento/luma theme for grunt config\"\n    THEME=luma\n    bin/clinotty cp ./dev/tools/grunt/configs/themes.js ./dev/tools/grunt/configs/local-themes.js\nelse\n    echo \"Using $VENDOR_THEME theme for grunt config\"\n    bin/node -e \"$GEN_THEME_JS\"\nfi\n\n# Create files from sample files if they do not yet exist\ntest -f src/package.json || cp src/package.json.sample src/package.json\ntest -f src/Gruntfile.js || cp src/Gruntfile.js.sample src/Gruntfile.js\ntest -f src/grunt-config.json || cp src/grunt-config.json.sample src/grunt-config.json\n\n# Disable grunt-contrib-jasmine on ARM processors (incompatible)\nif [ \"$(uname -m)\" == \"arm64\" ]; then\n    sed -e 's/\"grunt-contrib-jasmine\": \"[~.0-9]*\",//' src/package.json > package.json \\\n      && mv package.json src/package.json\nfi\n\n# Enable these custom files on compose.dev.yaml so custom updates are persisted\nsed -e 's/grunt-config.json.sample/grunt-config.json/' compose.dev.yaml > compose.dev.yaml.updated \\\n && mv compose.dev.yaml.updated compose.dev.yaml\nsed -e 's/Gruntfile.js.sample/Gruntfile.js/' compose.dev.yaml > compose.dev.yaml.updated \\\n && mv compose.dev.yaml.updated compose.dev.yaml\nsed -e 's/package.json.sample/package.json/' compose.dev.yaml > compose.dev.yaml.updated \\\n && mv compose.dev.yaml.updated compose.dev.yaml\nbin/restart app phpfpm\n\nbin/npm install ajv@^5.0.0 --save\nbin/npm install\nbin/magento cache:clean\nbin/grunt clean\nbin/grunt exec:\"$THEME\"\nbin/grunt less:\"$THEME\"\n"
  },
  {
    "path": "compose/bin/setup-install",
    "content": "#!/usr/bin/env bash\nset -o errexit\n\nDOMAIN=${1:-magento.test}\n\n# shellcheck source=../env/db.env\nsource env/db.env\n# shellcheck source=../env/elasticsearch.env\nsource env/elasticsearch.env\n# shellcheck source=../env/opensearch.env\nsource env/opensearch.env\n# shellcheck source=../env/magento.env\nsource env/magento.env\n# shellcheck source=../env/rabbitmq.env\nsource env/rabbitmq.env\n# shellcheck source=../env/redis.env\nsource env/redis.env\n\nbin/clinotty bin/magento setup:install \\\n  --db-host=\"$MYSQL_HOST\" \\\n  --db-name=\"$MYSQL_DATABASE\" \\\n  --db-user=\"$MYSQL_USER\" \\\n  --db-password=\"$MYSQL_PASSWORD\" \\\n  --base-url=https://\"$DOMAIN\"/ \\\n  --base-url-secure=https://\"$DOMAIN\"/ \\\n  --backend-frontname=\"$MAGENTO_ADMIN_FRONTNAME\" \\\n  --admin-firstname=\"$MAGENTO_ADMIN_FIRST_NAME\" \\\n  --admin-lastname=\"$MAGENTO_ADMIN_LAST_NAME\" \\\n  --admin-email=\"$MAGENTO_ADMIN_EMAIL\" \\\n  --admin-user=\"$MAGENTO_ADMIN_USER\" \\\n  --admin-password=\"$MAGENTO_ADMIN_PASSWORD\" \\\n  --language=\"$MAGENTO_LOCALE\" \\\n  --currency=\"$MAGENTO_CURRENCY\" \\\n  --timezone=\"$MAGENTO_TIMEZONE\" \\\n  --amqp-host=\"$RABBITMQ_HOST\" \\\n  --amqp-port=\"$RABBITMQ_PORT\" \\\n  --amqp-user=\"$RABBITMQ_DEFAULT_USER\" \\\n  --amqp-password=\"$RABBITMQ_DEFAULT_PASS\" \\\n  --amqp-virtualhost=\"$RABBITMQ_DEFAULT_VHOST\" \\\n  --cache-backend=redis \\\n  --cache-backend-redis-server=\"$REDIS_CACHE_BACKEND_SERVER\" \\\n  --cache-backend-redis-db=\"$REDIS_CACHE_BACKEND_DB\" \\\n  --page-cache=redis \\\n  --page-cache-redis-server=\"$REDIS_PAGE_CACHE_SERVER\" \\\n  --page-cache-redis-db=\"$REDIS_PAGE_CACHE_DB\" \\\n  --session-save=redis \\\n  --session-save-redis-host=\"$REDIS_SESSION_SAVE_HOST\" \\\n  --session-save-redis-log-level=4 \\\n  --session-save-redis-db=2 \\\n  --elasticsearch-host=\"$ES_HOST\" \\\n  --elasticsearch-port=\"$ES_PORT\" \\\n  --opensearch-host=\"$OPENSEARCH_HOST\" \\\n  --opensearch-port=\"$OPENSEARCH_PORT\" \\\n  --search-engine=opensearch \\\n  --use-rewrites=1 \\\n  --cleanup-database \\\n  --no-interaction\n"
  },
  {
    "path": "compose/bin/setup-integration-tests",
    "content": "#!/usr/bin/env bash\n\n# shellcheck source=../env/db.env\nsource env/db.env\n\nMYSQL_INTEGRATION_CONFIG=dev/tests/integration/etc/install-config-mysql.php\n\n# If database doesn't exist, create it and add user permissions\nbin/clinotty mysql -h\"${MYSQL_INTEGRATION_HOST}\" -uroot -p\"${MYSQL_ROOT_PASSWORD}\" \"${MYSQL_INTEGRATION_DATABASE}\" -e exit &> /dev/null ||\n  bin/clinotty mysqladmin -h\"${MYSQL_INTEGRATION_HOST}\" -uroot -p\"${MYSQL_ROOT_PASSWORD}\" create \"${MYSQL_INTEGRATION_DATABASE}\" &&\n  echo \"Database ${MYSQL_INTEGRATION_DATABASE} created.\" &&\n  bin/cli mysql -uroot -p\"${MYSQL_ROOT_PASSWORD}\" -h\"${MYSQL_INTEGRATION_HOST}\" \\\n    -e \"GRANT ALL PRIVILEGES ON ${MYSQL_INTEGRATION_DATABASE}.* TO '${MYSQL_INTEGRATION_USER}'@'%';FLUSH PRIVILEGES;\"\n\nif [[ ! -f \"src/${MYSQL_INTEGRATION_CONFIG}\" ]]; then\n  MAGENTO_MAJOR=$(bin/magento-version | cut -d'.' -f1,2)\n  cp template/\"${MYSQL_INTEGRATION_CONFIG}\".\"${MAGENTO_MAJOR}\".dist src/${MYSQL_INTEGRATION_CONFIG}\nfi\n\nbin/copytocontainer ${MYSQL_INTEGRATION_CONFIG}\n"
  },
  {
    "path": "compose/bin/setup-pwa-studio",
    "content": "#!/usr/bin/env bash\nset -o errexit\necho \"Install NodeJS and Yarn on host machine, otherwise setup will fail\"\n\nBASE_URL=${1:-master-7rqtwti-mfwmkrjfqvbjk.us-4.magentosite.cloud}\ngit clone https://github.com/magento/pwa-studio.git\ncd pwa-studio\nyarn install\nyarn buildpack create-custom-origin packages/venia-concept\nMAGENTO_BACKEND_URL=\"https://$BASE_URL/\" yarn buildpack create-env-file packages/venia-concept\n"
  },
  {
    "path": "compose/bin/setup-pwa-studio-sampledata",
    "content": "#!/usr/bin/env bash\nset +e\n\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nNC='\\033[0m'\n\nBASE_URL=${1:-master-7rqtwti-mfwmkrjfqvbjk.us-4.magentosite.cloud}\n\ninstall_sampledata() {\n    echo -e \"${GREEN}Setting up composer repository for Venia sample data.${NC}\"\n    bin/composer config --no-interaction --ansi repositories.venia-sample-data composer https://repo.magento.com\n\n    echo -e \"${GREEN}Requiring Venia sample data metapackage.${NC}\"\n    bin/composer require --no-interaction --ansi magento/venia-sample-data:*\n\n    echo -e \"${GREEN}Installing Venia sample data modules.${NC}\"\n    bin/magento setup:upgrade\n\n    echo -e \"${GREEN}Reindexing the data from the modules.${NC}\"\n    bin/magento indexer:reindex\n}\n\ninstall_sampledata\n\nENV_DIST_FILE=\"packages/venia-concept/.env.dist\"\nif [ -f \"$ENV_DIST_FILE\" ]; then\n    cp \"$ENV_DIST_FILE\" packages/venia-concept/.env\nelse\n    echo -e \"${RED}.env.dist file not found. Continuing without copying.${NC}\"\nfi\n\necho -e \"${GREEN}Script completed successfully.${NC}\"\necho \"You may now access your Magento PWA Studio instance at https://${BASE_URL}/\"\n"
  },
  {
    "path": "compose/bin/setup-ssl",
    "content": "#!/usr/bin/env bash\n[ $# -eq 0 ] && echo \"Please specify at least one domain (ex. mydomain.test)\" && exit\n\n# Generate certificate authority if not already setup\nif ! bin/docker-compose exec -T -u root app cat /root/.local/share/mkcert/rootCA.pem | grep -q 'BEGIN CERTIFICATE'; then\n  bin/setup-ssl-ca\nfi\n\n# Initialize an empty array to hold the processed domains\nDOMAINS_WITHOUT_PORT=()\n\n# Loop through each domain\nfor domain in \"$@\"; do\n  # Strip out the port number\n  DOMAIN_WITHOUT_PORT=$(echo \"$domain\" | cut -d ':' -f1)\n  # Append the processed domain to the array\n  DOMAINS_WITHOUT_PORT+=(\"$DOMAIN_WITHOUT_PORT\")\ndone\n\n# Use the array in the mkcert command\nbin/docker-compose exec -T -u root app mkcert -key-file nginx.key -cert-file nginx.crt \"${DOMAINS_WITHOUT_PORT[@]}\"\n\necho \"Moving key and cert to /etc/nginx/certs/...\"\nbin/docker-compose exec -T -u root app chown app:app nginx.key nginx.crt\nbin/docker-compose exec -T -u root app mv nginx.key nginx.crt /etc/nginx/certs/\n\n# Restart nginx to apply the updates\necho \"Restarting containers to apply updates...\"\nbin/restart\n"
  },
  {
    "path": "compose/bin/setup-ssl-ca",
    "content": "#!/usr/bin/env bash\nset -o errexit\n# Generate a new local CA \"/root/.local/share/mkcert\"\nbin/docker-compose exec -T -u root app mkcert -install\n\ndocker cp \"$(bin/docker-compose ps -q app|awk '{print $1}')\":/root/.local/share/mkcert/rootCA.pem .\necho \"System password requested to install certificate authority on host...\"\n\nif [ \"$(uname)\" == \"Darwin\" ]; then\n  sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain rootCA.pem\n  echo \"{\\\"policies\\\": {\\\"Certificates\\\": {\\\"ImportEnterpriseRoots\\\": true}}}\" | sudo tee policies.json\n\n  FIREFOX_FOUND=0\n  ### Check if Firefox is installed\n  for FFoxAppDir in \\\n    '/Applications/Firefox.app' \\\n    '/Applications/Firefox Developer Edition.app' \\\n    ; do\n\n    FFoxBin=$FFoxAppDir/Contents/MacOS/firefox-bin\n    if [[ -f $FFoxBin ]]; then\n      printf 'Firefox compatible found at: %s\\n' \"$FFoxAppDir\" >&2\n      FIREFOX_FOUND=1\n\n      ### Copy the newly created policies.json to the Certificates directory\n      DistDirectory=$FFoxAppDir/Contents/Resources/distribution\n      sudo mkdir -p \"$DistDirectory\"\n      sudo cp policies.json \"$DistDirectory\"/policies.json\n\n    fi\n  done\n\n  if [[ $FIREFOX_FOUND -ne 0 ]]; then\n    ### Copy the newly created .pem to the Certificates directory\n    CertDirectory='/Library/Application Support/Mozilla/Certificates'\n    printf 'Installing CA certificate to: %s\\n' \"$CertDirectory\" >&2\n    sudo mkdir -p \"$CertDirectory\"\n    sudo cp rootCA.pem \"$CertDirectory\"/rootCA.pem\n  fi\n\n  rm -f policies.json rootCA.pem\n\nelse\n\n  ### Requirement: apt install libnss3-tools\n  REQUIRED_PKG=\"libnss3-tools\"\n  PKG_OK=$(dpkg-query -W --showformat='${Status}\\n' $REQUIRED_PKG|grep \"install ok installed\")\n  echo Checking for $REQUIRED_PKG: \"$PKG_OK\"\n  if [ \"\" = \"$PKG_OK\" ]; then\n    echo \"No $REQUIRED_PKG found. Setting up $REQUIRED_PKG.\"\n    sudo apt-get --yes install $REQUIRED_PKG\n  fi\n\n  ### CA file to install (CUSTOMIZE!)\n  certfile=\"rootCA.pem\"\n  certname=\"Root CA\"\n\n  ### For cert8 (legacy - DBM)\n  find ~/ -name \"cert8.db\" -print0 | while read -r certDB\n  do\n      certdir=$(dirname \"${certDB}\");\n      certutil -D -n \"${certname}\" -i ${certfile} -d dbm:\"${certdir}\"\n      certutil -A -n \"${certname}\" -t \"TCu,Cu,Tu\" -i ${certfile} -d dbm:\"${certdir}\"\n  done\n\n  ### For cert9 (SQL)\n  find ~/ -name \"cert9.db\" -print0 | while read -r certDB\n  do\n      certdir=$(dirname \"${certDB}\");\n      certutil -D -n \"${certname}\" -i ${certfile} -d sql:\"${certdir}\"\n      certutil -A -n \"${certname}\" -t \"TCu,Cu,Tu\" -i ${certfile} -d sql:\"${certdir}\"\n  done\n\n  sudo mv rootCA.pem /usr/local/share/ca-certificates/rootCA.crt\n  sudo update-ca-certificates\nfi\n"
  },
  {
    "path": "compose/bin/spx",
    "content": "#!/usr/bin/env bash\n\nS=$(bin/clinotty cat /usr/local/etc/php/php.ini | grep -iGc 'zlib.output_compression = 1');\n\nspx_status() {\n    if [[ $S == 1 ]]; then\n        echo \"Output compression is enabled, so you cannot currently debug with SPX.\"\n    else\n        echo \"Output compression is disabled, so you can currently debug with SPX.\"\n    fi\n}\n\nspx_toggle() {\n    if [[ $S == 1 ]]; then\n        spx_enable\n    else\n        spx_disable\n    fi\n}\n\nspx_enable() {\n    if [[ $S == 1 ]]; then\n        bin/root sed -i -e 's/^zlib.output_compression = 1/zlib.output_compression = 0/g' /usr/local/etc/php/php.ini\n        sleep 1\n        bin/restart phpfpm\n        echo \"Output compression is now disabled, so you can start debugging with SPX.\"\n    else\n        echo \"Output compression is already disabled, so you can start debugging with SPX.\"\n    fi\n}\n\nspx_disable() {\n    if [[ $S == 0 ]]; then\n        bin/root sed -i -e 's/^zlib.output_compression = 0/zlib.output_compression = 1/g' /usr/local/etc/php/php.ini\n        sleep 1\n        bin/restart phpfpm\n        echo \"Output compression is now enabled, so you can no longer debug with SPX.\"\n    else\n        echo \"Output compression is already enabled, so you can no longer debug with SPX.\"\n    fi\n}\n\nfirstArgLetter=\"$(echo \"$1\" | head -c 1)\"\n\nif [[ $firstArgLetter == \"d\" ]]; then\n    spx_disable\nelif [[ $firstArgLetter == \"e\" ]]; then\n    spx_enable\nelif [[ $firstArgLetter == \"t\" ]]; then\n    spx_toggle\nelif [[ $firstArgLetter == \"s\" ]]; then\n    spx_status\nelse\n    printf \"Please specify either 'disable', 'enable', 'status' or 'toggle' as an argument.\\nEx: bin/spx status\\n\"\nfi\n"
  },
  {
    "path": "compose/bin/start",
    "content": "#!/usr/bin/env bash\nset -o errexit\n\nMEM=$(docker info | grep \"Total Memory\" | cut -d':' -f2 | xargs | sed s/GiB//)\n# Docker reports RAM 0.2 less than what it is actually set to\n(( $(echo \"$MEM < 5.7\" | bc -l) )) && echo \"There must be at least 6GB of RAM allocated to Docker to continue.\" && exit\n\nif [ \"$1\" == \"--no-dev\" ]; then\n  bin/docker-compose --no-dev up -d --remove-orphans \"${@:2}\"\n  exit $?\nfi\n\n# Ref: https://stackoverflow.com/a/51789677/9821321\nfunction parseYaml {\n  local s\n  local w\n  local fs\n  s='[[:space:]]*'\n  w='[a-zA-Z0-9_]*'\n  fs=$(echo @|tr @ '\\034')\n  sed -ne \"s|,$s\\]$s\\$|]|\" \\\n      -e \"s|^\\($s\\)\\($w\\)$s:$s\\[$s\\(.*\\)$s\\]|\\1\\2:\\n\\1  - \\3|;p\" \"$1\" | \\\n  sed -ne \"s|,$s}$s\\$|}|\" \\\n      -e \"s|^\\($s\\)-$s{$s\\(.*\\)$s}|\\1-\\n\\1  \\2|;p\" | \\\n  sed -ne \"s|^\\($s\\):|\\1|\" \\\n      -e \"s|^\\($s\\)-$s{[\\\"']\\(.*\\)[\\\"']}$s\\$|\\1$fs$fs\\2|p\" \\\n      -e \"s|^\\($s\\)-$s\\(.*\\)$s\\$|\\1$fs$fs\\2|p\" \\\n      -e \"s|^\\($s\\)\\($w\\)$s:$s{[\\\"']\\(.*\\)[\\\"']}$s\\$|\\1$fs\\2$fs\\3|p\" \\\n      -e \"s|^\\($s\\)\\($w\\)$s:$s\\(.*\\)$s\\$|\\1$fs\\2$fs\\3|p\" | \\\n  awk -F\"$fs\" '{\n    indent = length($1)/2;\n    vname[indent] = $2;\n    for (i in vname) {if (i > indent) {delete vname[i]; idx[i]=0}}\n    if (length($2) == 0) {vname[indent] = ++idx[indent] };\n    if (length($3) > 0) {\n      vn=\"\"; for (i=0; i<indent; i++) {vn = (vn)(vname[i])(\"_\")}\n      if (\"'\"$2\"'_\" == vn) {\n         print substr($3 ,1 , match($3,\":\")-1)\n      }\n    }\n  }'\n}\n\n# Check if volume files exist to avoid creating an empty folder\nVOLUME_LIST=$(parseYaml compose.dev.yaml services_app_volumes)\nIGNORE_LIST=\"./src/app/code ./src/m2-hotfixes ./src/patches ./src/var/log ./src/var/report ./src\"\nIS_VALID=true\n\n# Loop through all files missing from the compose.dev.yaml file\nfor file in $VOLUME_LIST; do\n  if [[ ! -e $file && \" $IGNORE_LIST \" != *\" $file \"* ]]; then\n    echo \"$file: No such file or directory\"\n    IS_VALID=false\n  fi\ndone\n\n# Wait to exit until all missing files have been outputted to the user\n[ $IS_VALID = false ] && echo \"Failed to start docker for missing volume files\" && exit\n\nbin/docker-compose up -d --remove-orphans \"$@\"\n\n## Blackfire support\n## ------------------\n## First register the blackfire agent with:\n#bin/root blackfire-agent --register --server-id={YOUR_SERVER_ID} --server-token={YOUR_SERVER_TOKEN}\n## Then uncomment the below line (and leave uncommented) to start the agent automatically with bin/start:\n#bin/root /etc/init.d/blackfire-agent start\n\n# Check if cron was previously enabled and restart it if needed\nif bin/cli test -f /var/www/html/var/.cron-enabled; then\n  echo \"Cron was previously enabled, restarting cron service...\"\n  bin/cron start\nfi\n\nbin/cache-clean --watch\n"
  },
  {
    "path": "compose/bin/status",
    "content": "#!/usr/bin/env bash\nbin/docker-compose ps\n"
  },
  {
    "path": "compose/bin/stop",
    "content": "#!/usr/bin/env bash\nbin/docker-compose stop \"$@\"\n"
  },
  {
    "path": "compose/bin/stopall",
    "content": "#!/usr/bin/env bash\nif [ -z \"$(docker ps -q)\" ]; then\n    echo \"You have no running container\"\nelse\n    echo \"Stopping all running containers...\"\n    docker ps -q | while IFS='' read -r container; do\n        docker stop \"$container\"\n    done\nfi\n"
  },
  {
    "path": "compose/bin/test/unit",
    "content": "#!/usr/bin/env bash\n\ndisplay_help() {\n  echo -e \"Description:\n  Run unit tests\n\nUsage:\n  bin/test/unit <unit_test_path>\n\nArguments:\n  <unit_test_path> Specify a path to your test or folder with tests Ex: bin/test/unit app/code/Vendor/Module\n\nOptions:\n  -h, --help       Display help message\"\n}\n\n\nif [[ $1 == \"-h\" || $1 == \"--help\" ]]; then\n  display_help\nelif [[ -z $1 ]]; then\n  echo -e \"Please specify a path to your test or folder with tests (ex. app/code/Vendor/Module)\"\nelse\n  bin/cli vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist /var/www/html/\"$1\"\nfi\n"
  },
  {
    "path": "compose/bin/test/unit-coverage",
    "content": "#!/usr/bin/env bash\n\ndisplay_help() {\n  echo -e \"Description:\n  Generate unit tests coverage report in folder: dev/tests/unit/report\n\nUsage:\n  bin/test/unit-coverage <unit_test_path>\n\nArguments:\n  <unit_test_path> Specify a path to your test or folder with tests Ex: bin/test/unit-coverage app/code/Vendor/Module\n\nOptions:\n  -h, --help       Display help message\"\n}\n\nif [[ $1 == \"-h\" || $1 == \"--help\" ]]; then\n  display_help\nelif [[ -z $1 ]]; then\n  echo -e \"Please specify a path to your test or folder with tests (ex. app/code/Vendor/Module)\"\nelse\n  bin/cli php -d xdebug.mode=coverage vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist --coverage-html ./dev/tests/unit/report /var/www/html/\"$1\"\n  echo -e \"Report path: dev/tests/unit/report\"\nfi\n"
  },
  {
    "path": "compose/bin/test/unit-xdebug",
    "content": "#!/usr/bin/env bash\n\ndisplay_help() {\n  echo -e \"Description:\n  Run unit tests with xdebug (you need to turn on xdebug in IDE as usual)\n\nUsage:\n  bin/test/unit-xdebug <unit_test_path>\n\nArguments:\n  <unit_test_path> Specify a path to your test or folder with tests Ex: bin/test/unit-xdebug app/code/Vendor/Module\n\nOptions:\n  -h, --help       Display help message\"\n}\n\n\nif [[ $1 == \"-h\" || $1 == \"--help\" ]]; then\n  display_help\nelif [[ -z $1 ]]; then\n  echo -e \"Please specify a path to your test or folder with tests (ex. app/code/Vendor/Module)\"\nelse\n  bin/cli php -d xdebug.start_with_request=yes vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist /var/www/html/\"$1\"\nfi\n"
  },
  {
    "path": "compose/bin/update",
    "content": "#!/usr/bin/env bash\nset -o errexit\nmkdir -p tmpupdate && cd \"$_\"\ncurl -s https://raw.githubusercontent.com/markshust/docker-magento/master/lib/template | bash\nrm -rf .git\nrsync -av --checksum ./ ../\ncd ..\nrm -rf tmpupdate\necho \"docker-magento has been updated, run bin/restart to apply the updates\"\n"
  },
  {
    "path": "compose/bin/xdebug",
    "content": "#!/usr/bin/env bash\n\ncurrent_mode=$(bin/clinotty cat /usr/local/etc/php/php.ini | grep '^xdebug.mode' | cut -d'=' -f2 | tr -d ' ')\n\ndisplay_modes() {\n    echo \"- off\"\n    echo \"- develop\"\n    echo \"- coverage\"\n    echo \"- debug\"\n    echo \"- gcstats\"\n    echo \"- profile\"\n    echo \"- trace\"\n    echo \"\"\n    printf \"You can also combine multiple modes with commas (e.g., develop,trace)\\n\"\n}\n\nxdebug_set_mode() {\n    local new_mode=$1\n\n    # Validate the mode(s)\n    IFS=',' read -ra MODES <<< \"$new_mode\"\n    for mode in \"${MODES[@]}\"; do\n        case $mode in\n            off|develop|coverage|debug|gcstats|profile|trace)\n                continue\n                ;;\n            *)\n                printf \"Invalid mode: %s\\n\\n\" \"$mode\"\n                echo \"Valid modes are:\"\n                display_modes\n                return 1\n                ;;\n        esac\n    done\n\n    if [ \"$current_mode\" = \"$new_mode\" ]; then\n        echo \"Current setting is already: xdebug.mode = $new_mode\"\n        return 0\n    fi\n\n    bin/root sed -i -e \"s/^xdebug\\.mode.*$/xdebug.mode = $new_mode/g\" /usr/local/etc/php/php.ini\n    bin/cli kill -USR2 1\n    echo \"New setting: xdebug.mode = $new_mode\"\n}\n\nif [ -z \"$1\" ]; then\n    printf \"Current setting: xdebug.mode = %s\\n\\n\" \"$current_mode\"\n    printf \"Update it by passing in a valid mode as an argument:\\n\"\n    display_modes\n    exit 1\nfi\n\nxdebug_set_mode \"$1\"\n"
  },
  {
    "path": "compose/compose.dev-linux.yaml",
    "content": "services:\n  app:\n    volumes: &appvolumes\n      - ./src/nginx.conf.sample:/var/www/html/nginx.conf:cached\n      - ./src:/var/www/html:cached\n\n  phpfpm:\n    volumes: *appvolumes    \n    \n  phpmyadmin:\n    image: linuxserver/phpmyadmin\n    env_file: env/db.env\n    ports:\n      - \"8080:80\"\n    depends_on:\n      - db\n"
  },
  {
    "path": "compose/compose.dev-ssh.yaml",
    "content": "services:\n  app:\n    volumes: &appvolumes\n      - ./src/nginx.conf.sample:/var/www/html/nginx.conf:cached\n\n  phpfpm:\n    volumes: *appvolumes\n\n  ssh:\n    image: markoshust/ssh\n    ports:\n      - \"22:22\"\n    volumes: *appvolumes\n"
  },
  {
    "path": "compose/compose.dev.yaml",
    "content": "services:\n  app:\n    volumes: &appvolumes\n      ## Host mounts with performance penalty, only put what is necessary here\n      - ./src/app/code:/var/www/html/app/code:cached\n      - ./src/app/design:/var/www/html/app/design:cached\n      - ./src/app/etc:/var/www/html/app/etc:cached\n      - ./src/composer.json:/var/www/html/composer.json:cached\n      - ./src/composer.lock:/var/www/html/composer.lock:cached\n      - ./src/grunt-config.json.sample:/var/www/html/grunt-config.json:cached\n      - ./src/Gruntfile.js.sample:/var/www/html/Gruntfile.js:cached\n      - ./src/dev/tools/grunt/configs:/var/www/html/dev/tools/grunt/configs:cached\n      - ./src/nginx.conf.sample:/var/www/html/nginx.conf:cached\n      - ./src/package.json.sample:/var/www/html/package.json:cached\n      - ./src/generated:/var/www/html/generated:cached\n      - ./src/var:/var/www/html/var:cached\n      #- ./src/auth.json:/var/www/html/auth.json:cached\n      #- ./src/m2-hotfixes:/var/www/html/m2-hotfixes:cached\n      #- ./src/patches:/var/www/html/patches:cached\n\n  phpfpm:\n    volumes: *appvolumes\n\n  phpmyadmin:\n    image: linuxserver/phpmyadmin\n    env_file: env/db.env\n    ports:\n      - \"8080:80\"\n    depends_on:\n      - db\n\n  ## Selenium support, uncomment to enable\n  #selenium:\n  #  image: selenium/standalone-chrome-debug:3.8.1\n  #  ports:\n  #    - \"5900:5900\"\n  #  extra_hosts: *appextrahosts\n"
  },
  {
    "path": "compose/compose.healthcheck.yaml",
    "content": "x-healthcheck-defaults: &healthcheck-defaults\n  interval: 5s\n  timeout: 5s\n  retries: 6\n\nx-healthcheck-slow-start: &healthcheck-slow-start\n  <<: *healthcheck-defaults\n  start_period: 5s\n\nservices:\n  app:\n    healthcheck:\n      test: \"curl --fail 127.0.0.1:8000\"\n      <<: *healthcheck-defaults\n    depends_on:\n      phpfpm:\n        condition: service_started\n\n  phpfpm:\n    depends_on:\n      db:\n        condition: service_healthy\n      redis:\n        condition: service_healthy\n      opensearch:\n        condition: service_healthy\n      rabbitmq:\n        condition: service_healthy\n      #elasticsearch:\n      #  condition: service_healthy\n\n  db:\n    healthcheck:\n      test: \"mysqladmin ping -h localhost -u root -pmagento || mariadb-admin ping -h localhost -u root -pmagento\"\n      <<: *healthcheck-defaults\n\n  redis:\n    healthcheck:\n      test: \"redis-cli ping || exit 1\"\n      <<: *healthcheck-slow-start\n\n  opensearch:\n    healthcheck:\n      test: \"curl --fail opensearch:9200/_cat/health >/dev/null || exit 1\"\n      <<: *healthcheck-slow-start\n\n  #elasticsearch:\n  #  healthcheck:\n  #    test: \"curl --fail elasticsearch:9200/_cat/health >/dev/null || exit 1\"\n  #    <<: *healthcheck-slow-start\n\n  rabbitmq:\n    healthcheck:\n      test: \"rabbitmq-diagnostics -q ping\"\n      <<: *healthcheck-slow-start\n\n  mailcatcher:\n    healthcheck:\n      test: \"wget --no-verbose --tries=1 --spider 127.0.0.1:1080 || exit 1\"\n      <<: *healthcheck-defaults\n"
  },
  {
    "path": "compose/compose.yaml",
    "content": "## Mark Shust's Docker Configuration for Magento\n## (https://github.com/markshust/docker-magento)\n##\n## Version 52.1.0\n\n## To use SSH, see https://github.com/markshust/docker-magento#ssh\n## Linux users, see https://github.com/markshust/docker-magento#linux\n\n## If you changed the default Docker network, you may need to replace\n## 172.17.0.1 in this file with the result of:\n## docker network inspect bridge --format='{{(index .IPAM.Config 0).Gateway}}'\n\nservices:\n  app:\n    image: markoshust/magento-nginx:1.24-0\n    ports:\n      - \"80:8000\"\n      - \"443:8443\"\n    volumes: &appvolumes\n      - ~/.composer:/var/www/.composer:cached\n      - ~/.ssh/id_rsa:/var/www/.ssh/id_rsa:cached\n      - ~/.ssh/known_hosts:/var/www/.ssh/known_hosts:cached\n      - appdata:/var/www/html\n      - sockdata:/sock\n      - ssldata:/etc/nginx/certs\n    #extra_hosts: &appextrahosts\n      ## Selenium support, replace \"magento.test\" with URL of your site\n      #- \"magento.test:172.17.0.1\"\n      ## Linux, uncomment for Xdebug capabilities:\n      #- \"host.docker.internal:host-gateway\"\n\n  phpfpm:\n    image: markoshust/magento-php:8.3-fpm-4\n    volumes: *appvolumes\n    env_file: env/phpfpm.env\n    #extra_hosts: *appextrahosts\n\n  db:\n    image: mariadb:11.4\n    command:\n      --max_allowed_packet=64M\n      --optimizer_use_condition_selectivity=1\n      --optimizer_switch=\"rowid_filter=off\"\n      --log_bin_trust_function_creators=1\n    ports:\n      - \"3306:3306\"\n    env_file: env/db.env\n    volumes:\n      - dbdata:/var/lib/mysql\n\n  ## If you wish to use MySQL, comment out the mariadb db image above and\n  ## uncomment this block.\n  #db:\n  #  image: mysql:8.4\n  #  command:\n  #    --max_allowed_packet=64M\n  #    --log_bin_trust_function_creators=1\n  #  ports:\n  #    - \"3306:3306\"\n  #  env_file: env/db.env\n  #  volumes:\n  #    - dbdata:/var/lib/mysql\n\n  redis:\n    image: valkey/valkey:8.1-alpine\n    ports:\n      - \"6379:6379\"\n\n  ## If you wish to use Redis, comment out the redis image above and\n  ## uncomment this block.\n  #redis:\n  #  image: redis:7.2-alpine\n  #  ports:\n  #    - \"6379:6379\"\n\n  opensearch:\n    image: markoshust/magento-opensearch:2.12-0\n    ports:\n      - \"9200:9200\"\n      - \"9300:9300\"\n    env_file: env/opensearch.env\n    environment:\n      - \"discovery.type=single-node\"\n      ## Avoid test failures due to small disks\n      ## More info at https://github.com/markshust/docker-magento/issues/488\n      - \"cluster.routing.allocation.disk.threshold_enabled=false\"\n      - \"index.blocks.read_only_allow_delete\"\n      ## Uncomment to set custom heap size to avoid memory errors\n      #- \"OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g\"\n      ## Uncomment to increase the virtual memory map count\n      #- \"max_map_count=262144\"\n\n  ## If you wish to use Elasticsearch, comment out opensearch image above and\n  ## uncomment this block. Do the same in the composer.healthcheck.yaml file.\n  # Additionally, if you are performing the manual setup, you will need to\n  # update the bin/setup command to use the $ES_HOST variable as the value for\n  # the --elasticsearch-host argument passed to bin/magento setup:install.\n  #elasticsearch:\n  #  image: markoshust/magento-elasticsearch:8.13-0\n  #  ports:\n  #    - \"9200:9200\"\n  #    - \"9300:9300\"\n  #  env_file: env/elasticsearch.env\n  #  environment:\n  #    - \"discovery.type=single-node\"\n  #    ## Avoid test failures due to small disks\n  #    ## More info at https://github.com/markshust/docker-magento/issues/488\n  #    - \"cluster.routing.allocation.disk.threshold_enabled=false\"\n  #    - \"index.blocks.read_only_allow_delete\"\n  #    ## Uncomment to set custom heap size to avoid memory errors\n  #    #- \"ES_JAVA_OPTS=-Xms1g -Xmx1g\"\n  #    ## Uncomment to increase the virtual memory map count\n  #    #- \"max_map_count=262144\"\n  #    ## Uncomment the line below if ElasticSearch fails to start and stops after ~150 seconds with the error \"container for service \"elasticsearch\" is unhealthy\".\n  #    #- \"xpack.security.enabled=false\"\n\n  rabbitmq:\n    image: markoshust/magento-rabbitmq:4.1-0\n    ports:\n      - \"15672:15672\"\n      - \"5672:5672\"\n    volumes:\n      - rabbitmqdata:/var/lib/rabbitmq\n    env_file: env/rabbitmq.env\n\n  mailcatcher:\n    image: sj26/mailcatcher:v0.10.0\n    ports:\n      - \"1080:1080\"\n\n  ## Cloudflare tunnel support, uncomment to enable\n  #tunnel:\n  #  container_name: cloudflared-tunnel\n  #  image: cloudflare/cloudflared:latest\n  #  command: tunnel run\n  #  env_file: env/cloudflare.env\n\n  ## Blackfire support, uncomment to enable\n  #blackfire:\n  #  image: blackfire/blackfire:2\n  #  ports:\n  #    - \"8307\"\n  #  env_file: env/blackfire.env\n\nvolumes:\n  appdata:\n  dbdata:\n  rabbitmqdata:\n  sockdata:\n  ssldata:\n"
  },
  {
    "path": "compose/env/blackfire.env",
    "content": "BLACKFIRE_DISABLE_LEGACY_PORT=true\nBLACKFIRE_LOG_LEVEL=\nBLACKFIRE_SERVER_ID=\nBLACKFIRE_SERVER_TOKEN=\n"
  },
  {
    "path": "compose/env/cloudflare.env",
    "content": "TUNNEL_TOKEN=\n"
  },
  {
    "path": "compose/env/db.env",
    "content": "MYSQL_HOST=db\nMYSQL_ROOT_PASSWORD=magento\nMYSQL_DATABASE=magento\nMYSQL_USER=magento\nMYSQL_PASSWORD=magento\n\nMYSQL_INTEGRATION_ROOT_PASSWORD=magento\nMYSQL_INTEGRATION_DATABASE=magento_integration_tests\nMYSQL_INTEGRATION_USER=magento\nMYSQL_INTEGRATION_PASSWORD=magento\nMYSQL_INTEGRATION_HOST=db\n"
  },
  {
    "path": "compose/env/elasticsearch.env",
    "content": "ES_HOST=elasticsearch\nES_PORT=9200\n"
  },
  {
    "path": "compose/env/magento.env",
    "content": "MAGENTO_ADMIN_EMAIL=john.smith@gmail.com\nMAGENTO_ADMIN_FIRST_NAME=john\nMAGENTO_ADMIN_LAST_NAME=smith\nMAGENTO_ADMIN_USER=john.smith\nMAGENTO_ADMIN_PASSWORD=password123\nMAGENTO_ADMIN_FRONTNAME=admin\nMAGENTO_LOCALE=en_US\nMAGENTO_CURRENCY=USD\nMAGENTO_TIMEZONE=America/New_York\n"
  },
  {
    "path": "compose/env/opensearch.env",
    "content": "OPENSEARCH_HOST=opensearch\nOPENSEARCH_PORT=9200\n\n# Prevent security patch conflicts with core M2 code\nDISABLE_SECURITY_PLUGIN=true\n"
  },
  {
    "path": "compose/env/phpfpm.env",
    "content": "BLACKFIRE_CLIENT_ID=\nBLACKFIRE_CLIENT_TOKEN=\nCOMPOSER_DISABLE_XDEBUG_WARN=1\nPHP_CS_FIXER_IGNORE_ENV=1\nPUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true\n"
  },
  {
    "path": "compose/env/rabbitmq.env",
    "content": "RABBITMQ_HOST=rabbitmq\nRABBITMQ_PORT=5672\nRABBITMQ_MANAGEMENT_PORT=15672\nRABBITMQ_DEFAULT_USER=magento\nRABBITMQ_DEFAULT_PASS=magento\nRABBITMQ_DEFAULT_VHOST=/\n"
  },
  {
    "path": "compose/env/redis.env",
    "content": "REDIS_CACHE_BACKEND_SERVER=redis\nREDIS_CACHE_BACKEND_DB=0\nREDIS_PAGE_CACHE_SERVER=redis\nREDIS_PAGE_CACHE_DB=1\nREDIS_SESSION_SAVE_HOST=redis\n"
  },
  {
    "path": "compose/template/dev/tests/integration/etc/install-config-mysql.php.2.3.dist",
    "content": "<?php\n/**\n * Copyright © Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\nreturn [\n    'db-host' => 'db',\n    'db-user' => 'magento',\n    'db-password' => 'magento',\n    'db-name' => 'magento_integration_tests',\n    'db-prefix' => '',\n    'backend-frontname' => 'backend',\n    'admin-user' => \\Magento\\TestFramework\\Bootstrap::ADMIN_NAME,\n    'admin-password' => \\Magento\\TestFramework\\Bootstrap::ADMIN_PASSWORD,\n    'admin-email' => \\Magento\\TestFramework\\Bootstrap::ADMIN_EMAIL,\n    'admin-firstname' => \\Magento\\TestFramework\\Bootstrap::ADMIN_FIRSTNAME,\n    'admin-lastname' => \\Magento\\TestFramework\\Bootstrap::ADMIN_LASTNAME,\n    'amqp-host' => 'rabbitmq',\n    'amqp-port' => '5672',\n    'amqp-user' => 'magento',\n    'amqp-password' => 'magento',\n];\n"
  },
  {
    "path": "compose/template/dev/tests/integration/etc/install-config-mysql.php.2.4.dist",
    "content": "<?php\n/**\n * Copyright © Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\nreturn [\n    'db-host' => 'db',\n    'db-user' => 'magento',\n    'db-password' => 'magento',\n    'db-name' => 'magento_integration_tests',\n    'db-prefix' => '',\n    'backend-frontname' => 'backend',\n    'search-engine' => 'opensearch',\n    'opensearch-host' => 'opensearch',\n    'admin-user' => \\Magento\\TestFramework\\Bootstrap::ADMIN_NAME,\n    'admin-password' => \\Magento\\TestFramework\\Bootstrap::ADMIN_PASSWORD,\n    'admin-email' => \\Magento\\TestFramework\\Bootstrap::ADMIN_EMAIL,\n    'admin-firstname' => \\Magento\\TestFramework\\Bootstrap::ADMIN_FIRSTNAME,\n    'admin-lastname' => \\Magento\\TestFramework\\Bootstrap::ADMIN_LASTNAME,\n    'amqp-host' => 'rabbitmq',\n    'amqp-port' => '5672',\n    'amqp-user' => 'magento',\n    'amqp-password' => 'magento',\n    'consumers-wait-for-messages' => '0',\n];\n"
  },
  {
    "path": "images/elasticsearch/7.16/Dockerfile",
    "content": "FROM elasticsearch:7.16.3\n\nRUN /usr/share/elasticsearch/bin/elasticsearch-plugin install \\\n  analysis-icu \\\n  analysis-phonetic\n"
  },
  {
    "path": "images/elasticsearch/7.17/Dockerfile",
    "content": "FROM elasticsearch:7.17.16\n\nRUN /usr/share/elasticsearch/bin/elasticsearch-plugin install \\\n  analysis-icu \\\n  analysis-phonetic\n"
  },
  {
    "path": "images/elasticsearch/8.11/Dockerfile",
    "content": "FROM elasticsearch:8.11.4\n\nRUN /usr/share/elasticsearch/bin/elasticsearch-plugin install \\\n  analysis-icu \\\n  analysis-phonetic\n"
  },
  {
    "path": "images/elasticsearch/8.13/Dockerfile",
    "content": "FROM elasticsearch:8.13.0\n\nRUN /usr/share/elasticsearch/bin/elasticsearch-plugin install \\\n  analysis-icu \\\n  analysis-phonetic\n"
  },
  {
    "path": "images/elasticsearch/8.4/Dockerfile",
    "content": "FROM elasticsearch:8.4.3\n\nRUN /usr/share/elasticsearch/bin/elasticsearch-plugin install \\\n  analysis-icu \\\n  analysis-phonetic\n"
  },
  {
    "path": "images/elasticsearch/8.5/Dockerfile",
    "content": "FROM elasticsearch:8.5.3\n\nRUN /usr/share/elasticsearch/bin/elasticsearch-plugin install \\\n  analysis-icu \\\n  analysis-phonetic\n"
  },
  {
    "path": "images/elasticsearch/8.7/Dockerfile",
    "content": "FROM elasticsearch:8.7.1\n\nRUN /usr/share/elasticsearch/bin/elasticsearch-plugin install \\\n  analysis-icu \\\n  analysis-phonetic\n"
  },
  {
    "path": "images/nginx/1.18/Dockerfile",
    "content": "FROM nginx:1.18-alpine\nMAINTAINER Mark Shust <mark@shust.com>\n\nARG APP_ID=1000\n\nRUN addgroup -g \"$APP_ID\" app \\\n && adduser -G app -u \"$APP_ID\" -h /var/www -s /bin/bash -S app\nRUN touch /var/run/nginx.pid\nRUN mkdir /sock\n\nRUN apk add --no-cache \\\n  curl \\\n  nss-tools \\\n  openssl\n\nRUN mkdir /etc/nginx/certs \\\n  && echo -e \"\\n\\n\\n\\n\\n\\n\\n\" | openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/certs/nginx.key -out /etc/nginx/certs/nginx.crt\n\nARG TARGETARCH\n\nRUN cd /usr/local/bin/ \\\n  && curl -L https://github.com/FiloSottile/mkcert/releases/download/v1.4.3/mkcert-v1.4.3-linux-$TARGETARCH -o mkcert \\\n  && chmod +x mkcert\n\nCOPY ./conf/nginx.conf /etc/nginx/\nCOPY ./conf/default.conf /etc/nginx/conf.d/\n\nRUN mkdir -p /etc/nginx/html /var/www/html \\\n  && chown -R app:app /etc/nginx /var/www /var/cache/nginx /var/run/nginx.pid /sock\n\nEXPOSE 8443\n\nUSER app:app\n\nVOLUME /var/www\n\nWORKDIR /var/www/html\n"
  },
  {
    "path": "images/nginx/1.18/conf/default.conf",
    "content": "upstream fastcgi_backend {\n  server unix:/sock/docker.sock;\n}\n\nserver {\n  listen 8000;\n  return 301 https://$host$request_uri;\n}\n\nserver {\n  listen [::]:8443 ssl http2 ipv6only=on;\n  listen 8443 ssl http2;\n\n  ssl_certificate /etc/nginx/certs/nginx.crt;\n  ssl_certificate_key /etc/nginx/certs/nginx.key;\n\n  set $MAGE_ROOT /var/www/html;\n\n  fastcgi_buffer_size 64k;\n  fastcgi_buffers 8 128k;\n\n  location /livereload.js {\n    proxy_set_header Host $host;\n    proxy_pass http://phpfpm:35729/livereload.js;\n  }\n\n  location /livereload {\n    proxy_http_version 1.1;\n    proxy_set_header Upgrade $http_upgrade;\n    proxy_set_header Connection \"Upgrade\";\n    proxy_pass http://phpfpm:35729/livereload;\n  }\n\n  include /var/www/html/nginx[.]conf;\n}\n"
  },
  {
    "path": "images/nginx/1.18/conf/default.magento1.conf",
    "content": "upstream fastcgi_backend {\n  server unix:/sock/docker.sock;\n}\n\nserver {\n  listen 8000;\n  server_name localhost;\n\n  set $MAGE_ROOT /var/www/html;\n  set $MAGE_IS_DEVELOPER_MODE true;\n\n  root $MAGE_ROOT;\n\n  index index.php;\n  autoindex off;\n  charset off;\n\n  add_header 'X-Content-Type-Options' 'nosniff';\n\n  location / {\n    try_files $uri $uri/ /index.php?$args;\n  }\n  \n  location ~ cron\\.php {\n    deny all;\n  }\n\n  location ~* \\.php$ {\n    try_files $uri =404;\n    fastcgi_pass fastcgi_backend;\n    fastcgi_index index.php;\n    fastcgi_param SCRIPT_FILENAME  $document_root$fastcgi_script_name;\n    include fastcgi_params;\n  }\n}\n"
  },
  {
    "path": "images/nginx/1.18/conf/nginx.conf",
    "content": "# let's assume dual-core machine\nworker_processes 2;\n\nerror_log /var/log/nginx/error.log debug;\npid /var/run/nginx.pid;\n\nload_module /etc/nginx/modules/ngx_http_image_filter_module.so;\n\nevents {\n  # this should be equal to value of \"ulimit -n\"\n  # reference: https://www.digitalocean.com/community/tutorials/how-to-optimize-nginx-configuration\n  worker_connections 1048576;\n}\n\nhttp {\n  include /etc/nginx/mime.types;\n  default_type application/octet-stream;\n\n  log_format main\n    '$remote_addr - $remote_user [$time_local] \"$request\" '\n    '$status $body_bytes_sent \"$http_referer\" '\n    '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n\n  access_log /var/log/nginx/access.log main;\n\n  sendfile on;\n  #tcp_nopush on;\n\n  keepalive_timeout 65;\n\n  #gzip on;\n\n  client_max_body_size 20M;\n\n  include /etc/nginx/conf.d/*.conf;\n}\n"
  },
  {
    "path": "images/nginx/1.22/Dockerfile",
    "content": "FROM nginx:1.22-alpine\nMAINTAINER Mark Shust <mark@shust.com>\n\nARG APP_ID=1000\n\nRUN addgroup -g \"$APP_ID\" app \\\n && adduser -G app -u \"$APP_ID\" -h /var/www -s /bin/bash -S app\nRUN touch /var/run/nginx.pid\nRUN mkdir /sock\n\nRUN apk add --no-cache \\\n  curl \\\n  nss-tools \\\n  openssl\n\nRUN mkdir /etc/nginx/certs \\\n  && echo -e \"\\n\\n\\n\\n\\n\\n\\n\" | openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/certs/nginx.key -out /etc/nginx/certs/nginx.crt\n\nARG TARGETARCH\n\nRUN cd /usr/local/bin/ \\\n  && curl -L https://github.com/FiloSottile/mkcert/releases/download/v1.4.3/mkcert-v1.4.3-linux-$TARGETARCH -o mkcert \\\n  && chmod +x mkcert\n\nCOPY ./conf/nginx.conf /etc/nginx/\nCOPY ./conf/default.conf /etc/nginx/conf.d/\n\nRUN mkdir -p /etc/nginx/html /var/www/html \\\n  && chown -R app:app /etc/nginx /var/www /var/cache/nginx /var/run/nginx.pid /sock\n\nEXPOSE 8443\n\nUSER app:app\n\nVOLUME /var/www\n\nWORKDIR /var/www/html\n"
  },
  {
    "path": "images/nginx/1.22/conf/default.conf",
    "content": "upstream fastcgi_backend {\n  server unix:/sock/docker.sock;\n}\n\nserver {\n  listen 8000;\n  return 301 https://$host$request_uri;\n}\n\nserver {\n  listen [::]:8443 ssl http2 ipv6only=on;\n  listen 8443 ssl http2;\n\n  ssl_certificate /etc/nginx/certs/nginx.crt;\n  ssl_certificate_key /etc/nginx/certs/nginx.key;\n\n  set $MAGE_ROOT /var/www/html;\n\n  fastcgi_buffer_size 64k;\n  fastcgi_buffers 8 128k;\n\n  location /livereload.js {\n    proxy_set_header Host $host;\n    proxy_pass http://phpfpm:35729/livereload.js;\n  }\n\n  location /livereload {\n    proxy_http_version 1.1;\n    proxy_set_header Upgrade $http_upgrade;\n    proxy_set_header Connection \"Upgrade\";\n    proxy_pass http://phpfpm:35729/livereload;\n  }\n\n  include /var/www/html/nginx[.]conf;\n}\n"
  },
  {
    "path": "images/nginx/1.22/conf/default.magento1.conf",
    "content": "upstream fastcgi_backend {\n  server unix:/sock/docker.sock;\n}\n\nserver {\n  listen 8000;\n  server_name localhost;\n\n  set $MAGE_ROOT /var/www/html;\n  set $MAGE_IS_DEVELOPER_MODE true;\n\n  root $MAGE_ROOT;\n\n  index index.php;\n  autoindex off;\n  charset off;\n\n  add_header 'X-Content-Type-Options' 'nosniff';\n\n  location / {\n    try_files $uri $uri/ /index.php?$args;\n  }\n  \n  location ~ cron\\.php {\n    deny all;\n  }\n\n  location ~* \\.php$ {\n    try_files $uri =404;\n    fastcgi_pass fastcgi_backend;\n    fastcgi_index index.php;\n    fastcgi_param SCRIPT_FILENAME  $document_root$fastcgi_script_name;\n    include fastcgi_params;\n  }\n}\n"
  },
  {
    "path": "images/nginx/1.22/conf/nginx.conf",
    "content": "# let's assume dual-core machine\nworker_processes 2;\n\nerror_log /var/log/nginx/error.log debug;\npid /var/run/nginx.pid;\n\nload_module /etc/nginx/modules/ngx_http_image_filter_module.so;\n\nevents {\n  # this should be equal to value of \"ulimit -n\"\n  # reference: https://www.digitalocean.com/community/tutorials/how-to-optimize-nginx-configuration\n  worker_connections 1048576;\n}\n\nhttp {\n  include /etc/nginx/mime.types;\n  default_type application/octet-stream;\n\n  log_format main\n    '$remote_addr - $remote_user [$time_local] \"$request\" '\n    '$status $body_bytes_sent \"$http_referer\" '\n    '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n\n  access_log /var/log/nginx/access.log main;\n\n  sendfile on;\n  #tcp_nopush on;\n\n  keepalive_timeout 65;\n\n  #gzip on;\n\n  client_max_body_size 20M;\n\n  include /etc/nginx/conf.d/*.conf;\n}\n"
  },
  {
    "path": "images/nginx/1.24/Dockerfile",
    "content": "FROM nginx:1.24-alpine\nLABEL maintainer=\"Mark Shust <mark@shust.com>\"\n\nARG APP_ID=1000\n\nRUN addgroup -g \"$APP_ID\" app \\\n && adduser -G app -u \"$APP_ID\" -h /var/www -s /bin/bash -S app\nRUN touch /var/run/nginx.pid\nRUN mkdir /sock\n\nRUN apk add --no-cache \\\n  curl \\\n  nss-tools \\\n  openssl\n\nRUN mkdir /etc/nginx/certs \\\n  && echo -e \"\\n\\n\\n\\n\\n\\n\\n\" | openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/certs/nginx.key -out /etc/nginx/certs/nginx.crt\n\nARG TARGETARCH\n\nRUN cd /usr/local/bin/ \\\n  && curl -L https://github.com/FiloSottile/mkcert/releases/download/v1.4.3/mkcert-v1.4.3-linux-$TARGETARCH -o mkcert \\\n  && chmod +x mkcert\n\nCOPY ./conf/nginx.conf /etc/nginx/\nCOPY ./conf/default.conf /etc/nginx/conf.d/\n\nRUN mkdir -p /etc/nginx/html /var/www/html \\\n  && chown -R app:app /etc/nginx /var/www /var/cache/nginx /var/run/nginx.pid /sock\n\nEXPOSE 8443\n\nUSER app:app\n\nVOLUME /var/www\n\nWORKDIR /var/www/html\n"
  },
  {
    "path": "images/nginx/1.24/conf/default.conf",
    "content": "upstream fastcgi_backend {\n  server unix:/sock/docker.sock;\n}\n\nserver {\n  listen 8000;\n  return 301 https://$host$request_uri;\n}\n\nserver {\n  listen [::]:8443 ssl http2 ipv6only=on;\n  listen 8443 ssl http2;\n\n  ssl_certificate /etc/nginx/certs/nginx.crt;\n  ssl_certificate_key /etc/nginx/certs/nginx.key;\n\n  set $MAGE_ROOT /var/www/html;\n\n  fastcgi_buffer_size 64k;\n  fastcgi_buffers 8 128k;\n\n  location /livereload.js {\n    proxy_set_header Host $host;\n    proxy_pass http://phpfpm:35729/livereload.js;\n  }\n\n  location /livereload {\n    proxy_http_version 1.1;\n    proxy_set_header Upgrade $http_upgrade;\n    proxy_set_header Connection \"Upgrade\";\n    proxy_pass http://phpfpm:35729/livereload;\n  }\n\n  include /var/www/html/nginx[.]conf;\n}\n"
  },
  {
    "path": "images/nginx/1.24/conf/default.magento1.conf",
    "content": "upstream fastcgi_backend {\n  server unix:/sock/docker.sock;\n}\n\nserver {\n  listen 8000;\n  server_name localhost;\n\n  set $MAGE_ROOT /var/www/html;\n  set $MAGE_IS_DEVELOPER_MODE true;\n\n  root $MAGE_ROOT;\n\n  index index.php;\n  autoindex off;\n  charset off;\n\n  add_header 'X-Content-Type-Options' 'nosniff';\n\n  location / {\n    try_files $uri $uri/ /index.php?$args;\n  }\n  \n  location ~ cron\\.php {\n    deny all;\n  }\n\n  location ~* \\.php$ {\n    try_files $uri =404;\n    fastcgi_pass fastcgi_backend;\n    fastcgi_index index.php;\n    fastcgi_param SCRIPT_FILENAME  $document_root$fastcgi_script_name;\n    include fastcgi_params;\n  }\n}\n"
  },
  {
    "path": "images/nginx/1.24/conf/nginx.conf",
    "content": "# let's assume dual-core machine\nworker_processes 2;\n\nerror_log /var/log/nginx/error.log debug;\npid /var/run/nginx.pid;\n\nload_module /etc/nginx/modules/ngx_http_image_filter_module.so;\n\nevents {\n  # this should be equal to value of \"ulimit -n\"\n  # reference: https://www.digitalocean.com/community/tutorials/how-to-optimize-nginx-configuration\n  worker_connections 1048576;\n}\n\nhttp {\n  include /etc/nginx/mime.types;\n  default_type application/octet-stream;\n\n  log_format main\n    '$remote_addr - $remote_user [$time_local] \"$request\" '\n    '$status $body_bytes_sent \"$http_referer\" '\n    '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n\n  access_log /var/log/nginx/access.log main;\n\n  sendfile on;\n  #tcp_nopush on;\n\n  keepalive_timeout 65;\n\n  #gzip on;\n\n  client_max_body_size 100M;\n\n  include /etc/nginx/conf.d/*.conf;\n}\n"
  },
  {
    "path": "images/opensearch/1.2/Dockerfile",
    "content": "FROM opensearchproject/opensearch:1.2.4\n\nRUN /usr/share/opensearch/bin/opensearch-plugin install --batch \\\n  analysis-icu \\\n  analysis-phonetic\n"
  },
  {
    "path": "images/opensearch/2.12/Dockerfile",
    "content": "FROM opensearchproject/opensearch:2.12.0\n\nRUN /usr/share/opensearch/bin/opensearch-plugin install --batch \\\n  analysis-icu \\\n  analysis-phonetic\n"
  },
  {
    "path": "images/opensearch/2.5/Dockerfile",
    "content": "FROM opensearchproject/opensearch:2.5.0\n\nRUN /usr/share/opensearch/bin/opensearch-plugin install --batch \\\n  analysis-icu \\\n  analysis-phonetic\n"
  },
  {
    "path": "images/php/8.1/Dockerfile",
    "content": "FROM php:8.1-fpm-bookworm\nLABEL maintainer=\"Mark Shust <mark@shust.com>\"\n\nARG APP_ID=1000\nRUN groupadd -g \"$APP_ID\" app \\\n  && useradd -g \"$APP_ID\" -u \"$APP_ID\" -d /var/www -s /bin/bash app\n\nRUN mkdir -p /etc/nginx/html /var/www/html /sock \\\n  && chown -R app:app /etc/nginx /var/www /usr/local/etc/php/conf.d /sock\n\nRUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash -\n\nRUN apt-get update && apt-get install -y \\\n    cron \\\n    default-mysql-client \\\n    git \\\n    gnupg \\\n    gzip \\\n    libbz2-dev \\\n    libfreetype6-dev \\\n    libicu-dev \\\n    libjpeg62-turbo-dev \\\n    libmagickwand-dev \\\n    libmcrypt-dev \\\n    libonig-dev \\\n    libpng-dev \\\n    libsodium-dev \\\n    libssh2-1-dev \\\n    libwebp-dev \\\n    libxslt1-dev \\\n    libzip-dev \\\n    lsof \\\n    mailutils \\\n    msmtp \\\n    nodejs \\\n    procps \\\n    rsync \\\n    strace \\\n    vim \\\n    zip \\\n    zlib1g-dev \\\n  && rm -rf /var/lib/apt/lists/*\n\nRUN pecl channel-update pecl.php.net && pecl install \\\n    redis-6.2.0 \\\n    ssh2-1.4.1 \\\n    swoole-6.0.2 \\\n    xdebug-3.4.2 \\\n    imagick-3.8.0RC2 \\\n  && pecl clear-cache \\\n  && rm -rf /tmp/pear\n\nRUN docker-php-ext-configure \\\n    gd --with-freetype --with-jpeg --with-webp \\\n  && docker-php-ext-install \\\n    bcmath \\\n    bz2 \\\n    calendar \\\n    exif \\\n    gd \\\n    gettext \\\n    intl \\\n    mbstring \\\n    mysqli \\\n    opcache \\\n    pcntl \\\n    pdo_mysql \\\n    soap \\\n    sockets \\\n    sodium \\\n    sysvmsg \\\n    sysvsem \\\n    sysvshm \\\n    xsl \\\n    zip \\\n  && docker-php-ext-enable \\\n    imagick \\\n    redis \\\n    ssh2 \\\n    xdebug\n\nRUN version=$(php -r \"echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;\") \\\n    && architecture=$(uname -m) \\\n    && curl -A \"Docker\" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/$architecture/$version \\\n    && mkdir -p /tmp/blackfire \\\n    && tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \\\n    && mv /tmp/blackfire/blackfire-*.so $(php -r \"echo ini_get ('extension_dir');\")/blackfire.so \\\n    && rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz\n\nRUN git clone --branch v0.4.18 --depth=1 https://github.com/NoiseByNorthwest/php-spx.git /usr/lib/php-spx \\\n    && cd /usr/lib/php-spx \\\n    && phpize \\\n    && ./configure \\\n    && make \\\n    && make install\n\nRUN curl -sS https://getcomposer.org/installer | \\\n  php -- --version=2.7.9 --install-dir=/usr/local/bin --filename=composer\n\nCOPY conf/blackfire.ini $PHP_INI_DIR/conf.d/blackfire.ini\nCOPY conf/spx.ini $PHP_INI_DIR/conf.d/spx.ini\nCOPY conf/msmtprc /etc/msmtprc\nCOPY conf/php.ini $PHP_INI_DIR\nCOPY conf/php-fpm.conf /usr/local/etc/\nCOPY conf/www.conf /usr/local/etc/php-fpm.d/\n\nUSER app:app\nVOLUME /var/www\nWORKDIR /var/www/html\n"
  },
  {
    "path": "images/php/8.1/conf/blackfire.ini",
    "content": "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8307\n"
  },
  {
    "path": "images/php/8.1/conf/msmtprc",
    "content": "account default\nhost mailcatcher\nport 1025\nfrom \"user@domain.com\"\n"
  },
  {
    "path": "images/php/8.1/conf/php-fpm.conf",
    "content": "; This file was initially adapted from the output of: (on PHP 5.6)\n;   grep -vE '^;|^ *$' /usr/local/etc/php-fpm.conf.default\n\n[global]\n\nerror_log = /proc/self/fd/2\ndaemonize = no\n\n[www]\n\n; if we send this to /proc/self/fd/1, it never appears\naccess.log = /proc/self/fd/2\n\n;user = app\n;group = app\n\nlisten = /sock/docker.sock\nlisten.owner = app\nlisten.group = app\nlisten.mode = 0660\n\npm = dynamic\npm.max_children = 10\npm.start_servers = 4\npm.min_spare_servers = 2\npm.max_spare_servers = 6\n\nclear_env = no\n\n; Ensure worker stdout and stderr are sent to the main error log.\ncatch_workers_output = yes\n\n; This needed to make PHP-SPX work in fpm mode.\nprocess.dumpable = yes\n"
  },
  {
    "path": "images/php/8.1/conf/php.ini",
    "content": "memory_limit = 4G\nmax_execution_time = 1800\nzlib.output_compression = 1\ncgi.fix_pathinfo = 0\ndate.timezone = UTC\n\nxdebug.mode = off\nxdebug.client_host = host.docker.internal\nxdebug.idekey = PHPSTORM\nxdebug.start_with_request = trigger\nxdebug.output_dir = /var/www/html/var/profile\nxdebug.profiler_output_name = cachegrind.out.%t.%p\n\nupload_max_filesize = 100M\npost_max_size = 100M\nmax_input_vars = 10000\n\nsendmail_path = \"/usr/bin/msmtp -t\"\n"
  },
  {
    "path": "images/php/8.1/conf/spx.ini",
    "content": "extension = /usr/lib/php-spx/modules/spx.so\nspx.http_enabled = 1\nspx.http_key = \"dev\"\nspx.http_ip_whitelist = \"*\"\nspx.data_dir = /var/www/spx_dumps\n"
  },
  {
    "path": "images/php/8.1/conf/www.conf",
    "content": "; Start a new pool named 'www'.\n; the variable $pool can we used in any directive and will be replaced by the\n; pool name ('www' here)\n[www]\n\n; Per pool prefix\n; It only applies on the following directives:\n; - 'access.log'\n; - 'slowlog'\n; - 'listen' (unixsocket)\n; - 'chroot'\n; - 'chdir'\n; - 'php_values'\n; - 'php_admin_values'\n; When not set, the global prefix (or NONE) applies instead.\n; Note: This directive can also be relative to the global prefix.\n; Default Value: none\n;prefix = /path/to/pools/$pool\n\n; Unix user/group of processes\n; Note: The user is mandatory. If the group is not set, the default user's group\n;       will be used.\nuser = app\ngroup = app\n\n; The address on which to accept FastCGI requests.\n; Valid syntaxes are:\n;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific IPv4 address on\n;                            a specific port;\n;   '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on\n;                            a specific port;\n;   'port'                 - to listen on a TCP socket to all addresses\n;                            (IPv6 and IPv4-mapped) on a specific port;\n;   '/path/to/unix/socket' - to listen on a unix socket.\n; Note: This value is mandatory.\nlisten = 127.0.0.1:9000\n\n; Set listen(2) backlog.\n; Default Value: 511 (-1 on FreeBSD and OpenBSD)\n;listen.backlog = 511\n\n; Set permissions for unix socket, if one is used. In Linux, read/write\n; permissions must be set in order to allow connections from a web server. Many\n; BSD-derived systems allow connections regardless of permissions.\n; Default Values: user and group are set as the running user\n;                 mode is set to 0660\n;listen.owner = www-data\n;listen.group = www-data\n;listen.mode = 0660\n; When POSIX Access Control Lists are supported you can set them using\n; these options, value is a comma separated list of user/group names.\n; When set, listen.owner and listen.group are ignored\n;listen.acl_users =\n;listen.acl_groups =\n\n; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect.\n; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original\n; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address\n; must be separated by a comma. If this value is left blank, connections will be\n; accepted from any ip address.\n; Default Value: any\n;listen.allowed_clients = 127.0.0.1\n\n; Specify the nice(2) priority to apply to the pool processes (only if set)\n; The value can vary from -19 (highest priority) to 20 (lower priority)\n; Note: - It will only work if the FPM master process is launched as root\n;       - The pool processes will inherit the master process priority\n;         unless it specified otherwise\n; Default Value: no set\n; process.priority = -19\n\n; Choose how the process manager will control the number of child processes.\n; Possible Values:\n;   static  - a fixed number (pm.max_children) of child processes;\n;   dynamic - the number of child processes are set dynamically based on the\n;             following directives. With this process management, there will be\n;             always at least 1 children.\n;             pm.max_children      - the maximum number of children that can\n;                                    be alive at the same time.\n;             pm.start_servers     - the number of children created on startup.\n;             pm.min_spare_servers - the minimum number of children in 'idle'\n;                                    state (waiting to process). If the number\n;                                    of 'idle' processes is less than this\n;                                    number then some children will be created.\n;             pm.max_spare_servers - the maximum number of children in 'idle'\n;                                    state (waiting to process). If the number\n;                                    of 'idle' processes is greater than this\n;                                    number then some children will be killed.\n;  ondemand - no children are created at startup. Children will be forked when\n;             new requests will connect. The following parameter are used:\n;             pm.max_children           - the maximum number of children that\n;                                         can be alive at the same time.\n;             pm.process_idle_timeout   - The number of seconds after which\n;                                         an idle process will be killed.\n; Note: This value is mandatory.\npm = dynamic\n\n; The number of child processes to be created when pm is set to 'static' and the\n; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.\n; This value sets the limit on the number of simultaneous requests that will be\n; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.\n; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP\n; CGI. The below defaults are based on a server without much resources. Don't\n; forget to tweak pm.* to fit your needs.\n; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'\n; Note: This value is mandatory.\npm.max_children = 5\n\n; The number of child processes created on startup.\n; Note: Used only when pm is set to 'dynamic'\n; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2\npm.start_servers = 2\n\n; The desired minimum number of idle server processes.\n; Note: Used only when pm is set to 'dynamic'\n; Note: Mandatory when pm is set to 'dynamic'\npm.min_spare_servers = 1\n\n; The desired maximum number of idle server processes.\n; Note: Used only when pm is set to 'dynamic'\n; Note: Mandatory when pm is set to 'dynamic'\npm.max_spare_servers = 3\n\n; The number of seconds after which an idle process will be killed.\n; Note: Used only when pm is set to 'ondemand'\n; Default Value: 10s\n;pm.process_idle_timeout = 10s;\n\n; The number of requests each child process should execute before respawning.\n; This can be useful to work around memory leaks in 3rd party libraries. For\n; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS.\n; Default Value: 0\n;pm.max_requests = 500\n\n; The URI to view the FPM status page. If this value is not set, no URI will be\n; recognized as a status page. It shows the following informations:\n;   pool                 - the name of the pool;\n;   process manager      - static, dynamic or ondemand;\n;   start time           - the date and time FPM has started;\n;   start since          - number of seconds since FPM has started;\n;   accepted conn        - the number of request accepted by the pool;\n;   listen queue         - the number of request in the queue of pending\n;                          connections (see backlog in listen(2));\n;   max listen queue     - the maximum number of requests in the queue\n;                          of pending connections since FPM has started;\n;   listen queue len     - the size of the socket queue of pending connections;\n;   idle processes       - the number of idle processes;\n;   active processes     - the number of active processes;\n;   total processes      - the number of idle + active processes;\n;   max active processes - the maximum number of active processes since FPM\n;                          has started;\n;   max children reached - number of times, the process limit has been reached,\n;                          when pm tries to start more children (works only for\n;                          pm 'dynamic' and 'ondemand');\n; Value are updated in real time.\n; Example output:\n;   pool:                 www\n;   process manager:      static\n;   start time:           01/Jul/2011:17:53:49 +0200\n;   start since:          62636\n;   accepted conn:        190460\n;   listen queue:         0\n;   max listen queue:     1\n;   listen queue len:     42\n;   idle processes:       4\n;   active processes:     11\n;   total processes:      15\n;   max active processes: 12\n;   max children reached: 0\n;\n; By default the status page output is formatted as text/plain. Passing either\n; 'html', 'xml' or 'json' in the query string will return the corresponding\n; output syntax. Example:\n;   http://www.foo.bar/status\n;   http://www.foo.bar/status?json\n;   http://www.foo.bar/status?html\n;   http://www.foo.bar/status?xml\n;\n; By default the status page only outputs short status. Passing 'full' in the\n; query string will also return status for each pool process.\n; Example:\n;   http://www.foo.bar/status?full\n;   http://www.foo.bar/status?json&full\n;   http://www.foo.bar/status?html&full\n;   http://www.foo.bar/status?xml&full\n; The Full status returns for each process:\n;   pid                  - the PID of the process;\n;   state                - the state of the process (Idle, Running, ...);\n;   start time           - the date and time the process has started;\n;   start since          - the number of seconds since the process has started;\n;   requests             - the number of requests the process has served;\n;   request duration     - the duration in µs of the requests;\n;   request method       - the request method (GET, POST, ...);\n;   request URI          - the request URI with the query string;\n;   content length       - the content length of the request (only with POST);\n;   user                 - the user (PHP_AUTH_USER) (or '-' if not set);\n;   script               - the main script called (or '-' if not set);\n;   last request cpu     - the %cpu the last request consumed\n;                          it's always 0 if the process is not in Idle state\n;                          because CPU calculation is done when the request\n;                          processing has terminated;\n;   last request memory  - the max amount of memory the last request consumed\n;                          it's always 0 if the process is not in Idle state\n;                          because memory calculation is done when the request\n;                          processing has terminated;\n; If the process is in Idle state, then informations are related to the\n; last request the process has served. Otherwise informations are related to\n; the current request being served.\n; Example output:\n;   ************************\n;   pid:                  31330\n;   state:                Running\n;   start time:           01/Jul/2011:17:53:49 +0200\n;   start since:          63087\n;   requests:             12808\n;   request duration:     1250261\n;   request method:       GET\n;   request URI:          /test_mem.php?N=10000\n;   content length:       0\n;   user:                 -\n;   script:               /home/fat/web/docs/php/test_mem.php\n;   last request cpu:     0.00\n;   last request memory:  0\n;\n; Note: There is a real-time FPM status monitoring sample web page available\n;       It's available in: /usr/local/share/php/fpm/status.html\n;\n; Note: The value must start with a leading slash (/). The value can be\n;       anything, but it may not be a good idea to use the .php extension or it\n;       may conflict with a real PHP file.\n; Default Value: not set\n;pm.status_path = /status\n\n; The ping URI to call the monitoring page of FPM. If this value is not set, no\n; URI will be recognized as a ping page. This could be used to test from outside\n; that FPM is alive and responding, or to\n; - create a graph of FPM availability (rrd or such);\n; - remove a server from a group if it is not responding (load balancing);\n; - trigger alerts for the operating team (24/7).\n; Note: The value must start with a leading slash (/). The value can be\n;       anything, but it may not be a good idea to use the .php extension or it\n;       may conflict with a real PHP file.\n; Default Value: not set\n;ping.path = /ping\n\n; This directive may be used to customize the response of a ping request. The\n; response is formatted as text/plain with a 200 response code.\n; Default Value: pong\n;ping.response = pong\n\n; The access log file\n; Default: not set\n;access.log = log/$pool.access.log\n\n; The access log format.\n; The following syntax is allowed\n;  %%: the '%' character\n;  %C: %CPU used by the request\n;      it can accept the following format:\n;      - %{user}C for user CPU only\n;      - %{system}C for system CPU only\n;      - %{total}C  for user + system CPU (default)\n;  %d: time taken to serve the request\n;      it can accept the following format:\n;      - %{seconds}d (default)\n;      - %{miliseconds}d\n;      - %{mili}d\n;      - %{microseconds}d\n;      - %{micro}d\n;  %e: an environment variable (same as $_ENV or $_SERVER)\n;      it must be associated with embraces to specify the name of the env\n;      variable. Some exemples:\n;      - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e\n;      - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e\n;  %f: script filename\n;  %l: content-length of the request (for POST request only)\n;  %m: request method\n;  %M: peak of memory allocated by PHP\n;      it can accept the following format:\n;      - %{bytes}M (default)\n;      - %{kilobytes}M\n;      - %{kilo}M\n;      - %{megabytes}M\n;      - %{mega}M\n;  %n: pool name\n;  %o: output header\n;      it must be associated with embraces to specify the name of the header:\n;      - %{Content-Type}o\n;      - %{X-Powered-By}o\n;      - %{Transfert-Encoding}o\n;      - ....\n;  %p: PID of the child that serviced the request\n;  %P: PID of the parent of the child that serviced the request\n;  %q: the query string\n;  %Q: the '?' character if query string exists\n;  %r: the request URI (without the query string, see %q and %Q)\n;  %R: remote IP address\n;  %s: status (response code)\n;  %t: server time the request was received\n;      it can accept a strftime(3) format:\n;      %d/%b/%Y:%H:%M:%S %z (default)\n;      The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag\n;      e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t\n;  %T: time the log has been written (the request has finished)\n;      it can accept a strftime(3) format:\n;      %d/%b/%Y:%H:%M:%S %z (default)\n;      The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag\n;      e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t\n;  %u: remote user\n;\n; Default: \"%R - %u %t \\\"%m %r\\\" %s\"\n;access.format = \"%R - %u %t \\\"%m %r%Q%q\\\" %s %f %{mili}d %{kilo}M %C%%\"\n\n; The log file for slow requests\n; Default Value: not set\n; Note: slowlog is mandatory if request_slowlog_timeout is set\n;slowlog = log/$pool.log.slow\n\n; The timeout for serving a single request after which a PHP backtrace will be\n; dumped to the 'slowlog' file. A value of '0s' means 'off'.\n; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)\n; Default Value: 0\n;request_slowlog_timeout = 0\n\n; The timeout for serving a single request after which the worker process will\n; be killed. This option should be used when the 'max_execution_time' ini option\n; does not stop script execution for some reason. A value of '0' means 'off'.\n; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)\n; Default Value: 0\n;request_terminate_timeout = 0\n\n; Set open file descriptor rlimit.\n; Default Value: system defined value\n;rlimit_files = 1024\n\n; Set max core size rlimit.\n; Possible Values: 'unlimited' or an integer greater or equal to 0\n; Default Value: system defined value\n;rlimit_core = 0\n\n; Chroot to this directory at the start. This value must be defined as an\n; absolute path. When this value is not set, chroot is not used.\n; Note: you can prefix with '$prefix' to chroot to the pool prefix or one\n; of its subdirectories. If the pool prefix is not set, the global prefix\n; will be used instead.\n; Note: chrooting is a great security feature and should be used whenever\n;       possible. However, all PHP paths will be relative to the chroot\n;       (error_log, sessions.save_path, ...).\n; Default Value: not set\n;chroot =\n\n; Chdir to this directory at the start.\n; Note: relative path can be used.\n; Default Value: current directory or / when chroot\n;chdir = /var/www\n\n; Redirect worker stdout and stderr into main error log. If not set, stdout and\n; stderr will be redirected to /dev/null according to FastCGI specs.\n; Note: on highloaded environement, this can cause some delay in the page\n; process time (several ms).\n; Default Value: no\n;catch_workers_output = yes\n\n; Clear environment in FPM workers\n; Prevents arbitrary environment variables from reaching FPM worker processes\n; by clearing the environment in workers before env vars specified in this\n; pool configuration are added.\n; Setting to \"no\" will make all environment variables available to PHP code\n; via getenv(), $_ENV and $_SERVER.\n; Default Value: yes\n;clear_env = no\n\n; Limits the extensions of the main script FPM will allow to parse. This can\n; prevent configuration mistakes on the web server side. You should only limit\n; FPM to .php extensions to prevent malicious users to use other extensions to\n; exectute php code.\n; Note: set an empty value to allow all extensions.\n; Default Value: .php\n;security.limit_extensions = .php .php3 .php4 .php5 .php7\n\n; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from\n; the current environment.\n; Default Value: clean env\n;env[HOSTNAME] = $HOSTNAME\n;env[PATH] = /usr/local/bin:/usr/bin:/bin\n;env[TMP] = /tmp\n;env[TMPDIR] = /tmp\n;env[TEMP] = /tmp\n\n; Additional php.ini defines, specific to this pool of workers. These settings\n; overwrite the values previously defined in the php.ini. The directives are the\n; same as the PHP SAPI:\n;   php_value/php_flag             - you can set classic ini defines which can\n;                                    be overwritten from PHP call 'ini_set'.\n;   php_admin_value/php_admin_flag - these directives won't be overwritten by\n;                                     PHP call 'ini_set'\n; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.\n\n; Defining 'extension' will load the corresponding shared extension from\n; extension_dir. Defining 'disable_functions' or 'disable_classes' will not\n; overwrite previously defined php.ini values, but will append the new value\n; instead.\n\n; Note: path INI options can be relative and will be expanded with the prefix\n; (pool, global or /usr/local)\n\n; Default Value: nothing is defined by default except the values in php.ini and\n;                specified at startup with the -d argument\n;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com\n;php_flag[display_errors] = off\n;php_admin_value[error_log] = /var/log/fpm-php.www.log\n;php_admin_flag[log_errors] = on\n;php_admin_value[memory_limit] = 32M\n"
  },
  {
    "path": "images/php/8.2/Dockerfile",
    "content": "FROM php:8.2-fpm-bookworm\nLABEL maintainer=\"Mark Shust <mark@shust.com>\"\n\nARG APP_ID=1000\nRUN groupadd -g \"$APP_ID\" app \\\n  && useradd -g \"$APP_ID\" -u \"$APP_ID\" -d /var/www -s /bin/bash app\n\nRUN mkdir -p /etc/nginx/html /var/www/html /sock \\\n  && chown -R app:app /etc/nginx /var/www /usr/local/etc/php/conf.d /sock\n\nRUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash -\n\nRUN apt-get update && apt-get install -y \\\n    cron \\\n    default-mysql-client \\\n    git \\\n    gnupg \\\n    gzip \\\n    libbz2-dev \\\n    libfreetype6-dev \\\n    libicu-dev \\\n    libjpeg62-turbo-dev \\\n    libmagickwand-dev \\\n    libmcrypt-dev \\\n    libonig-dev \\\n    libpng-dev \\\n    libsodium-dev \\\n    libssh2-1-dev \\\n    libwebp-dev \\\n    libxslt1-dev \\\n    libzip-dev \\\n    lsof \\\n    mailutils \\\n    msmtp \\\n    nodejs \\\n    procps \\\n    rsync \\\n    strace \\\n    vim \\\n    zip \\\n    zlib1g-dev \\\n  && rm -rf /var/lib/apt/lists/*\n\nRUN pecl channel-update pecl.php.net && pecl install \\\n    redis-6.2.0 \\\n    ssh2-1.4.1 \\\n    swoole-6.0.2 \\\n    xdebug-3.4.2 \\\n    imagick-3.8.0RC2 \\\n  && pecl clear-cache \\\n  && rm -rf /tmp/pear\n\nRUN docker-php-ext-configure \\\n    gd --with-freetype --with-jpeg --with-webp \\\n  && docker-php-ext-install \\\n    bcmath \\\n    bz2 \\\n    calendar \\\n    exif \\\n    ftp \\\n    gd \\\n    gettext \\\n    intl \\\n    mbstring \\\n    mysqli \\\n    opcache \\\n    pcntl \\\n    pdo_mysql \\\n    soap \\\n    sockets \\\n    sodium \\\n    sysvmsg \\\n    sysvsem \\\n    sysvshm \\\n    xsl \\\n    zip \\\n  && docker-php-ext-enable \\\n    imagick \\\n    redis \\\n    ssh2 \\\n    xdebug\n\nRUN version=$(php -r \"echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;\") \\\n    && architecture=$(uname -m) \\\n    && curl -A \"Docker\" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/$architecture/$version \\\n    && mkdir -p /tmp/blackfire \\\n    && tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \\\n    && mv /tmp/blackfire/blackfire-*.so $(php -r \"echo ini_get ('extension_dir');\")/blackfire.so \\\n    && rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz\n\nRUN git clone --branch v0.4.18 --depth=1 https://github.com/NoiseByNorthwest/php-spx.git /usr/lib/php-spx \\\n    && cd /usr/lib/php-spx \\\n    && phpize \\\n    && ./configure \\\n    && make \\\n    && make install\n\nRUN curl -sS https://getcomposer.org/installer | \\\n  php -- --version=2.8.6 --install-dir=/usr/local/bin --filename=composer\n\nCOPY conf/blackfire.ini $PHP_INI_DIR/conf.d/blackfire.ini\nCOPY conf/spx.ini $PHP_INI_DIR/conf.d/spx.ini\nCOPY conf/msmtprc /etc/msmtprc\nCOPY conf/php.ini $PHP_INI_DIR\nCOPY conf/php-fpm.conf /usr/local/etc/\nCOPY conf/www.conf /usr/local/etc/php-fpm.d/\n\nUSER app:app\nVOLUME /var/www\nWORKDIR /var/www/html\n"
  },
  {
    "path": "images/php/8.2/conf/blackfire.ini",
    "content": "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8307\n"
  },
  {
    "path": "images/php/8.2/conf/msmtprc",
    "content": "account default\nhost mailcatcher\nport 1025\nfrom \"user@domain.com\"\n"
  },
  {
    "path": "images/php/8.2/conf/php-fpm.conf",
    "content": "; This file was initially adapted from the output of: (on PHP 5.6)\n;   grep -vE '^;|^ *$' /usr/local/etc/php-fpm.conf.default\n\n[global]\n\nerror_log = /proc/self/fd/2\ndaemonize = no\n\n[www]\n\n; if we send this to /proc/self/fd/1, it never appears\naccess.log = /proc/self/fd/2\n\n;user = app\n;group = app\n\nlisten = /sock/docker.sock\nlisten.owner = app\nlisten.group = app\nlisten.mode = 0660\n\npm = dynamic\npm.max_children = 10\npm.start_servers = 4\npm.min_spare_servers = 2\npm.max_spare_servers = 6\n\nclear_env = no\n\n; Ensure worker stdout and stderr are sent to the main error log.\ncatch_workers_output = yes\n\n; This needed to make PHP-SPX work in fpm mode.\nprocess.dumpable = yes\n"
  },
  {
    "path": "images/php/8.2/conf/php.ini",
    "content": "memory_limit = 4G\nmax_execution_time = 1800\nzlib.output_compression = 1\ncgi.fix_pathinfo = 0\ndate.timezone = UTC\n\nxdebug.mode = off\nxdebug.client_host = host.docker.internal\nxdebug.idekey = PHPSTORM\nxdebug.start_with_request = trigger\nxdebug.output_dir = /var/www/html/var/profile\nxdebug.profiler_output_name = cachegrind.out.%t.%p\n\nupload_max_filesize = 100M\npost_max_size = 100M\nmax_input_vars = 10000\n\nsendmail_path = \"/usr/bin/msmtp -t\"\n"
  },
  {
    "path": "images/php/8.2/conf/spx.ini",
    "content": "extension = /usr/lib/php-spx/modules/spx.so\nspx.http_enabled = 1\nspx.http_key = \"dev\"\nspx.http_ip_whitelist = \"*\"\nspx.data_dir = /var/www/spx_dumps\n"
  },
  {
    "path": "images/php/8.2/conf/www.conf",
    "content": "; Start a new pool named 'www'.\n; the variable $pool can we used in any directive and will be replaced by the\n; pool name ('www' here)\n[www]\n\n; Per pool prefix\n; It only applies on the following directives:\n; - 'access.log'\n; - 'slowlog'\n; - 'listen' (unixsocket)\n; - 'chroot'\n; - 'chdir'\n; - 'php_values'\n; - 'php_admin_values'\n; When not set, the global prefix (or NONE) applies instead.\n; Note: This directive can also be relative to the global prefix.\n; Default Value: none\n;prefix = /path/to/pools/$pool\n\n; Unix user/group of processes\n; Note: The user is mandatory. If the group is not set, the default user's group\n;       will be used.\nuser = app\ngroup = app\n\n; The address on which to accept FastCGI requests.\n; Valid syntaxes are:\n;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific IPv4 address on\n;                            a specific port;\n;   '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on\n;                            a specific port;\n;   'port'                 - to listen on a TCP socket to all addresses\n;                            (IPv6 and IPv4-mapped) on a specific port;\n;   '/path/to/unix/socket' - to listen on a unix socket.\n; Note: This value is mandatory.\nlisten = 127.0.0.1:9000\n\n; Set listen(2) backlog.\n; Default Value: 511 (-1 on FreeBSD and OpenBSD)\n;listen.backlog = 511\n\n; Set permissions for unix socket, if one is used. In Linux, read/write\n; permissions must be set in order to allow connections from a web server. Many\n; BSD-derived systems allow connections regardless of permissions.\n; Default Values: user and group are set as the running user\n;                 mode is set to 0660\n;listen.owner = www-data\n;listen.group = www-data\n;listen.mode = 0660\n; When POSIX Access Control Lists are supported you can set them using\n; these options, value is a comma separated list of user/group names.\n; When set, listen.owner and listen.group are ignored\n;listen.acl_users =\n;listen.acl_groups =\n\n; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect.\n; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original\n; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address\n; must be separated by a comma. If this value is left blank, connections will be\n; accepted from any ip address.\n; Default Value: any\n;listen.allowed_clients = 127.0.0.1\n\n; Specify the nice(2) priority to apply to the pool processes (only if set)\n; The value can vary from -19 (highest priority) to 20 (lower priority)\n; Note: - It will only work if the FPM master process is launched as root\n;       - The pool processes will inherit the master process priority\n;         unless it specified otherwise\n; Default Value: no set\n; process.priority = -19\n\n; Choose how the process manager will control the number of child processes.\n; Possible Values:\n;   static  - a fixed number (pm.max_children) of child processes;\n;   dynamic - the number of child processes are set dynamically based on the\n;             following directives. With this process management, there will be\n;             always at least 1 children.\n;             pm.max_children      - the maximum number of children that can\n;                                    be alive at the same time.\n;             pm.start_servers     - the number of children created on startup.\n;             pm.min_spare_servers - the minimum number of children in 'idle'\n;                                    state (waiting to process). If the number\n;                                    of 'idle' processes is less than this\n;                                    number then some children will be created.\n;             pm.max_spare_servers - the maximum number of children in 'idle'\n;                                    state (waiting to process). If the number\n;                                    of 'idle' processes is greater than this\n;                                    number then some children will be killed.\n;  ondemand - no children are created at startup. Children will be forked when\n;             new requests will connect. The following parameter are used:\n;             pm.max_children           - the maximum number of children that\n;                                         can be alive at the same time.\n;             pm.process_idle_timeout   - The number of seconds after which\n;                                         an idle process will be killed.\n; Note: This value is mandatory.\npm = dynamic\n\n; The number of child processes to be created when pm is set to 'static' and the\n; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.\n; This value sets the limit on the number of simultaneous requests that will be\n; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.\n; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP\n; CGI. The below defaults are based on a server without much resources. Don't\n; forget to tweak pm.* to fit your needs.\n; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'\n; Note: This value is mandatory.\npm.max_children = 5\n\n; The number of child processes created on startup.\n; Note: Used only when pm is set to 'dynamic'\n; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2\npm.start_servers = 2\n\n; The desired minimum number of idle server processes.\n; Note: Used only when pm is set to 'dynamic'\n; Note: Mandatory when pm is set to 'dynamic'\npm.min_spare_servers = 1\n\n; The desired maximum number of idle server processes.\n; Note: Used only when pm is set to 'dynamic'\n; Note: Mandatory when pm is set to 'dynamic'\npm.max_spare_servers = 3\n\n; The number of seconds after which an idle process will be killed.\n; Note: Used only when pm is set to 'ondemand'\n; Default Value: 10s\n;pm.process_idle_timeout = 10s;\n\n; The number of requests each child process should execute before respawning.\n; This can be useful to work around memory leaks in 3rd party libraries. For\n; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS.\n; Default Value: 0\n;pm.max_requests = 500\n\n; The URI to view the FPM status page. If this value is not set, no URI will be\n; recognized as a status page. It shows the following informations:\n;   pool                 - the name of the pool;\n;   process manager      - static, dynamic or ondemand;\n;   start time           - the date and time FPM has started;\n;   start since          - number of seconds since FPM has started;\n;   accepted conn        - the number of request accepted by the pool;\n;   listen queue         - the number of request in the queue of pending\n;                          connections (see backlog in listen(2));\n;   max listen queue     - the maximum number of requests in the queue\n;                          of pending connections since FPM has started;\n;   listen queue len     - the size of the socket queue of pending connections;\n;   idle processes       - the number of idle processes;\n;   active processes     - the number of active processes;\n;   total processes      - the number of idle + active processes;\n;   max active processes - the maximum number of active processes since FPM\n;                          has started;\n;   max children reached - number of times, the process limit has been reached,\n;                          when pm tries to start more children (works only for\n;                          pm 'dynamic' and 'ondemand');\n; Value are updated in real time.\n; Example output:\n;   pool:                 www\n;   process manager:      static\n;   start time:           01/Jul/2011:17:53:49 +0200\n;   start since:          62636\n;   accepted conn:        190460\n;   listen queue:         0\n;   max listen queue:     1\n;   listen queue len:     42\n;   idle processes:       4\n;   active processes:     11\n;   total processes:      15\n;   max active processes: 12\n;   max children reached: 0\n;\n; By default the status page output is formatted as text/plain. Passing either\n; 'html', 'xml' or 'json' in the query string will return the corresponding\n; output syntax. Example:\n;   http://www.foo.bar/status\n;   http://www.foo.bar/status?json\n;   http://www.foo.bar/status?html\n;   http://www.foo.bar/status?xml\n;\n; By default the status page only outputs short status. Passing 'full' in the\n; query string will also return status for each pool process.\n; Example:\n;   http://www.foo.bar/status?full\n;   http://www.foo.bar/status?json&full\n;   http://www.foo.bar/status?html&full\n;   http://www.foo.bar/status?xml&full\n; The Full status returns for each process:\n;   pid                  - the PID of the process;\n;   state                - the state of the process (Idle, Running, ...);\n;   start time           - the date and time the process has started;\n;   start since          - the number of seconds since the process has started;\n;   requests             - the number of requests the process has served;\n;   request duration     - the duration in µs of the requests;\n;   request method       - the request method (GET, POST, ...);\n;   request URI          - the request URI with the query string;\n;   content length       - the content length of the request (only with POST);\n;   user                 - the user (PHP_AUTH_USER) (or '-' if not set);\n;   script               - the main script called (or '-' if not set);\n;   last request cpu     - the %cpu the last request consumed\n;                          it's always 0 if the process is not in Idle state\n;                          because CPU calculation is done when the request\n;                          processing has terminated;\n;   last request memory  - the max amount of memory the last request consumed\n;                          it's always 0 if the process is not in Idle state\n;                          because memory calculation is done when the request\n;                          processing has terminated;\n; If the process is in Idle state, then informations are related to the\n; last request the process has served. Otherwise informations are related to\n; the current request being served.\n; Example output:\n;   ************************\n;   pid:                  31330\n;   state:                Running\n;   start time:           01/Jul/2011:17:53:49 +0200\n;   start since:          63087\n;   requests:             12808\n;   request duration:     1250261\n;   request method:       GET\n;   request URI:          /test_mem.php?N=10000\n;   content length:       0\n;   user:                 -\n;   script:               /home/fat/web/docs/php/test_mem.php\n;   last request cpu:     0.00\n;   last request memory:  0\n;\n; Note: There is a real-time FPM status monitoring sample web page available\n;       It's available in: /usr/local/share/php/fpm/status.html\n;\n; Note: The value must start with a leading slash (/). The value can be\n;       anything, but it may not be a good idea to use the .php extension or it\n;       may conflict with a real PHP file.\n; Default Value: not set\n;pm.status_path = /status\n\n; The ping URI to call the monitoring page of FPM. If this value is not set, no\n; URI will be recognized as a ping page. This could be used to test from outside\n; that FPM is alive and responding, or to\n; - create a graph of FPM availability (rrd or such);\n; - remove a server from a group if it is not responding (load balancing);\n; - trigger alerts for the operating team (24/7).\n; Note: The value must start with a leading slash (/). The value can be\n;       anything, but it may not be a good idea to use the .php extension or it\n;       may conflict with a real PHP file.\n; Default Value: not set\n;ping.path = /ping\n\n; This directive may be used to customize the response of a ping request. The\n; response is formatted as text/plain with a 200 response code.\n; Default Value: pong\n;ping.response = pong\n\n; The access log file\n; Default: not set\n;access.log = log/$pool.access.log\n\n; The access log format.\n; The following syntax is allowed\n;  %%: the '%' character\n;  %C: %CPU used by the request\n;      it can accept the following format:\n;      - %{user}C for user CPU only\n;      - %{system}C for system CPU only\n;      - %{total}C  for user + system CPU (default)\n;  %d: time taken to serve the request\n;      it can accept the following format:\n;      - %{seconds}d (default)\n;      - %{miliseconds}d\n;      - %{mili}d\n;      - %{microseconds}d\n;      - %{micro}d\n;  %e: an environment variable (same as $_ENV or $_SERVER)\n;      it must be associated with embraces to specify the name of the env\n;      variable. Some exemples:\n;      - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e\n;      - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e\n;  %f: script filename\n;  %l: content-length of the request (for POST request only)\n;  %m: request method\n;  %M: peak of memory allocated by PHP\n;      it can accept the following format:\n;      - %{bytes}M (default)\n;      - %{kilobytes}M\n;      - %{kilo}M\n;      - %{megabytes}M\n;      - %{mega}M\n;  %n: pool name\n;  %o: output header\n;      it must be associated with embraces to specify the name of the header:\n;      - %{Content-Type}o\n;      - %{X-Powered-By}o\n;      - %{Transfert-Encoding}o\n;      - ....\n;  %p: PID of the child that serviced the request\n;  %P: PID of the parent of the child that serviced the request\n;  %q: the query string\n;  %Q: the '?' character if query string exists\n;  %r: the request URI (without the query string, see %q and %Q)\n;  %R: remote IP address\n;  %s: status (response code)\n;  %t: server time the request was received\n;      it can accept a strftime(3) format:\n;      %d/%b/%Y:%H:%M:%S %z (default)\n;      The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag\n;      e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t\n;  %T: time the log has been written (the request has finished)\n;      it can accept a strftime(3) format:\n;      %d/%b/%Y:%H:%M:%S %z (default)\n;      The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag\n;      e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t\n;  %u: remote user\n;\n; Default: \"%R - %u %t \\\"%m %r\\\" %s\"\n;access.format = \"%R - %u %t \\\"%m %r%Q%q\\\" %s %f %{mili}d %{kilo}M %C%%\"\n\n; The log file for slow requests\n; Default Value: not set\n; Note: slowlog is mandatory if request_slowlog_timeout is set\n;slowlog = log/$pool.log.slow\n\n; The timeout for serving a single request after which a PHP backtrace will be\n; dumped to the 'slowlog' file. A value of '0s' means 'off'.\n; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)\n; Default Value: 0\n;request_slowlog_timeout = 0\n\n; The timeout for serving a single request after which the worker process will\n; be killed. This option should be used when the 'max_execution_time' ini option\n; does not stop script execution for some reason. A value of '0' means 'off'.\n; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)\n; Default Value: 0\n;request_terminate_timeout = 0\n\n; Set open file descriptor rlimit.\n; Default Value: system defined value\n;rlimit_files = 1024\n\n; Set max core size rlimit.\n; Possible Values: 'unlimited' or an integer greater or equal to 0\n; Default Value: system defined value\n;rlimit_core = 0\n\n; Chroot to this directory at the start. This value must be defined as an\n; absolute path. When this value is not set, chroot is not used.\n; Note: you can prefix with '$prefix' to chroot to the pool prefix or one\n; of its subdirectories. If the pool prefix is not set, the global prefix\n; will be used instead.\n; Note: chrooting is a great security feature and should be used whenever\n;       possible. However, all PHP paths will be relative to the chroot\n;       (error_log, sessions.save_path, ...).\n; Default Value: not set\n;chroot =\n\n; Chdir to this directory at the start.\n; Note: relative path can be used.\n; Default Value: current directory or / when chroot\n;chdir = /var/www\n\n; Redirect worker stdout and stderr into main error log. If not set, stdout and\n; stderr will be redirected to /dev/null according to FastCGI specs.\n; Note: on highloaded environement, this can cause some delay in the page\n; process time (several ms).\n; Default Value: no\n;catch_workers_output = yes\n\n; Clear environment in FPM workers\n; Prevents arbitrary environment variables from reaching FPM worker processes\n; by clearing the environment in workers before env vars specified in this\n; pool configuration are added.\n; Setting to \"no\" will make all environment variables available to PHP code\n; via getenv(), $_ENV and $_SERVER.\n; Default Value: yes\n;clear_env = no\n\n; Limits the extensions of the main script FPM will allow to parse. This can\n; prevent configuration mistakes on the web server side. You should only limit\n; FPM to .php extensions to prevent malicious users to use other extensions to\n; exectute php code.\n; Note: set an empty value to allow all extensions.\n; Default Value: .php\n;security.limit_extensions = .php .php3 .php4 .php5 .php7\n\n; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from\n; the current environment.\n; Default Value: clean env\n;env[HOSTNAME] = $HOSTNAME\n;env[PATH] = /usr/local/bin:/usr/bin:/bin\n;env[TMP] = /tmp\n;env[TMPDIR] = /tmp\n;env[TEMP] = /tmp\n\n; Additional php.ini defines, specific to this pool of workers. These settings\n; overwrite the values previously defined in the php.ini. The directives are the\n; same as the PHP SAPI:\n;   php_value/php_flag             - you can set classic ini defines which can\n;                                    be overwritten from PHP call 'ini_set'.\n;   php_admin_value/php_admin_flag - these directives won't be overwritten by\n;                                     PHP call 'ini_set'\n; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.\n\n; Defining 'extension' will load the corresponding shared extension from\n; extension_dir. Defining 'disable_functions' or 'disable_classes' will not\n; overwrite previously defined php.ini values, but will append the new value\n; instead.\n\n; Note: path INI options can be relative and will be expanded with the prefix\n; (pool, global or /usr/local)\n\n; Default Value: nothing is defined by default except the values in php.ini and\n;                specified at startup with the -d argument\n;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com\n;php_flag[display_errors] = off\n;php_admin_value[error_log] = /var/log/fpm-php.www.log\n;php_admin_flag[log_errors] = on\n;php_admin_value[memory_limit] = 32M\n"
  },
  {
    "path": "images/php/8.3/Dockerfile",
    "content": "FROM php:8.3-fpm-bookworm\nLABEL maintainer=\"Mark Shust <mark@shust.com>\"\n\nARG APP_ID=1000\nRUN groupadd -g \"$APP_ID\" app \\\n  && useradd -g \"$APP_ID\" -u \"$APP_ID\" -d /var/www -s /bin/bash app\n\nRUN mkdir -p /etc/nginx/html /var/www/html /sock \\\n  && chown -R app:app /etc/nginx /var/www /usr/local/etc/php/conf.d /sock\n\nRUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash -\n\nRUN apt-get update && apt-get install -y \\\n    cron \\\n    default-mysql-client \\\n    git \\\n    gnupg \\\n    gzip \\\n    libbz2-dev \\\n    libfreetype6-dev \\\n    libicu-dev \\\n    libjpeg62-turbo-dev \\\n    libmagickwand-dev \\\n    libmcrypt-dev \\\n    libonig-dev \\\n    libpng-dev \\\n    libsodium-dev \\\n    libssh2-1-dev \\\n    libwebp-dev \\\n    libxslt1-dev \\\n    libzip-dev \\\n    lsof \\\n    mailutils \\\n    msmtp \\\n    nodejs \\\n    procps \\\n    rsync \\\n    strace \\\n    vim \\\n    zip \\\n    zlib1g-dev \\\n  && rm -rf /var/lib/apt/lists/*\n\nRUN pecl channel-update pecl.php.net && pecl install \\\n    redis-6.2.0 \\\n    ssh2-1.4.1 \\\n    swoole-6.0.2 \\\n    xdebug-3.4.2 \\\n    imagick-3.8.0RC2 \\\n  && pecl clear-cache \\\n  && rm -rf /tmp/pear\n\nRUN docker-php-ext-configure \\\n    gd --with-freetype --with-jpeg --with-webp \\\n  && docker-php-ext-install \\\n    bcmath \\\n    bz2 \\\n    calendar \\\n    exif \\\n    ftp \\\n    gd \\\n    gettext \\\n    intl \\\n    mbstring \\\n    mysqli \\\n    opcache \\\n    pcntl \\\n    pdo_mysql \\\n    soap \\\n    sockets \\\n    sodium \\\n    sysvmsg \\\n    sysvsem \\\n    sysvshm \\\n    xsl \\\n    zip \\\n  && docker-php-ext-enable \\\n    imagick \\\n    redis \\\n    ssh2 \\\n    xdebug\n\nRUN version=$(php -r \"echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;\") \\\n    && architecture=$(uname -m) \\\n    && curl -A \"Docker\" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/$architecture/$version \\\n    && mkdir -p /tmp/blackfire \\\n    && tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \\\n    && mv /tmp/blackfire/blackfire-*.so $(php -r \"echo ini_get ('extension_dir');\")/blackfire.so \\\n    && rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz\n\nRUN git clone --branch v0.4.18 --depth=1 https://github.com/NoiseByNorthwest/php-spx.git /usr/lib/php-spx \\\n    && cd /usr/lib/php-spx \\\n    && phpize \\\n    && ./configure \\\n    && make \\\n    && make install\n\nRUN curl -sS https://getcomposer.org/installer | \\\n  php -- --version=2.8.6 --install-dir=/usr/local/bin --filename=composer\n\nCOPY conf/blackfire.ini $PHP_INI_DIR/conf.d/blackfire.ini\nCOPY conf/spx.ini $PHP_INI_DIR/conf.d/spx.ini\nCOPY conf/msmtprc /etc/msmtprc\nCOPY conf/php.ini $PHP_INI_DIR\nCOPY conf/php-fpm.conf /usr/local/etc/\nCOPY conf/www.conf /usr/local/etc/php-fpm.d/\n\nUSER app:app\nVOLUME /var/www\nWORKDIR /var/www/html\n"
  },
  {
    "path": "images/php/8.3/conf/blackfire.ini",
    "content": "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8307\n"
  },
  {
    "path": "images/php/8.3/conf/msmtprc",
    "content": "account default\nhost mailcatcher\nport 1025\nfrom \"user@domain.com\"\n"
  },
  {
    "path": "images/php/8.3/conf/php-fpm.conf",
    "content": "; This file was initially adapted from the output of: (on PHP 5.6)\n;   grep -vE '^;|^ *$' /usr/local/etc/php-fpm.conf.default\n\n[global]\n\nerror_log = /proc/self/fd/2\ndaemonize = no\n\n[www]\n\n; if we send this to /proc/self/fd/1, it never appears\naccess.log = /proc/self/fd/2\n\n;user = app\n;group = app\n\nlisten = /sock/docker.sock\nlisten.owner = app\nlisten.group = app\nlisten.mode = 0660\n\npm = dynamic\npm.max_children = 10\npm.start_servers = 4\npm.min_spare_servers = 2\npm.max_spare_servers = 6\n\nclear_env = no\n\n; Ensure worker stdout and stderr are sent to the main error log.\ncatch_workers_output = yes\n\n; This needed to make PHP-SPX work in fpm mode.\nprocess.dumpable = yes\n"
  },
  {
    "path": "images/php/8.3/conf/php.ini",
    "content": "memory_limit = 4G\nmax_execution_time = 1800\nzlib.output_compression = 1\ncgi.fix_pathinfo = 0\ndate.timezone = UTC\n\nxdebug.mode = off\nxdebug.client_host = host.docker.internal\nxdebug.idekey = PHPSTORM\nxdebug.start_with_request = trigger\nxdebug.output_dir = /var/www/html/var/profile\nxdebug.profiler_output_name = cachegrind.out.%t.%p\n\nupload_max_filesize = 100M\npost_max_size = 100M\nmax_input_vars = 10000\n\nsendmail_path = \"/usr/bin/msmtp -t\"\n"
  },
  {
    "path": "images/php/8.3/conf/spx.ini",
    "content": "extension = /usr/lib/php-spx/modules/spx.so\nspx.http_enabled = 1\nspx.http_key = \"dev\"\nspx.http_ip_whitelist = \"*\"\nspx.data_dir = /var/www/spx_dumps\n"
  },
  {
    "path": "images/php/8.3/conf/www.conf",
    "content": "; Start a new pool named 'www'.\n; the variable $pool can we used in any directive and will be replaced by the\n; pool name ('www' here)\n[www]\n\n; Per pool prefix\n; It only applies on the following directives:\n; - 'access.log'\n; - 'slowlog'\n; - 'listen' (unixsocket)\n; - 'chroot'\n; - 'chdir'\n; - 'php_values'\n; - 'php_admin_values'\n; When not set, the global prefix (or NONE) applies instead.\n; Note: This directive can also be relative to the global prefix.\n; Default Value: none\n;prefix = /path/to/pools/$pool\n\n; Unix user/group of processes\n; Note: The user is mandatory. If the group is not set, the default user's group\n;       will be used.\nuser = app\ngroup = app\n\n; The address on which to accept FastCGI requests.\n; Valid syntaxes are:\n;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific IPv4 address on\n;                            a specific port;\n;   '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on\n;                            a specific port;\n;   'port'                 - to listen on a TCP socket to all addresses\n;                            (IPv6 and IPv4-mapped) on a specific port;\n;   '/path/to/unix/socket' - to listen on a unix socket.\n; Note: This value is mandatory.\nlisten = 127.0.0.1:9000\n\n; Set listen(2) backlog.\n; Default Value: 511 (-1 on FreeBSD and OpenBSD)\n;listen.backlog = 511\n\n; Set permissions for unix socket, if one is used. In Linux, read/write\n; permissions must be set in order to allow connections from a web server. Many\n; BSD-derived systems allow connections regardless of permissions.\n; Default Values: user and group are set as the running user\n;                 mode is set to 0660\n;listen.owner = www-data\n;listen.group = www-data\n;listen.mode = 0660\n; When POSIX Access Control Lists are supported you can set them using\n; these options, value is a comma separated list of user/group names.\n; When set, listen.owner and listen.group are ignored\n;listen.acl_users =\n;listen.acl_groups =\n\n; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect.\n; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original\n; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address\n; must be separated by a comma. If this value is left blank, connections will be\n; accepted from any ip address.\n; Default Value: any\n;listen.allowed_clients = 127.0.0.1\n\n; Specify the nice(2) priority to apply to the pool processes (only if set)\n; The value can vary from -19 (highest priority) to 20 (lower priority)\n; Note: - It will only work if the FPM master process is launched as root\n;       - The pool processes will inherit the master process priority\n;         unless it specified otherwise\n; Default Value: no set\n; process.priority = -19\n\n; Choose how the process manager will control the number of child processes.\n; Possible Values:\n;   static  - a fixed number (pm.max_children) of child processes;\n;   dynamic - the number of child processes are set dynamically based on the\n;             following directives. With this process management, there will be\n;             always at least 1 children.\n;             pm.max_children      - the maximum number of children that can\n;                                    be alive at the same time.\n;             pm.start_servers     - the number of children created on startup.\n;             pm.min_spare_servers - the minimum number of children in 'idle'\n;                                    state (waiting to process). If the number\n;                                    of 'idle' processes is less than this\n;                                    number then some children will be created.\n;             pm.max_spare_servers - the maximum number of children in 'idle'\n;                                    state (waiting to process). If the number\n;                                    of 'idle' processes is greater than this\n;                                    number then some children will be killed.\n;  ondemand - no children are created at startup. Children will be forked when\n;             new requests will connect. The following parameter are used:\n;             pm.max_children           - the maximum number of children that\n;                                         can be alive at the same time.\n;             pm.process_idle_timeout   - The number of seconds after which\n;                                         an idle process will be killed.\n; Note: This value is mandatory.\npm = dynamic\n\n; The number of child processes to be created when pm is set to 'static' and the\n; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.\n; This value sets the limit on the number of simultaneous requests that will be\n; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.\n; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP\n; CGI. The below defaults are based on a server without much resources. Don't\n; forget to tweak pm.* to fit your needs.\n; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'\n; Note: This value is mandatory.\npm.max_children = 5\n\n; The number of child processes created on startup.\n; Note: Used only when pm is set to 'dynamic'\n; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2\npm.start_servers = 2\n\n; The desired minimum number of idle server processes.\n; Note: Used only when pm is set to 'dynamic'\n; Note: Mandatory when pm is set to 'dynamic'\npm.min_spare_servers = 1\n\n; The desired maximum number of idle server processes.\n; Note: Used only when pm is set to 'dynamic'\n; Note: Mandatory when pm is set to 'dynamic'\npm.max_spare_servers = 3\n\n; The number of seconds after which an idle process will be killed.\n; Note: Used only when pm is set to 'ondemand'\n; Default Value: 10s\n;pm.process_idle_timeout = 10s;\n\n; The number of requests each child process should execute before respawning.\n; This can be useful to work around memory leaks in 3rd party libraries. For\n; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS.\n; Default Value: 0\n;pm.max_requests = 500\n\n; The URI to view the FPM status page. If this value is not set, no URI will be\n; recognized as a status page. It shows the following informations:\n;   pool                 - the name of the pool;\n;   process manager      - static, dynamic or ondemand;\n;   start time           - the date and time FPM has started;\n;   start since          - number of seconds since FPM has started;\n;   accepted conn        - the number of request accepted by the pool;\n;   listen queue         - the number of request in the queue of pending\n;                          connections (see backlog in listen(2));\n;   max listen queue     - the maximum number of requests in the queue\n;                          of pending connections since FPM has started;\n;   listen queue len     - the size of the socket queue of pending connections;\n;   idle processes       - the number of idle processes;\n;   active processes     - the number of active processes;\n;   total processes      - the number of idle + active processes;\n;   max active processes - the maximum number of active processes since FPM\n;                          has started;\n;   max children reached - number of times, the process limit has been reached,\n;                          when pm tries to start more children (works only for\n;                          pm 'dynamic' and 'ondemand');\n; Value are updated in real time.\n; Example output:\n;   pool:                 www\n;   process manager:      static\n;   start time:           01/Jul/2011:17:53:49 +0200\n;   start since:          62636\n;   accepted conn:        190460\n;   listen queue:         0\n;   max listen queue:     1\n;   listen queue len:     42\n;   idle processes:       4\n;   active processes:     11\n;   total processes:      15\n;   max active processes: 12\n;   max children reached: 0\n;\n; By default the status page output is formatted as text/plain. Passing either\n; 'html', 'xml' or 'json' in the query string will return the corresponding\n; output syntax. Example:\n;   http://www.foo.bar/status\n;   http://www.foo.bar/status?json\n;   http://www.foo.bar/status?html\n;   http://www.foo.bar/status?xml\n;\n; By default the status page only outputs short status. Passing 'full' in the\n; query string will also return status for each pool process.\n; Example:\n;   http://www.foo.bar/status?full\n;   http://www.foo.bar/status?json&full\n;   http://www.foo.bar/status?html&full\n;   http://www.foo.bar/status?xml&full\n; The Full status returns for each process:\n;   pid                  - the PID of the process;\n;   state                - the state of the process (Idle, Running, ...);\n;   start time           - the date and time the process has started;\n;   start since          - the number of seconds since the process has started;\n;   requests             - the number of requests the process has served;\n;   request duration     - the duration in µs of the requests;\n;   request method       - the request method (GET, POST, ...);\n;   request URI          - the request URI with the query string;\n;   content length       - the content length of the request (only with POST);\n;   user                 - the user (PHP_AUTH_USER) (or '-' if not set);\n;   script               - the main script called (or '-' if not set);\n;   last request cpu     - the %cpu the last request consumed\n;                          it's always 0 if the process is not in Idle state\n;                          because CPU calculation is done when the request\n;                          processing has terminated;\n;   last request memory  - the max amount of memory the last request consumed\n;                          it's always 0 if the process is not in Idle state\n;                          because memory calculation is done when the request\n;                          processing has terminated;\n; If the process is in Idle state, then informations are related to the\n; last request the process has served. Otherwise informations are related to\n; the current request being served.\n; Example output:\n;   ************************\n;   pid:                  31330\n;   state:                Running\n;   start time:           01/Jul/2011:17:53:49 +0200\n;   start since:          63087\n;   requests:             12808\n;   request duration:     1250261\n;   request method:       GET\n;   request URI:          /test_mem.php?N=10000\n;   content length:       0\n;   user:                 -\n;   script:               /home/fat/web/docs/php/test_mem.php\n;   last request cpu:     0.00\n;   last request memory:  0\n;\n; Note: There is a real-time FPM status monitoring sample web page available\n;       It's available in: /usr/local/share/php/fpm/status.html\n;\n; Note: The value must start with a leading slash (/). The value can be\n;       anything, but it may not be a good idea to use the .php extension or it\n;       may conflict with a real PHP file.\n; Default Value: not set\n;pm.status_path = /status\n\n; The ping URI to call the monitoring page of FPM. If this value is not set, no\n; URI will be recognized as a ping page. This could be used to test from outside\n; that FPM is alive and responding, or to\n; - create a graph of FPM availability (rrd or such);\n; - remove a server from a group if it is not responding (load balancing);\n; - trigger alerts for the operating team (24/7).\n; Note: The value must start with a leading slash (/). The value can be\n;       anything, but it may not be a good idea to use the .php extension or it\n;       may conflict with a real PHP file.\n; Default Value: not set\n;ping.path = /ping\n\n; This directive may be used to customize the response of a ping request. The\n; response is formatted as text/plain with a 200 response code.\n; Default Value: pong\n;ping.response = pong\n\n; The access log file\n; Default: not set\n;access.log = log/$pool.access.log\n\n; The access log format.\n; The following syntax is allowed\n;  %%: the '%' character\n;  %C: %CPU used by the request\n;      it can accept the following format:\n;      - %{user}C for user CPU only\n;      - %{system}C for system CPU only\n;      - %{total}C  for user + system CPU (default)\n;  %d: time taken to serve the request\n;      it can accept the following format:\n;      - %{seconds}d (default)\n;      - %{miliseconds}d\n;      - %{mili}d\n;      - %{microseconds}d\n;      - %{micro}d\n;  %e: an environment variable (same as $_ENV or $_SERVER)\n;      it must be associated with embraces to specify the name of the env\n;      variable. Some exemples:\n;      - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e\n;      - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e\n;  %f: script filename\n;  %l: content-length of the request (for POST request only)\n;  %m: request method\n;  %M: peak of memory allocated by PHP\n;      it can accept the following format:\n;      - %{bytes}M (default)\n;      - %{kilobytes}M\n;      - %{kilo}M\n;      - %{megabytes}M\n;      - %{mega}M\n;  %n: pool name\n;  %o: output header\n;      it must be associated with embraces to specify the name of the header:\n;      - %{Content-Type}o\n;      - %{X-Powered-By}o\n;      - %{Transfert-Encoding}o\n;      - ....\n;  %p: PID of the child that serviced the request\n;  %P: PID of the parent of the child that serviced the request\n;  %q: the query string\n;  %Q: the '?' character if query string exists\n;  %r: the request URI (without the query string, see %q and %Q)\n;  %R: remote IP address\n;  %s: status (response code)\n;  %t: server time the request was received\n;      it can accept a strftime(3) format:\n;      %d/%b/%Y:%H:%M:%S %z (default)\n;      The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag\n;      e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t\n;  %T: time the log has been written (the request has finished)\n;      it can accept a strftime(3) format:\n;      %d/%b/%Y:%H:%M:%S %z (default)\n;      The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag\n;      e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t\n;  %u: remote user\n;\n; Default: \"%R - %u %t \\\"%m %r\\\" %s\"\n;access.format = \"%R - %u %t \\\"%m %r%Q%q\\\" %s %f %{mili}d %{kilo}M %C%%\"\n\n; The log file for slow requests\n; Default Value: not set\n; Note: slowlog is mandatory if request_slowlog_timeout is set\n;slowlog = log/$pool.log.slow\n\n; The timeout for serving a single request after which a PHP backtrace will be\n; dumped to the 'slowlog' file. A value of '0s' means 'off'.\n; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)\n; Default Value: 0\n;request_slowlog_timeout = 0\n\n; The timeout for serving a single request after which the worker process will\n; be killed. This option should be used when the 'max_execution_time' ini option\n; does not stop script execution for some reason. A value of '0' means 'off'.\n; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)\n; Default Value: 0\n;request_terminate_timeout = 0\n\n; Set open file descriptor rlimit.\n; Default Value: system defined value\n;rlimit_files = 1024\n\n; Set max core size rlimit.\n; Possible Values: 'unlimited' or an integer greater or equal to 0\n; Default Value: system defined value\n;rlimit_core = 0\n\n; Chroot to this directory at the start. This value must be defined as an\n; absolute path. When this value is not set, chroot is not used.\n; Note: you can prefix with '$prefix' to chroot to the pool prefix or one\n; of its subdirectories. If the pool prefix is not set, the global prefix\n; will be used instead.\n; Note: chrooting is a great security feature and should be used whenever\n;       possible. However, all PHP paths will be relative to the chroot\n;       (error_log, sessions.save_path, ...).\n; Default Value: not set\n;chroot =\n\n; Chdir to this directory at the start.\n; Note: relative path can be used.\n; Default Value: current directory or / when chroot\n;chdir = /var/www\n\n; Redirect worker stdout and stderr into main error log. If not set, stdout and\n; stderr will be redirected to /dev/null according to FastCGI specs.\n; Note: on highloaded environement, this can cause some delay in the page\n; process time (several ms).\n; Default Value: no\n;catch_workers_output = yes\n\n; Clear environment in FPM workers\n; Prevents arbitrary environment variables from reaching FPM worker processes\n; by clearing the environment in workers before env vars specified in this\n; pool configuration are added.\n; Setting to \"no\" will make all environment variables available to PHP code\n; via getenv(), $_ENV and $_SERVER.\n; Default Value: yes\n;clear_env = no\n\n; Limits the extensions of the main script FPM will allow to parse. This can\n; prevent configuration mistakes on the web server side. You should only limit\n; FPM to .php extensions to prevent malicious users to use other extensions to\n; exectute php code.\n; Note: set an empty value to allow all extensions.\n; Default Value: .php\n;security.limit_extensions = .php .php3 .php4 .php5 .php7\n\n; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from\n; the current environment.\n; Default Value: clean env\n;env[HOSTNAME] = $HOSTNAME\n;env[PATH] = /usr/local/bin:/usr/bin:/bin\n;env[TMP] = /tmp\n;env[TMPDIR] = /tmp\n;env[TEMP] = /tmp\n\n; Additional php.ini defines, specific to this pool of workers. These settings\n; overwrite the values previously defined in the php.ini. The directives are the\n; same as the PHP SAPI:\n;   php_value/php_flag             - you can set classic ini defines which can\n;                                    be overwritten from PHP call 'ini_set'.\n;   php_admin_value/php_admin_flag - these directives won't be overwritten by\n;                                     PHP call 'ini_set'\n; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.\n\n; Defining 'extension' will load the corresponding shared extension from\n; extension_dir. Defining 'disable_functions' or 'disable_classes' will not\n; overwrite previously defined php.ini values, but will append the new value\n; instead.\n\n; Note: path INI options can be relative and will be expanded with the prefix\n; (pool, global or /usr/local)\n\n; Default Value: nothing is defined by default except the values in php.ini and\n;                specified at startup with the -d argument\n;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com\n;php_flag[display_errors] = off\n;php_admin_value[error_log] = /var/log/fpm-php.www.log\n;php_admin_flag[log_errors] = on\n;php_admin_value[memory_limit] = 32M\n"
  },
  {
    "path": "images/php/8.4/Dockerfile",
    "content": "FROM php:8.4-fpm-bookworm\nLABEL maintainer=\"Mark Shust <mark@shust.com>\"\n\nARG APP_ID=1000\nRUN groupadd -g \"$APP_ID\" app \\\n  && useradd -g \"$APP_ID\" -u \"$APP_ID\" -d /var/www -s /bin/bash app\n\nRUN mkdir -p /etc/nginx/html /var/www/html /sock \\\n  && chown -R app:app /etc/nginx /var/www /usr/local/etc/php/conf.d /sock\n\nRUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash -\n\nRUN apt-get update && apt-get install -y \\\n    cron \\\n    default-mysql-client \\\n    git \\\n    gnupg \\\n    gzip \\\n    libbz2-dev \\\n    libfreetype6-dev \\\n    libicu-dev \\\n    libjpeg62-turbo-dev \\\n    libmagickwand-dev \\\n    libmcrypt-dev \\\n    libonig-dev \\\n    libpng-dev \\\n    libsodium-dev \\\n    libssh2-1-dev \\\n    libwebp-dev \\\n    libxslt1-dev \\\n    libzip-dev \\\n    lsof \\\n    mailutils \\\n    msmtp \\\n    nodejs \\\n    procps \\\n    rsync \\\n    strace \\\n    vim \\\n    zip \\\n    zlib1g-dev \\\n  && rm -rf /var/lib/apt/lists/*\n\nRUN pecl channel-update pecl.php.net && pecl install \\\n    redis-6.2.0 \\\n    ssh2-1.4.1 \\\n    swoole-6.0.2 \\\n    xdebug-3.4.2 \\\n    imagick-3.8.0RC2 \\\n  && pecl clear-cache \\\n  && rm -rf /tmp/pear\n\nRUN docker-php-ext-configure \\\n    gd --with-freetype --with-jpeg --with-webp \\\n  && docker-php-ext-install \\\n    bcmath \\\n    bz2 \\\n    calendar \\\n    exif \\\n    ftp \\\n    gd \\\n    gettext \\\n    intl \\\n    mbstring \\\n    mysqli \\\n    opcache \\\n    pcntl \\\n    pdo_mysql \\\n    soap \\\n    sockets \\\n    sodium \\\n    sysvmsg \\\n    sysvsem \\\n    sysvshm \\\n    xsl \\\n    zip \\\n  && docker-php-ext-enable \\\n    imagick \\\n    redis \\\n    ssh2 \\\n    xdebug\n\nRUN version=$(php -r \"echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;\") \\\n    && architecture=$(uname -m) \\\n    && curl -A \"Docker\" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/$architecture/$version \\\n    && mkdir -p /tmp/blackfire \\\n    && tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \\\n    && mv /tmp/blackfire/blackfire-*.so $(php -r \"echo ini_get ('extension_dir');\")/blackfire.so \\\n    && rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz\n\nRUN git clone --branch v0.4.18 --depth=1 https://github.com/NoiseByNorthwest/php-spx.git /usr/lib/php-spx \\\n    && cd /usr/lib/php-spx \\\n    && phpize \\\n    && ./configure \\\n    && make \\\n    && make install\n\nRUN curl -sS https://getcomposer.org/installer | \\\n  php -- --version=2.8.6 --install-dir=/usr/local/bin --filename=composer\n\nCOPY conf/blackfire.ini $PHP_INI_DIR/conf.d/blackfire.ini\nCOPY conf/spx.ini $PHP_INI_DIR/conf.d/spx.ini\nCOPY conf/msmtprc /etc/msmtprc\nCOPY conf/php.ini $PHP_INI_DIR\nCOPY conf/php-fpm.conf /usr/local/etc/\nCOPY conf/www.conf /usr/local/etc/php-fpm.d/\n\nUSER app:app\nVOLUME /var/www\nWORKDIR /var/www/html\n"
  },
  {
    "path": "images/php/8.4/conf/blackfire.ini",
    "content": "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8307\n"
  },
  {
    "path": "images/php/8.4/conf/msmtprc",
    "content": "account default\nhost mailcatcher\nport 1025\nfrom \"user@domain.com\"\n"
  },
  {
    "path": "images/php/8.4/conf/php-fpm.conf",
    "content": "; This file was initially adapted from the output of: (on PHP 5.6)\n;   grep -vE '^;|^ *$' /usr/local/etc/php-fpm.conf.default\n\n[global]\n\nerror_log = /proc/self/fd/2\ndaemonize = no\n\n[www]\n\n; if we send this to /proc/self/fd/1, it never appears\naccess.log = /proc/self/fd/2\n\n;user = app\n;group = app\n\nlisten = /sock/docker.sock\nlisten.owner = app\nlisten.group = app\nlisten.mode = 0660\n\npm = dynamic\npm.max_children = 10\npm.start_servers = 4\npm.min_spare_servers = 2\npm.max_spare_servers = 6\n\nclear_env = no\n\n; Ensure worker stdout and stderr are sent to the main error log.\ncatch_workers_output = yes\n\n; This needed to make PHP-SPX work in fpm mode.\nprocess.dumpable = yes\n"
  },
  {
    "path": "images/php/8.4/conf/php.ini",
    "content": "memory_limit = 4G\nmax_execution_time = 1800\nzlib.output_compression = 1\ncgi.fix_pathinfo = 0\ndate.timezone = UTC\n\nxdebug.mode = off\nxdebug.client_host = host.docker.internal\nxdebug.idekey = PHPSTORM\nxdebug.start_with_request = trigger\nxdebug.output_dir = /var/www/html/var/profile\nxdebug.profiler_output_name = cachegrind.out.%t.%p\n\nupload_max_filesize = 100M\npost_max_size = 100M\nmax_input_vars = 10000\n\nsendmail_path = \"/usr/bin/msmtp -t\"\n"
  },
  {
    "path": "images/php/8.4/conf/spx.ini",
    "content": "extension = /usr/lib/php-spx/modules/spx.so\nspx.http_enabled = 1\nspx.http_key = \"dev\"\nspx.http_ip_whitelist = \"*\"\nspx.data_dir = /var/www/spx_dumps\n"
  },
  {
    "path": "images/php/8.4/conf/www.conf",
    "content": "; Start a new pool named 'www'.\n; the variable $pool can we used in any directive and will be replaced by the\n; pool name ('www' here)\n[www]\n\n; Per pool prefix\n; It only applies on the following directives:\n; - 'access.log'\n; - 'slowlog'\n; - 'listen' (unixsocket)\n; - 'chroot'\n; - 'chdir'\n; - 'php_values'\n; - 'php_admin_values'\n; When not set, the global prefix (or NONE) applies instead.\n; Note: This directive can also be relative to the global prefix.\n; Default Value: none\n;prefix = /path/to/pools/$pool\n\n; Unix user/group of processes\n; Note: The user is mandatory. If the group is not set, the default user's group\n;       will be used.\nuser = app\ngroup = app\n\n; The address on which to accept FastCGI requests.\n; Valid syntaxes are:\n;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific IPv4 address on\n;                            a specific port;\n;   '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on\n;                            a specific port;\n;   'port'                 - to listen on a TCP socket to all addresses\n;                            (IPv6 and IPv4-mapped) on a specific port;\n;   '/path/to/unix/socket' - to listen on a unix socket.\n; Note: This value is mandatory.\nlisten = 127.0.0.1:9000\n\n; Set listen(2) backlog.\n; Default Value: 511 (-1 on FreeBSD and OpenBSD)\n;listen.backlog = 511\n\n; Set permissions for unix socket, if one is used. In Linux, read/write\n; permissions must be set in order to allow connections from a web server. Many\n; BSD-derived systems allow connections regardless of permissions.\n; Default Values: user and group are set as the running user\n;                 mode is set to 0660\n;listen.owner = www-data\n;listen.group = www-data\n;listen.mode = 0660\n; When POSIX Access Control Lists are supported you can set them using\n; these options, value is a comma separated list of user/group names.\n; When set, listen.owner and listen.group are ignored\n;listen.acl_users =\n;listen.acl_groups =\n\n; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect.\n; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original\n; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address\n; must be separated by a comma. If this value is left blank, connections will be\n; accepted from any ip address.\n; Default Value: any\n;listen.allowed_clients = 127.0.0.1\n\n; Specify the nice(2) priority to apply to the pool processes (only if set)\n; The value can vary from -19 (highest priority) to 20 (lower priority)\n; Note: - It will only work if the FPM master process is launched as root\n;       - The pool processes will inherit the master process priority\n;         unless it specified otherwise\n; Default Value: no set\n; process.priority = -19\n\n; Choose how the process manager will control the number of child processes.\n; Possible Values:\n;   static  - a fixed number (pm.max_children) of child processes;\n;   dynamic - the number of child processes are set dynamically based on the\n;             following directives. With this process management, there will be\n;             always at least 1 children.\n;             pm.max_children      - the maximum number of children that can\n;                                    be alive at the same time.\n;             pm.start_servers     - the number of children created on startup.\n;             pm.min_spare_servers - the minimum number of children in 'idle'\n;                                    state (waiting to process). If the number\n;                                    of 'idle' processes is less than this\n;                                    number then some children will be created.\n;             pm.max_spare_servers - the maximum number of children in 'idle'\n;                                    state (waiting to process). If the number\n;                                    of 'idle' processes is greater than this\n;                                    number then some children will be killed.\n;  ondemand - no children are created at startup. Children will be forked when\n;             new requests will connect. The following parameter are used:\n;             pm.max_children           - the maximum number of children that\n;                                         can be alive at the same time.\n;             pm.process_idle_timeout   - The number of seconds after which\n;                                         an idle process will be killed.\n; Note: This value is mandatory.\npm = dynamic\n\n; The number of child processes to be created when pm is set to 'static' and the\n; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.\n; This value sets the limit on the number of simultaneous requests that will be\n; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.\n; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP\n; CGI. The below defaults are based on a server without much resources. Don't\n; forget to tweak pm.* to fit your needs.\n; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'\n; Note: This value is mandatory.\npm.max_children = 5\n\n; The number of child processes created on startup.\n; Note: Used only when pm is set to 'dynamic'\n; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2\npm.start_servers = 2\n\n; The desired minimum number of idle server processes.\n; Note: Used only when pm is set to 'dynamic'\n; Note: Mandatory when pm is set to 'dynamic'\npm.min_spare_servers = 1\n\n; The desired maximum number of idle server processes.\n; Note: Used only when pm is set to 'dynamic'\n; Note: Mandatory when pm is set to 'dynamic'\npm.max_spare_servers = 3\n\n; The number of seconds after which an idle process will be killed.\n; Note: Used only when pm is set to 'ondemand'\n; Default Value: 10s\n;pm.process_idle_timeout = 10s;\n\n; The number of requests each child process should execute before respawning.\n; This can be useful to work around memory leaks in 3rd party libraries. For\n; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS.\n; Default Value: 0\n;pm.max_requests = 500\n\n; The URI to view the FPM status page. If this value is not set, no URI will be\n; recognized as a status page. It shows the following informations:\n;   pool                 - the name of the pool;\n;   process manager      - static, dynamic or ondemand;\n;   start time           - the date and time FPM has started;\n;   start since          - number of seconds since FPM has started;\n;   accepted conn        - the number of request accepted by the pool;\n;   listen queue         - the number of request in the queue of pending\n;                          connections (see backlog in listen(2));\n;   max listen queue     - the maximum number of requests in the queue\n;                          of pending connections since FPM has started;\n;   listen queue len     - the size of the socket queue of pending connections;\n;   idle processes       - the number of idle processes;\n;   active processes     - the number of active processes;\n;   total processes      - the number of idle + active processes;\n;   max active processes - the maximum number of active processes since FPM\n;                          has started;\n;   max children reached - number of times, the process limit has been reached,\n;                          when pm tries to start more children (works only for\n;                          pm 'dynamic' and 'ondemand');\n; Value are updated in real time.\n; Example output:\n;   pool:                 www\n;   process manager:      static\n;   start time:           01/Jul/2011:17:53:49 +0200\n;   start since:          62636\n;   accepted conn:        190460\n;   listen queue:         0\n;   max listen queue:     1\n;   listen queue len:     42\n;   idle processes:       4\n;   active processes:     11\n;   total processes:      15\n;   max active processes: 12\n;   max children reached: 0\n;\n; By default the status page output is formatted as text/plain. Passing either\n; 'html', 'xml' or 'json' in the query string will return the corresponding\n; output syntax. Example:\n;   http://www.foo.bar/status\n;   http://www.foo.bar/status?json\n;   http://www.foo.bar/status?html\n;   http://www.foo.bar/status?xml\n;\n; By default the status page only outputs short status. Passing 'full' in the\n; query string will also return status for each pool process.\n; Example:\n;   http://www.foo.bar/status?full\n;   http://www.foo.bar/status?json&full\n;   http://www.foo.bar/status?html&full\n;   http://www.foo.bar/status?xml&full\n; The Full status returns for each process:\n;   pid                  - the PID of the process;\n;   state                - the state of the process (Idle, Running, ...);\n;   start time           - the date and time the process has started;\n;   start since          - the number of seconds since the process has started;\n;   requests             - the number of requests the process has served;\n;   request duration     - the duration in µs of the requests;\n;   request method       - the request method (GET, POST, ...);\n;   request URI          - the request URI with the query string;\n;   content length       - the content length of the request (only with POST);\n;   user                 - the user (PHP_AUTH_USER) (or '-' if not set);\n;   script               - the main script called (or '-' if not set);\n;   last request cpu     - the %cpu the last request consumed\n;                          it's always 0 if the process is not in Idle state\n;                          because CPU calculation is done when the request\n;                          processing has terminated;\n;   last request memory  - the max amount of memory the last request consumed\n;                          it's always 0 if the process is not in Idle state\n;                          because memory calculation is done when the request\n;                          processing has terminated;\n; If the process is in Idle state, then informations are related to the\n; last request the process has served. Otherwise informations are related to\n; the current request being served.\n; Example output:\n;   ************************\n;   pid:                  31330\n;   state:                Running\n;   start time:           01/Jul/2011:17:53:49 +0200\n;   start since:          63087\n;   requests:             12808\n;   request duration:     1250261\n;   request method:       GET\n;   request URI:          /test_mem.php?N=10000\n;   content length:       0\n;   user:                 -\n;   script:               /home/fat/web/docs/php/test_mem.php\n;   last request cpu:     0.00\n;   last request memory:  0\n;\n; Note: There is a real-time FPM status monitoring sample web page available\n;       It's available in: /usr/local/share/php/fpm/status.html\n;\n; Note: The value must start with a leading slash (/). The value can be\n;       anything, but it may not be a good idea to use the .php extension or it\n;       may conflict with a real PHP file.\n; Default Value: not set\n;pm.status_path = /status\n\n; The ping URI to call the monitoring page of FPM. If this value is not set, no\n; URI will be recognized as a ping page. This could be used to test from outside\n; that FPM is alive and responding, or to\n; - create a graph of FPM availability (rrd or such);\n; - remove a server from a group if it is not responding (load balancing);\n; - trigger alerts for the operating team (24/7).\n; Note: The value must start with a leading slash (/). The value can be\n;       anything, but it may not be a good idea to use the .php extension or it\n;       may conflict with a real PHP file.\n; Default Value: not set\n;ping.path = /ping\n\n; This directive may be used to customize the response of a ping request. The\n; response is formatted as text/plain with a 200 response code.\n; Default Value: pong\n;ping.response = pong\n\n; The access log file\n; Default: not set\n;access.log = log/$pool.access.log\n\n; The access log format.\n; The following syntax is allowed\n;  %%: the '%' character\n;  %C: %CPU used by the request\n;      it can accept the following format:\n;      - %{user}C for user CPU only\n;      - %{system}C for system CPU only\n;      - %{total}C  for user + system CPU (default)\n;  %d: time taken to serve the request\n;      it can accept the following format:\n;      - %{seconds}d (default)\n;      - %{miliseconds}d\n;      - %{mili}d\n;      - %{microseconds}d\n;      - %{micro}d\n;  %e: an environment variable (same as $_ENV or $_SERVER)\n;      it must be associated with embraces to specify the name of the env\n;      variable. Some exemples:\n;      - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e\n;      - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e\n;  %f: script filename\n;  %l: content-length of the request (for POST request only)\n;  %m: request method\n;  %M: peak of memory allocated by PHP\n;      it can accept the following format:\n;      - %{bytes}M (default)\n;      - %{kilobytes}M\n;      - %{kilo}M\n;      - %{megabytes}M\n;      - %{mega}M\n;  %n: pool name\n;  %o: output header\n;      it must be associated with embraces to specify the name of the header:\n;      - %{Content-Type}o\n;      - %{X-Powered-By}o\n;      - %{Transfert-Encoding}o\n;      - ....\n;  %p: PID of the child that serviced the request\n;  %P: PID of the parent of the child that serviced the request\n;  %q: the query string\n;  %Q: the '?' character if query string exists\n;  %r: the request URI (without the query string, see %q and %Q)\n;  %R: remote IP address\n;  %s: status (response code)\n;  %t: server time the request was received\n;      it can accept a strftime(3) format:\n;      %d/%b/%Y:%H:%M:%S %z (default)\n;      The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag\n;      e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t\n;  %T: time the log has been written (the request has finished)\n;      it can accept a strftime(3) format:\n;      %d/%b/%Y:%H:%M:%S %z (default)\n;      The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag\n;      e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t\n;  %u: remote user\n;\n; Default: \"%R - %u %t \\\"%m %r\\\" %s\"\n;access.format = \"%R - %u %t \\\"%m %r%Q%q\\\" %s %f %{mili}d %{kilo}M %C%%\"\n\n; The log file for slow requests\n; Default Value: not set\n; Note: slowlog is mandatory if request_slowlog_timeout is set\n;slowlog = log/$pool.log.slow\n\n; The timeout for serving a single request after which a PHP backtrace will be\n; dumped to the 'slowlog' file. A value of '0s' means 'off'.\n; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)\n; Default Value: 0\n;request_slowlog_timeout = 0\n\n; The timeout for serving a single request after which the worker process will\n; be killed. This option should be used when the 'max_execution_time' ini option\n; does not stop script execution for some reason. A value of '0' means 'off'.\n; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)\n; Default Value: 0\n;request_terminate_timeout = 0\n\n; Set open file descriptor rlimit.\n; Default Value: system defined value\n;rlimit_files = 1024\n\n; Set max core size rlimit.\n; Possible Values: 'unlimited' or an integer greater or equal to 0\n; Default Value: system defined value\n;rlimit_core = 0\n\n; Chroot to this directory at the start. This value must be defined as an\n; absolute path. When this value is not set, chroot is not used.\n; Note: you can prefix with '$prefix' to chroot to the pool prefix or one\n; of its subdirectories. If the pool prefix is not set, the global prefix\n; will be used instead.\n; Note: chrooting is a great security feature and should be used whenever\n;       possible. However, all PHP paths will be relative to the chroot\n;       (error_log, sessions.save_path, ...).\n; Default Value: not set\n;chroot =\n\n; Chdir to this directory at the start.\n; Note: relative path can be used.\n; Default Value: current directory or / when chroot\n;chdir = /var/www\n\n; Redirect worker stdout and stderr into main error log. If not set, stdout and\n; stderr will be redirected to /dev/null according to FastCGI specs.\n; Note: on highloaded environement, this can cause some delay in the page\n; process time (several ms).\n; Default Value: no\n;catch_workers_output = yes\n\n; Clear environment in FPM workers\n; Prevents arbitrary environment variables from reaching FPM worker processes\n; by clearing the environment in workers before env vars specified in this\n; pool configuration are added.\n; Setting to \"no\" will make all environment variables available to PHP code\n; via getenv(), $_ENV and $_SERVER.\n; Default Value: yes\n;clear_env = no\n\n; Limits the extensions of the main script FPM will allow to parse. This can\n; prevent configuration mistakes on the web server side. You should only limit\n; FPM to .php extensions to prevent malicious users to use other extensions to\n; exectute php code.\n; Note: set an empty value to allow all extensions.\n; Default Value: .php\n;security.limit_extensions = .php .php3 .php4 .php5 .php7\n\n; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from\n; the current environment.\n; Default Value: clean env\n;env[HOSTNAME] = $HOSTNAME\n;env[PATH] = /usr/local/bin:/usr/bin:/bin\n;env[TMP] = /tmp\n;env[TMPDIR] = /tmp\n;env[TEMP] = /tmp\n\n; Additional php.ini defines, specific to this pool of workers. These settings\n; overwrite the values previously defined in the php.ini. The directives are the\n; same as the PHP SAPI:\n;   php_value/php_flag             - you can set classic ini defines which can\n;                                    be overwritten from PHP call 'ini_set'.\n;   php_admin_value/php_admin_flag - these directives won't be overwritten by\n;                                     PHP call 'ini_set'\n; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.\n\n; Defining 'extension' will load the corresponding shared extension from\n; extension_dir. Defining 'disable_functions' or 'disable_classes' will not\n; overwrite previously defined php.ini values, but will append the new value\n; instead.\n\n; Note: path INI options can be relative and will be expanded with the prefix\n; (pool, global or /usr/local)\n\n; Default Value: nothing is defined by default except the values in php.ini and\n;                specified at startup with the -d argument\n;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com\n;php_flag[display_errors] = off\n;php_admin_value[error_log] = /var/log/fpm-php.www.log\n;php_admin_flag[log_errors] = on\n;php_admin_value[memory_limit] = 32M\n"
  },
  {
    "path": "images/rabbitmq/3.11/Dockerfile",
    "content": "FROM rabbitmq:3.11-management-alpine\n\nCOPY conf/rabbitmq.conf /etc/rabbitmq/rabbitmq.conf\n"
  },
  {
    "path": "images/rabbitmq/3.11/conf/rabbitmq.conf",
    "content": "vm_memory_high_watermark.absolute = 1GB\n"
  },
  {
    "path": "images/rabbitmq/3.12/Dockerfile",
    "content": "FROM rabbitmq:3.12-management-alpine\n\nCOPY conf/rabbitmq.conf /etc/rabbitmq/rabbitmq.conf\n"
  },
  {
    "path": "images/rabbitmq/3.12/conf/rabbitmq.conf",
    "content": "vm_memory_high_watermark.absolute = 1GB\n"
  },
  {
    "path": "images/rabbitmq/3.13/Dockerfile",
    "content": "FROM rabbitmq:3.13-management-alpine\n\nCOPY conf/rabbitmq.conf /etc/rabbitmq/rabbitmq.conf\n"
  },
  {
    "path": "images/rabbitmq/3.13/conf/rabbitmq.conf",
    "content": "vm_memory_high_watermark.absolute = 1GB\n"
  },
  {
    "path": "images/rabbitmq/3.9/Dockerfile",
    "content": "FROM rabbitmq:3.9-management-alpine\n\nCOPY conf/rabbitmq.conf /etc/rabbitmq/rabbitmq.conf\n"
  },
  {
    "path": "images/rabbitmq/3.9/conf/rabbitmq.conf",
    "content": "vm_memory_high_watermark.absolute = 1GB\n"
  },
  {
    "path": "images/rabbitmq/4.1/Dockerfile",
    "content": "FROM rabbitmq:4.1-management-alpine\n\nCOPY conf/rabbitmq.conf /etc/rabbitmq/rabbitmq.conf\n"
  },
  {
    "path": "images/rabbitmq/4.1/conf/rabbitmq.conf",
    "content": "vm_memory_high_watermark.absolute = 1GB\n"
  },
  {
    "path": "images/ssh/Dockerfile",
    "content": "FROM debian:buster-slim\n\nARG APP_ID=1000\n\nRUN apt-get update && apt-get install -y ssh\n\nRUN groupadd -g \"$APP_ID\" app \\\n  && useradd -g \"$APP_ID\" -u \"$APP_ID\" -d /var/www -s /bin/bash app\n\nRUN echo 'app:app' | chpasswd\n\nRUN service ssh start\n\nEXPOSE 22\n\nCMD [\"/usr/sbin/sshd\",\"-D\"]\n"
  },
  {
    "path": "lib/onelinesetup",
    "content": "#!/usr/bin/env bash\nset -o errexit\n\nDOMAIN=${1:-magento.test}\nEDITION=${2}\nVERSION=${3}\n\ncurl -s https://raw.githubusercontent.com/markshust/docker-magento/master/lib/template | bash\n\n# &&'s are used below otherwise onelinesetup script fails/errors after bin/download\n# ${:+\"\"} format only includes parameters if they were explicitly set\nbin/download ${EDITION:+\"$EDITION\"} ${VERSION:+\"$VERSION\"} \\\n  && bin/setup \"${DOMAIN}\"\n"
  },
  {
    "path": "lib/template",
    "content": "#!/usr/bin/env bash\n\nif [ -d \"./bin\" ]; then\n  echo \"Error: The current directory is not empty. Please remove all contents within this directory and try again.\"\n  exit 1\nfi\n\ngit init -qqq\ngit remote add origin https://github.com/markshust/docker-magento\ngit fetch origin -qqq\ngit checkout origin/master -- compose\n\nmv compose/* ./\nmv compose/.gitignore ./\nmv compose/.vscode ./\nrm -rf compose .git\ngit init\n\n# Ensure these are created so Docker doesn't create them as root\nmkdir -p ~/.composer ~/.ssh\n"
  }
]