diff --git a/.editorconfig b/.editorconfig index 3d04c2ec7..7a0bdf70c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,53 +5,18 @@ root = true [*] -# Change these settings to your own preference -indent_style = space -indent_size = 4 - -# We recommend you to keep these unchanged -end_of_line = lf charset = utf-8 -trim_trailing_whitespace = true insert_final_newline = true - -[*.{js,html,ts,tsx}] -indent_size = 2 - -[*.json] -indent_size = 2 - -[*.md] -trim_trailing_whitespace = false - -[*.sh] -indent_style = tab - -[*.xml.dist] +end_of_line = lf indent_style = space indent_size = 4 -[*.{yaml,yml}] -trim_trailing_whitespace = false - -[.github/workflows/*.yml] -indent_size = 2 - -[.gitmodules] +[**/{Dockerfile,Caddyfile,*.sh}] indent_style = tab -[.php_cs.dist] -indent_style = space -indent_size = 4 - -[composer.json] -indent_size = 4 - -[{compose,docker-compose}.{*.yaml,*.yml,yaml,yml}] +[{compose.*yaml,.github/**/*.yaml}] indent_size = 2 -[*.*Dockerfile] -indent_style = tab - -[{Caddyfile,*.*Caddyfile}] -indent_style = tab +[**.md] +indent_size = unset +indent_style = unset diff --git a/.github/linters/zizmor.yaml b/.github/linters/zizmor.yaml new file mode 100644 index 000000000..bbb03663b --- /dev/null +++ b/.github/linters/zizmor.yaml @@ -0,0 +1,6 @@ +--- +rules: + unpinned-uses: + config: + policies: + "*": ref-pin diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yaml similarity index 67% rename from .github/workflows/ci.yml rename to .github/workflows/ci.yaml index 48e0317a8..0447ec613 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yaml @@ -1,3 +1,4 @@ +--- name: CI on: @@ -7,6 +8,9 @@ on: pull_request: ~ workflow_dispatch: ~ +permissions: + contents: read + concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true @@ -16,14 +20,13 @@ jobs: name: Tests runs-on: ubuntu-latest steps: - - - name: Checkout + - name: Checkout code uses: actions/checkout@v5 - - - name: Set up Docker Buildx + with: + persist-credentials: false + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - - name: Build Docker images + - name: Build Docker images uses: docker/bake-action@v6 with: pull: true @@ -35,42 +38,43 @@ jobs: *.cache-from=type=gha,scope=${{github.ref}} *.cache-from=type=gha,scope=refs/heads/main *.cache-to=type=gha,scope=${{github.ref}},mode=max - - - name: Start services + - name: Start services run: docker compose up --wait --no-build - - - name: Check HTTP reachability + - name: Check HTTP reachability run: curl -v --fail-with-body http://localhost - - - name: Check HTTPS reachability + - name: Check HTTPS reachability if: false # Remove this line when the homepage is configured, or change the path to check run: curl -v --insecure --fail-with-body https://localhost - - - name: Check Mercure reachability + - name: Check Mercure reachability run: curl -vI --insecure --fail-with-body https://localhost/.well-known/mercure?topic=test - - - name: Create test database + - name: Create test database if: false # Remove this line if Doctrine ORM is installed run: docker compose exec -T php bin/console -e test doctrine:database:create - - - name: Run migrations + - name: Run migrations if: false # Remove this line if Doctrine Migrations is installed run: docker compose exec -T php bin/console -e test doctrine:migrations:migrate --no-interaction - - - name: Run PHPUnit + - name: Run PHPUnit if: false # Remove this line if PHPUnit is installed run: docker compose exec -T php bin/phpunit - - - name: Doctrine Schema Validator + - name: Doctrine Schema Validator if: false # Remove this line if Doctrine ORM is installed run: docker compose exec -T php bin/console -e test doctrine:schema:validate lint: - name: Docker Lint + name: Lint runs-on: ubuntu-latest + permissions: + contents: read + packages: read + statuses: write steps: - - - name: Checkout + - name: Checkout uses: actions/checkout@v5 - - - name: Lint Dockerfile - uses: hadolint/hadolint-action@v3.1.0 + with: + fetch-depth: 0 + persist-credentials: false + - name: Lint Code Base + uses: super-linter/super-linter/slim@v8 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VALIDATE_CHECKOV: false + VALIDATE_TRIVY: false diff --git a/README.md b/README.md index 1fb26da65..0995172a2 100644 --- a/README.md +++ b/README.md @@ -15,16 +15,16 @@ with [FrankenPHP](https://frankenphp.dev) and [Caddy](https://caddyserver.com/) ## Features -* Production, development and CI ready -* Just 1 service by default -* Blazing-fast performance thanks to [the worker mode of FrankenPHP](https://github.com/dunglas/frankenphp/blob/main/docs/worker.md) (automatically enabled in prod mode) -* [Installation of extra Docker Compose services](docs/extra-services.md) with Symfony Flex -* Automatic HTTPS (in dev and prod) -* HTTP/3 and [Early Hints](https://symfony.com/blog/new-in-symfony-6-3-early-hints) support -* Real-time messaging thanks to a built-in [Mercure hub](https://symfony.com/doc/current/mercure.html) -* [Vulcain](https://vulcain.rocks) support -* Native [XDebug](docs/xdebug.md) integration -* Super-readable configuration +- Production, development and CI ready +- Just 1 service by default +- Blazing-fast performance thanks to [the worker mode of FrankenPHP](https://github.com/dunglas/frankenphp/blob/main/docs/worker.md) (automatically enabled in prod mode) +- [Installation of extra Docker Compose services](docs/extra-services.md) with Symfony Flex +- Automatic HTTPS (in dev and prod) +- HTTP/3 and [Early Hints](https://symfony.com/blog/new-in-symfony-6-3-early-hints) support +- Real-time messaging thanks to a built-in [Mercure hub](https://symfony.com/doc/current/mercure.html) +- [Vulcain](https://vulcain.rocks) support +- Native [XDebug](docs/xdebug.md) integration +- Super-readable configuration **Enjoy!** diff --git a/compose.override.yaml b/compose.override.yaml index e47ed828b..ed85a3fdb 100644 --- a/compose.override.yaml +++ b/compose.override.yaml @@ -1,3 +1,4 @@ +--- # Development environment override services: php: @@ -21,6 +22,5 @@ services: # Ensure that host.docker.internal is correctly defined on Linux - host.docker.internal:host-gateway tty: true - ###> symfony/mercure-bundle ### ###< symfony/mercure-bundle ### diff --git a/compose.prod.yaml b/compose.prod.yaml index f0db05da6..a067ed3eb 100644 --- a/compose.prod.yaml +++ b/compose.prod.yaml @@ -1,3 +1,4 @@ +--- # Production environment override services: php: diff --git a/compose.yaml b/compose.yaml index 4920b12ea..48fa85ae3 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,3 +1,4 @@ +--- services: php: image: ${IMAGES_PREFIX:-}app-php diff --git a/docs/alpine.md b/docs/alpine.md index 012f577be..d165359ad 100644 --- a/docs/alpine.md +++ b/docs/alpine.md @@ -8,9 +8,11 @@ are known to be slower, and have several known issues. To switch to Alpine-based images, apply the following changes to the `Dockerfile`: + + ```patch --FROM dunglas/frankenphp:1-php8.3 AS frankenphp_upstream -+FROM dunglas/frankenphp:1-php8.3-alpine AS frankenphp_upstream +-FROM dunglas/frankenphp:1-php8.4 AS frankenphp_upstream ++FROM dunglas/frankenphp:1-php8.4-alpine AS frankenphp_upstream -# hadolint ignore=DL3008 -RUN apt-get update && apt-get install -y --no-install-recommends \ @@ -21,9 +23,10 @@ To switch to Alpine-based images, apply the following changes to the `Dockerfile - && rm -rf /var/lib/apt/lists/* +# hadolint ignore=DL3018 +RUN apk add --no-cache \ -+ acl \ -+ file \ -+ gettext \ -+ git \ -+ ; ++ acl \ ++ file \ ++ gettext \ ++ git ``` + + diff --git a/docs/existing-project.md b/docs/existing-project.md index 7a7893598..472ecb4c4 100644 --- a/docs/existing-project.md +++ b/docs/existing-project.md @@ -4,46 +4,72 @@ It's also possible to use Symfony Docker with existing projects! First, [download this skeleton](https://github.com/dunglas/symfony-docker). -If you cloned the Git repository, be sure to not copy the `.git` directory to prevent conflicts with the `.git` directory already in your existing project. -You can copy the contents of the repository using git and tar. This will not contain `.git` or any uncommited changes. +If you cloned the Git repository, be sure to not copy the `.git` directory +to prevent conflicts with the `.git` directory already in your existing project. - git archive --format=tar HEAD | tar -xC my-existing-project/ +You can copy the contents of the repository using Git and tar. +This will not contain `.git` or any uncommited changes. -If you downloaded the skeleton as a zip you can just copy the extracted files: +```console +git archive --format=tar HEAD | tar -xC my-existing-project/ +``` - cp -Rp symfony-docker/. my-existing-project/ +If you downloaded the skeleton as a ZIP you can just copy the extracted files: + +```console +cp -Rp symfony-docker/. my-existing-project/ +``` Enable the Docker support of Symfony Flex: - composer config --json extra.symfony.docker 'true' +```console +composer config --json extra.symfony.docker 'true' +``` + +If you want to use the [worker mode of FrankenPHP](https://github.com/php/frankenphp/blob/main/docs/worker.md), +add the FrankenPHP runtime for Symfony: -If you want to use the [worker mode of FrankenPHP](https://github.com/php/frankenphp/blob/main/docs/worker.md), add the FrankenPHP runtime for Symfony: - - composer require runtime/frankenphp-symfony +```console +composer require runtime/frankenphp-symfony +``` > [!TIP] -> With Symfony 7.4, the `runtime/frankenphp-symfony` package isn't required anymore, as Symfony Runtime natively supports FrankenPHP worker mode. +> +> With Symfony 7.4, the `runtime/frankenphp-symfony` package isn't required anymore, +> as Symfony Runtime natively supports FrankenPHP worker mode. -Re-execute the recipes to update the Docker-related files according to the packages you use: +Re-execute the recipes to update the Docker-related files according to +the packages you use: - rm symfony.lock - composer recipes:install --force --verbose +```console +rm symfony.lock +composer recipes:install --force --verbose +``` Double-check the changes, revert the changes that you don't want to keep: - git diff - ... +```console +git diff +``` Build the Docker images: - docker compose build --pull --no-cache +```console +docker compose build --pull --no-cache +``` Start the project! - docker compose up --wait +```console +docker compose up --wait +``` Browse `https://localhost`, your Docker configuration is ready! > [!NOTE] -> The worker mode of FrankenPHP is enabled by default in the Caddyfile. To disabled it, comment the `worker {}` section of this file. -> You may also remove `runtime/frankenphp-symfony` if you never plan on using the worker mode. +> +> The worker mode of FrankenPHP is enabled by default in the Caddyfile. +> To disabled it, comment the `worker {}` section of this file. +> +> You may also remove `runtime/frankenphp-symfony` +> if you never plan on using the worker mode. diff --git a/docs/extra-services.md b/docs/extra-services.md index 851e5499f..683bd95fd 100644 --- a/docs/extra-services.md +++ b/docs/extra-services.md @@ -1,18 +1,25 @@ # Support for Extra Services -Symfony Docker is extensible. When you install a compatible Composer package using Symfony Flex, -the recipe will automatically modify the `Dockerfile` and `compose.yaml` to fulfill the requirements of this package. +Symfony Docker is extensible. +When you install a compatible Composer package using Symfony Flex, +the recipe will automatically modify the `Dockerfile` and `compose.yaml` files +to fulfill the requirements of this package. The currently supported packages are: -* `symfony/orm-pack`: install a PostgreSQL service -* `symfony/mercure-bundle`: use the Mercure.rocks module shipped with Caddy -* `symfony/panther`: install chromium and these drivers -* `symfony/mailer`: install a Mailpit service -* `blackfireio/blackfire-symfony-meta`: install a Blackfire service +- `symfony/orm-pack`: install a PostgreSQL service +- `symfony/mercure-bundle`: use the Mercure.rocks module shipped with Caddy +- `symfony/panther`: install chromium and these drivers +- `symfony/mailer`: install a Mailpit service +- `blackfireio/blackfire-symfony-meta`: install a Blackfire service > [!NOTE] +> > If a recipe modifies the Dockerfile, the container needs to be rebuilt. + + > [!WARNING] -> We recommend that you use the `composer require` command inside the container in development mode so that recipes can be applied correctly +> +> We recommend that you use the `composer require` command inside the container +> in development mode so that recipes can be applied correctly diff --git a/docs/makefile.md b/docs/makefile.md index 05b071a1a..355f895a5 100644 --- a/docs/makefile.md +++ b/docs/makefile.md @@ -27,10 +27,17 @@ git \ And rebuild the PHP image. -> [!NOTE] -> If you are using Windows, you have to install [chocolatey.org](https://chocolatey.org/) or [Cygwin](http://cygwin.com) to use the `make` command. Check out this [StackOverflow question](https://stackoverflow.com/q/2532234/633864) for more explanations. +> [!NOTE] +> +> If you are using Windows, you have to install [chocolatey.org](https://chocolatey.org/) +> or [Cygwin](http://cygwin.com) to use the `make` command. +> +> Check out this [StackOverflow question](https://stackoverflow.com/q/2532234/633864) +> for more explanations. -## The template +## The Template + + ```Makefile # Executables (local) @@ -96,9 +103,16 @@ cc: c=c:c ## Clear the cache cc: sf ``` -## Adding and modifying jobs + + +## Adding and Modifying Jobs + +Make sure to add this configuration to the [.editorconfig](/.editorconfig) file, +so that it forces your editor to use tabs instead of spaces. -Make sure to add this configuration to the [.editorconfig](/.editorconfig) file, so that it forces your editor to use tabs instead of spaces (Makefiles are not compatible with spaces by default). +> [!NOTE] +> +> Makefiles are not compatible with spaces by default. ```.editorconfig @@ -107,4 +121,5 @@ indent_style = tab ``` -If you still want to use space, you can configure the prefix in the Makefile itself. See [this answer on StackExchange](https://retrocomputing.stackexchange.com/a/20303). \ No newline at end of file +If you still want to use space, you can configure the prefix in the Makefile itself. +See [this answer on Stack Exchange](https://retrocomputing.stackexchange.com/a/20303). diff --git a/docs/mysql.md b/docs/mysql.md index ce955d5c7..9d6f96fee 100644 --- a/docs/mysql.md +++ b/docs/mysql.md @@ -1,13 +1,22 @@ # Using MySQL -The Docker configuration of this repository is extensible thanks to Flex recipes. By default, the recipe installs PostgreSQL. +The Docker configuration of this repository is extensible thanks to Flex recipes. +By default, the recipe installs PostgreSQL. + If you prefer to work with MySQL, follow these steps: -First, install the `symfony/orm-pack` package as described: `docker compose exec php composer req symfony/orm-pack` +First, install the `symfony/orm-pack` package as described: + +```console +docker compose exec php composer req symfony/orm-pack +``` ## Docker Configuration + Change the database image to use MySQL instead of PostgreSQL in `compose.yaml`: + + ```diff ###> doctrine/doctrine-bundle ### - image: postgres:${POSTGRES_VERSION:-16}-alpine @@ -36,12 +45,17 @@ Change the database image to use MySQL instead of PostgreSQL in `compose.yaml`: ###< doctrine/doctrine-bundle ### ``` -Depending on the database configuration, modify the environment in the same file at `services.php.environment.DATABASE_URL` -``` + + +Depending on the database configuration, +modify the environment in the same file at `services.php.environment.DATABASE_URL` + +```yaml DATABASE_URL: mysql://${MYSQL_USER:-app}:${MYSQL_PASSWORD:-!ChangeMe!}@database:3306/${MYSQL_DATABASE:-app}?serverVersion=${MYSQL_VERSION:-8}&charset=${MYSQL_CHARSET:-utf8mb4} ``` Since we changed the port, we also have to define this in the `compose.override.yaml`: + ```diff ###> doctrine/doctrine-bundle ### database: @@ -52,6 +66,7 @@ Since we changed the port, we also have to define this in the `compose.override. ``` Last but not least, we need to install the MySQL driver in `Dockerfile`: + ```diff ###> doctrine/doctrine-bundle ### -RUN install-php-extensions pdo_pgsql @@ -60,24 +75,33 @@ Last but not least, we need to install the MySQL driver in `Dockerfile`: ``` ## Change Environment + Change the database configuration in `.env`: -```dotenv +```dotenv DATABASE_URL=mysql://${MYSQL_USER:-app}:${MYSQL_PASSWORD:-!ChangeMe!}@database:3306/${MYSQL_DATABASE:-app}?serverVersion=${MYSQL_VERSION:-8}&charset=${MYSQL_CHARSET:-utf8mb4} ``` ## Final steps -Rebuild the docker environment: -```shell + +Rebuild the Docker environment: + +```console docker compose down --remove-orphans && docker compose build --pull --no-cache ``` Start the services: -```shell + +```console docker compose up --wait ``` Test your setup: -```shell + + + +```console docker compose exec php bin/console dbal:run-sql -q "SELECT 1" && echo "OK" || echo "Connection is not working" ``` + + diff --git a/docs/options.md b/docs/options.md index d38f6f9cd..fea2e11de 100644 --- a/docs/options.md +++ b/docs/options.md @@ -1,9 +1,11 @@ # Docker Build Options -You can customize the docker build process using these environment variables. +You can customize the Docker build process using these environment variables. -> [!NOTE] -> All Symfony-specific environment variables are used only if no `composer.json` file is found in the project directory. +> [!NOTE] +> +> All Symfony-specific environment variables are used only if no `composer.json` +> file is found in the project directory. ## Selecting a Specific Symfony Version @@ -13,53 +15,74 @@ For instance, use the following command to install Symfony 6.4: On Linux: - SYMFONY_VERSION=6.4.* docker compose up --wait +```console +SYMFONY_VERSION=6.4.* docker compose up --wait +``` + On Windows: - set SYMFONY_VERSION=6.4.* && docker compose up --wait&set SYMFONY_VERSION= +```console +set SYMFONY_VERSION=6.4.* && docker compose up --wait&set SYMFONY_VERSION= +``` ## Installing Development Versions of Symfony -To install a non-stable version of Symfony, use the `STABILITY` environment variable during the build. +To install a non-stable version of Symfony, +use the `STABILITY` environment variable during the build. + The value must be [a valid Composer stability option](https://getcomposer.org/doc/04-schema.md#minimum-stability). For instance, use the following command to use the development branch of Symfony: On Linux: - STABILITY=dev docker compose up --wait +```console +STABILITY=dev docker compose up --wait +``` On Windows: - - set STABILITY=dev && docker compose up --wait&set STABILITY= -## Using custom HTTP ports +```console +set STABILITY=dev && docker compose up --wait&set STABILITY= +``` -Use the environment variables `HTTP_PORT`, `HTTPS_PORT` and/or `HTTP3_PORT` to adjust the ports to your needs, e.g. +## Using Custom HTTP Ports - HTTP_PORT=8000 HTTPS_PORT=4443 HTTP3_PORT=4443 docker compose up --wait +Use the environment variables `HTTP_PORT`, `HTTPS_PORT` and/or `HTTP3_PORT` +to adjust the ports to your needs, e.g. + +```console +HTTP_PORT=8000 HTTPS_PORT=4443 HTTP3_PORT=4443 docker compose up --wait +``` to access your application on [https://localhost:4443](https://localhost:4443). -> [!NOTE] -> Let's Encrypt only supports the standard HTTP and HTTPS ports. Creating a Let's Encrypt certificate for another port will not work, you have to use the standard ports or to configure Caddy to use another provider. +> [!NOTE] +> +> Let's Encrypt only supports the standard HTTP and HTTPS ports. +> Creating a Let's Encrypt certificate for another port will not work, +> you have to use the standard ports or to configure Caddy to use another provider. +## `Caddyfile` Options -## Caddyfile Options +You can also customize the `Caddyfile` by using the following environment variables +to inject options block, directive or configuration. -You can also customize the `Caddyfile` by using the following environment variables to inject options block, directive or configuration. +> [!TIP] +> +> All the following environment variables can be defined in your `.env` file +> at the root of the project to keep them persistent at each startup -> [!TIP] -> All the following environment variables can be defined in your `.env` file at the root of the project to keep them persistent at each startup + | Environment variable | Description | Default value | -|---------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------| +| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | | `CADDY_GLOBAL_OPTIONS` | the [global options block](https://caddyserver.com/docs/caddyfile/options#global-options), one per line | | | `CADDY_EXTRA_CONFIG` | the [snippet](https://caddyserver.com/docs/caddyfile/concepts#snippets) or the [named-routes](https://caddyserver.com/docs/caddyfile/concepts#named-routes) options block, one per line | | | `CADDY_SERVER_EXTRA_DIRECTIVES` | the [`Caddyfile` directives](https://caddyserver.com/docs/caddyfile/concepts#directives) | | | `CADDY_SERVER_LOG_OPTIONS` | the [server log options block](https://caddyserver.com/docs/caddyfile/directives/log), one per line | | | `SERVER_NAME` | the server name or address | `localhost` | -| `FRANKENPHP_CONFIG` | a list of extra [FrankenPHP directives](https://frankenphp.dev/docs/config/#caddyfile-config), one per line | `import worker.Caddyfile` | +| `FRANKENPHP_CONFIG` | a list of extra [FrankenPHP directives](https://frankenphp.dev/docs/config/#caddyfile-config), one per line | `import worker.Caddyfile` | | `MERCURE_TRANSPORT_URL` | the value passed to the `transport_url` directive | `bolt:///data/mercure.db` | | `MERCURE_PUBLISHER_JWT_KEY` | the JWT key to use for publishers | | | `MERCURE_PUBLISHER_JWT_ALG` | the JWT algorithm to use for publishers | `HS256` | @@ -67,6 +90,10 @@ You can also customize the `Caddyfile` by using the following environment variab | `MERCURE_SUBSCRIBER_JWT_ALG` | the JWT algorithm to use for subscribers | `HS256` | | `MERCURE_EXTRA_DIRECTIVES` | a list of extra [Mercure directives](https://mercure.rocks/docs/hub/config), one per line | | -### Example of server name customize: + + +### Customizing the Server Name - SERVER_NAME="app.localhost" docker compose up --wait +```console +SERVER_NAME="app.localhost" docker compose up --wait +``` diff --git a/docs/production.md b/docs/production.md index af890f2b2..f1cbd824f 100644 --- a/docs/production.md +++ b/docs/production.md @@ -1,24 +1,38 @@ # Deploying in Production -Symfony Docker provides Docker images, and a Docker Compose definition optimized for production usage. -In this tutorial, we will learn how to deploy our Symfony application on a single server using Docker Compose. +Symfony Docker provides Docker images, and a Docker Compose definition optimized +for production usage. +In this tutorial, we will learn how to deploy our Symfony application +on a single server using Docker Compose. ## Preparing a Server To deploy your application in production, you need a server. -In this tutorial, we will use a virtual machine provided by DigitalOcean, but any Linux server can work. -If you already have a Linux server with Docker Compose installed, you can skip straight to [the next section](#configuring-a-domain-name). - -Otherwise, use [this affiliate link](https://m.do.co/c/5d8aabe3ab80) to get $100 of free credit, create an account, then click on "Create a Droplet". -Then, click on the "Marketplace" tab under the "Choose an image" section and search for the app named "Docker". -This will provision an Ubuntu server with the latest versions of Docker and Docker Compose already installed! - -For test purposes, the cheapest plans will be enough, even though you might want at least 2GB of RAM to execute Docker Compose for the first time. For real production usage, you'll probably want to pick a plan in the "general purpose" section to fit your needs. +In this tutorial, we will use a virtual machine provided by DigitalOcean, +but any Linux server can work. + +If you already have a Linux server with Docker Compose installed, +you can skip straight to [the next section](#configuring-a-domain-name). + +Otherwise, use [this affiliate link](https://m.do.co/c/5d8aabe3ab80) +to get $100 of free credit, create an account, then click on "Create a Droplet". +Then, click on the "Marketplace" tab under the "Choose an image" section +and search for the app named "Docker". +This will provision an Ubuntu server with the latest versions of Docker and +Docker Compose already installed! + +For test purposes, the cheapest plans will be enough, +even though you might want at least 2GB of RAM to execute Docker Compose +for the first time. +For real production usage, +you'll probably want to pick a plan in the "general purpose" section +to fit your needs. ![Deploying a Symfony app on DigitalOcean with Docker Compose](digitalocean-droplet.png) You can keep the defaults for other settings, or tweak them according to your needs. -Don't forget to add your SSH key or create a password then press the "Finalize and create" button. +Don't forget to add your SSH key or create a password +then press the "Finalize and create" button. Then, wait a few seconds while your Droplet is provisioning. When your Droplet is ready, use SSH to connect: @@ -32,7 +46,8 @@ ssh root@ In most cases, you'll want to associate a domain name with your site. If you don't own a domain name yet, you'll have to buy one through a registrar. -Then create a DNS record of type `A` for your domain name pointing to the IP address of your server: +Then create a DNS record of type `A` for your domain name pointing +to the IP address of your server: ```dns your-domain-name.example.com. IN A 207.154.233.113 @@ -42,12 +57,16 @@ Example with the DigitalOcean Domains service ("Networking" > "Domains"): ![Configuring DNS on DigitalOcean](digitalocean-dns.png) -> [!NOTE] -> Let's Encrypt, the service used by default by Symfony Docker to automatically generate a TLS certificate doesn't support using bare IP addresses. Using a domain name is mandatory to use Let's Encrypt. +> [!NOTE] +> +> Let's Encrypt, the service used by default by Symfony Docker to automatically +> generate a TLS certificate doesn't support using bare IP addresses. +> Using a domain name is mandatory to use Let's Encrypt. ## Deploying -Copy your project on the server using `git clone`, `scp`, or any other tool that may fit your need. +Copy your project on the server using `git clone`, `scp`, or any other tool +that may fit your need. If you use GitHub, you may want to use [a deploy key](https://docs.github.com/en/free-pro-team@latest/developers/overview/managing-deploy-keys#deploy-keys). Deploy keys are also [supported by GitLab](https://docs.gitlab.com/ee/user/project/deploy_keys/). @@ -57,7 +76,8 @@ Example with Git: git clone git@github.com:/.git ``` -Go into the directory containing your project (``), and start the app in production mode: +Go into the directory containing your project (``), +and start the app in production mode: ```console # Build fresh production image @@ -70,20 +90,32 @@ CADDY_MERCURE_JWT_SECRET=ChangeThisMercureHubJWTSecretKey \ docker compose -f compose.yaml -f compose.prod.yaml up --wait ``` -Be sure to replace `your-domain-name.example.com` with your actual domain name and to set the values of `APP_SECRET`, `CADDY_MERCURE_JWT_SECRET` to cryptographically secure random values. +Be sure to replace `your-domain-name.example.com` with your actual domain name +and to set the values of `APP_SECRET`, `CADDY_MERCURE_JWT_SECRET` +to cryptographically secure random values. -Your server is up and running, and a HTTPS certificate has been automatically generated for you. +Your server is up and running, and a HTTPS certificate has been automatically +generated for you. Go to `https://your-domain-name.example.com` and enjoy! > [!NOTE] -> The worker mode of FrankenPHP is enabled by default in prod. To disable it, add the env var FRANKENPHP_CONFIG as empty to the compose.prod.yaml file. +> +> The worker mode of FrankenPHP is enabled by default in prod. +> To disable it, add the env var `FRANKENPHP_CONFIG` as empty +> to the `compose.prod.yaml` file. + + > [!CAUTION] -> Docker can have a cache layer, make sure you have the right build for each deployment or rebuild your project with --no-cache option to avoid cache issue. +> +> Docker can have a cache layer, make sure you have the right build +> for each deployment or rebuild your project with `--no-cache` option +> to avoid cache issue. ## Disabling HTTPS -Alternatively, if you don't want to expose an HTTPS server but only an HTTP one, run the following command: +Alternatively, if you don't want to expose an HTTPS server but only an HTTP one, +run the following command: ```console SERVER_NAME=:80 \ @@ -96,7 +128,9 @@ docker compose -f compose.yaml -f compose.prod.yaml up --wait If you want to deploy your app on a cluster of machines, you can use [Docker Swarm](https://docs.docker.com/engine/swarm/stack-deploy/), which is compatible with the provided Compose files. -To deploy on Kubernetes, take a look at [the Helm chart provided with API Platform](https://api-platform.com/docs/deployment/kubernetes/), which can be easily adapted for use with Symfony Docker. +To deploy on Kubernetes, take a look +at [the Helm chart provided with API Platform](https://api-platform.com/docs/deployment/kubernetes/), +which can be easily adapted for use with Symfony Docker. ## Passing local environment variables to containers @@ -107,8 +141,8 @@ If you want to pass them to your containers, you can use the [`env_file` attribu # compose.prod.yml services: - php: - env_file: - - .env.prod.local - # ... + php: + env_file: + - .env.prod.local + # ... ``` diff --git a/docs/tls.md b/docs/tls.md index 89e2a4bec..0e7d88f50 100644 --- a/docs/tls.md +++ b/docs/tls.md @@ -2,50 +2,84 @@ ## Trusting the Authority -With a standard installation, the authority used to sign certificates generated in the Caddy container is not trusted by your local machine. -You must add the authority to the trust store of the host : +With a standard installation, the authority used to sign certificates +generated in the Caddy container is not trusted by your local machine. +You must add the authority to the trust store of the host. + + + +### Linux + +```console +docker cp $(docker compose ps -q php):/data/caddy/pki/authorities/local/root.crt /usr/local/share/ca-certificates/root.crt && sudo update-ca-certificates ``` -# Mac -$ docker cp $(docker compose ps -q php):/data/caddy/pki/authorities/local/root.crt /tmp/root.crt && sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /tmp/root.crt -# Linux -$ docker cp $(docker compose ps -q php):/data/caddy/pki/authorities/local/root.crt /usr/local/share/ca-certificates/root.crt && sudo update-ca-certificates -# Windows -$ docker compose cp php:/data/caddy/pki/authorities/local/root.crt %TEMP%/root.crt && certutil -addstore -f "ROOT" %TEMP%/root.crt + +### Mac + +```console +docker cp $(docker compose ps -q php):/data/caddy/pki/authorities/local/root.crt /tmp/root.crt && sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /tmp/root.crt ``` +### Windows + +```console +docker compose cp php:/data/caddy/pki/authorities/local/root.crt %TEMP%/root.crt && certutil -addstore -f "ROOT" %TEMP%/root.crt +``` + + + ## Using Custom TLS Certificates -By default, Caddy will automatically generate TLS certificates using Let's Encrypt or ZeroSSL. +By default, Caddy will automatically generate TLS certificates using Let's Encrypt +or ZeroSSL. But sometimes you may prefer using custom certificates. -For instance, to use self-signed certificates created with [mkcert](https://github.com/FiloSottile/mkcert) do as follows: +For instance, to use self-signed certificates created with [mkcert](https://github.com/FiloSottile/mkcert) +do as follows: 1. Locally install `mkcert` 2. Create the folder storing the certs: - `mkdir -p frankenphp/certs` + + ```console + mkdir -p frankenphp/certs + ``` + 3. Generate the certificates for your local host (example: "server-name.localhost"): - `mkcert -cert-file frankenphp/certs/tls.pem -key-file frankenphp/certs/tls.key "server-name.localhost"` -4. Add these lines to the `./compose.override.yaml` file about `CADDY_SERVER_EXTRA_DIRECTIVES` environment and volume for the `php` service : - ```diff + + + + ```console + mkcert -cert-file frankenphp/certs/tls.pem -key-file frankenphp/certs/tls.key "server-name.localhost" + ``` + + + +4. Add these lines to the `./compose.override.yaml` file about `CADDY_SERVER_EXTRA_DIRECTIVES` + environment and volume for the `php` service: + + ```diff php: environment: - + CADDY_SERVER_EXTRA_DIRECTIVES: "tls /etc/caddy/certs/tls.pem /etc/caddy/certs/tls.key" + + CADDY_SERVER_EXTRA_DIRECTIVES: "tls /etc/caddy/certs/tls.pem /etc/caddy/certs/tls.key" # ... volumes: - + - ./frankenphp/certs:/etc/caddy/certs:ro + + - ./frankenphp/certs:/etc/caddy/certs:ro # ... - ``` + ``` + 5. Restart your `php` service ## Disabling HTTPS for Local Development -To disable HTTPS, configure your environment to use HTTP by setting the following variables and starting the project with this command: +To disable HTTPS, configure your environment to use HTTP by setting the following +variables and starting the project with this command: -```bash +```console SERVER_NAME=http://localhost \ MERCURE_PUBLIC_URL=http://localhost/.well-known/mercure \ docker compose up --wait ``` -Ensure your application is accessible over HTTP by visiting `http://localhost` in your web browser. +Ensure your application is accessible over HTTP by visiting `http://localhost` +in your web browser. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 5832c8f42..d2fde1f43 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -2,45 +2,59 @@ ## Editing Permissions on Linux -If you work on linux and cannot edit some of the project files right after the first installation, you can run `docker compose run --rm php chown -R $(id -u):$(id -g) .` to set yourself as owner of the project files that were created by the docker container. +If you work on Linux and cannot edit some of the project files right after +the first installation, you can run the following command +to set yourself as owner of the project files that were created by the Docker container: + +```console +docker compose run --rm php chown -R $(id -u):$(id -g) . +``` ## TLS/HTTPS Issues See more in the [TLS section](tls.md) -## Production issues +## Production Issues -### How to properly build fresh images for production use +### How To Properly Build Fresh Images for Production Use -Remember that, by default, if you run `docker compose up --wait`, only the files `compose.yaml` and `compose.override.yaml` will be used. -See https://docs.docker.com/compose/intro/compose-application-model and https://docs.docker.com/compose/how-tos/multiple-compose-files/merge. +Remember that, by default, if you run `docker compose up --wait`, +only the files `compose.yaml` and `compose.override.yaml` will be used. +See ["How Compose works"](https://docs.docker.com/compose/intro/compose-application-model) +and ["Merge Compose files"](https://docs.docker.com/compose/how-tos/multiple-compose-files/merge). -If you need to build images for production environment, you have to use the following command: +If you need to build images for production environment, you have to use the following +command: ```console docker compose -f compose.yaml -f compose.prod.yaml build --pull --no-cache ``` -### Why application outputs `phpinfo()` +### Why Application Outputs `phpinfo()`? -Both dev and prod images have the same image tag (`<...>app-php:latest`). This can cause confusion when working with images. -It is important to make sure that your image is the appropriate one for the current environment. +Both dev and prod images have the same image tag (`<...>app-php:latest`). +This can cause confusion when working with images. +It is important to make sure that your image is the appropriate one +for the current environment. If you are not careful about this, and try to run your production container(s) with `docker compose -f compose.yaml -f compose.prod.yaml up --wait` -without the right build process beforehand, your application **will still launch**, but will be displaying an output of `phpinfo()` (or possibly even a HTTP 500 error page). +without the right build process beforehand, your application **will still launch**, +but will be displaying an output of `phpinfo()` +(or possibly even a HTTP 500 error page). See details below. -
+#### Output of a basic build process -Output of a basic build process +In the case of a dev image, you need the `compose.yaml` and +`compose.override.yaml` files, which are the default files for Docker Compose. -In the case of a dev image, you need the `compose.yaml` and `compose.override.yaml` files. Which are the default files for Docker Compose. -This means that running `docker compose ` or `docker compose -f compose.yaml -f compose.override.yaml ` is the same thing. +This means that running `docker compose ` or +`docker compose -f compose.yaml -f compose.override.yaml ` is the same thing. -And in doing so, images `frankenphp_base` and `frankenphp_dev` are built. And not `frankenphp_prod`. -Which is good enough for dev purposes. +In doing so, images `frankenphp_base` and `frankenphp_dev` are built, +but not `frankenphp_prod`, which is good enough for dev purposes. Then, you can start your dev container(s) by running: @@ -48,26 +62,26 @@ Then, you can start your dev container(s) by running: docker compose up --wait ``` +#### Output expected for the production build process -
+To build the production image, you have to specify the `compose.yaml` and +`compose.prod.yaml` files. -
+This means you have to run the following command in order to build your image: -
- -Output expected for the production build process +```console +docker compose -f compose.yaml -f compose.prod.yaml build --pull --no-cache +``` -To build the production image, you have to specify the `compose.yaml` and `compose.prod.yaml` files. -This means you have to run: `docker compose -f compose.yaml -f compose.prod.yaml build --pull --no-cache` in order to build your image -(careful: the order of `-f` arguments is important). +> [!WARINING] +> +> The order of `-f` arguments matters. -That way, you will see that `frankenphp_base` and `frankenphp_prod` are built this time, which is what you will need for production purposes. +That way, you will see that `frankenphp_base` and `frankenphp_prod` are built, +which is what you will need for production purposes. You can finally start your prod container(s) by running: ```console docker compose -f compose.yaml -f compose.prod.yaml up --wait ``` - -
- diff --git a/docs/updating.md b/docs/updating.md index f406d56c2..ed328fb49 100644 --- a/docs/updating.md +++ b/docs/updating.md @@ -1,15 +1,19 @@ # Updating Your Project -To import the changes made to the *Symfony Docker* template into your project, we recommend using -[*template-sync*](https://github.com/coopTilleuls/template-sync): +To import the changes made to the _Symfony Docker_ template into your project, +we recommend using [_template-sync_](https://github.com/coopTilleuls/template-sync): 1. Run the script to synchronize your project with the latest version of the skeleton: - ```console - curl -sSL https://raw.githubusercontent.com/coopTilleuls/template-sync/main/template-sync.sh | sh -s -- https://github.com/dunglas/symfony-docker - ``` + + + ```console + curl -sSL https://raw.githubusercontent.com/coopTilleuls/template-sync/main/template-sync.sh | sh -s -- https://github.com/dunglas/symfony-docker + ``` + + 2. Resolve conflicts, if any 3. Run `git cherry-pick --continue` -For more advanced options, refer to [the documentation of *template sync*](https://github.com/coopTilleuls/template-sync#template-sync). +For more advanced options, refer to [the documentation of _template sync_](https://github.com/coopTilleuls/template-sync#template-sync). diff --git a/docs/xdebug.md b/docs/xdebug.md index a10cdf0d2..362c5517d 100644 --- a/docs/xdebug.md +++ b/docs/xdebug.md @@ -3,78 +3,90 @@ The default development image is shipped with [Xdebug](https://xdebug.org/), a popular debugger and profiler for PHP. -Because it has a significant performance overhead, the step-by-step debugger is disabled by default. +Because it has a significant performance overhead, the step-by-step debugger +is disabled by default. It can be enabled by setting the `XDEBUG_MODE` environment variable to `debug`. On Linux and Mac: -``` +```console XDEBUG_MODE=debug docker compose up --wait ``` On Windows: -``` +```console set XDEBUG_MODE=debug&& docker compose up --wait&set XDEBUG_MODE= ``` -## Debugging with Xdebug and PHPStorm +## Debugging with Xdebug and PhpStorm First, [create a PHP debug remote server configuration](https://www.jetbrains.com/help/phpstorm/creating-a-php-debug-server-configuration.html): 1. In the `Settings/Preferences` dialog, go to `PHP | Servers` 2. Create a new server: - * Name: `symfony` (or whatever you want to use for the variable `PHP_IDE_CONFIG`) - * Host: `localhost` (or the one defined using the `SERVER_NAME` environment variable) - * Port: `443` - * Debugger: `Xdebug` - * Check `Use path mappings` - * Absolute path on the server: `/app` + - Name: `symfony` (or whatever you want to use for the variable `PHP_IDE_CONFIG`) + - Host: `localhost` (or the one defined using the `SERVER_NAME` environment variable) + - Port: `443` + - Debugger: `Xdebug` + - Check `Use path mappings` + - Absolute path on the server: `/app` You can now use the debugger! -1. In PHPStorm, open the `Run` menu and click on `Start Listening for PHP Debug Connections` -2. Add the `XDEBUG_SESSION=PHPSTORM` query parameter to the URL of the page you want to debug, or use [other available triggers](https://xdebug.org/docs/step_debug#activate_debugger) - - Alternatively, you can use [the **Xdebug extension**](https://xdebug.org/docs/step_debug#browser-extensions) for your preferred web browser. - -3. On command line, we might need to tell PHPStorm which [path mapping configuration](https://www.jetbrains.com/help/phpstorm/zero-configuration-debugging-cli.html#configure-path-mappings) should be used, set the value of the PHP_IDE_CONFIG environment variable to `serverName=symfony`, where `symfony` is the name of the debug server configured higher. - - Example: - - ```console - XDEBUG_SESSION=1 PHP_IDE_CONFIG="serverName=symfony" php bin/console ... - ``` - -## Debugging with Xdebug and VScode - -1. Install necessary [PHP extension for VScode](https://marketplace.visualstudio.com/items?itemName=DEVSENSE.phptools-vscode). -2. Add [debug configuration](https://code.visualstudio.com/docs/debugtest/debugging-configuration#_launch-configurations) into your `.vscode\launch.json` file. - - Example: - - ``` - { - "version": "0.2.0", - "configurations": [ - { - "name": "Listen for Xdebug", - "type": "php", - "request": "launch", - "port": 9003, - "pathMappings": { - "/app": "${workspaceFolder}" - } - } - ] - } - ``` - -3. Use [Run and Debug](https://code.visualstudio.com/docs/debugtest/debugging#_start-a-debugging-session) options and run `Listen for Xdebug` command to listen for upcomming connections with [the **Xdebug extension**](https://xdebug.org/docs/step_debug#browser-extensions) installed and active. +1. In PhpStorm, open the `Run` menu and click on `Start Listening for PHP Debug Connections` +2. Add the `XDEBUG_SESSION=PHPSTORM` query parameter to the URL of + the page you want to debug, or use [other available triggers](https://xdebug.org/docs/step_debug#activate_debugger) + + Alternatively, you can use [the **Xdebug extension**](https://xdebug.org/docs/step_debug#browser-extensions) + for your preferred web browser. + +3. On command line, we might need to tell PhpStorm which + [path mapping configuration](https://www.jetbrains.com/help/phpstorm/zero-configuration-debugging-cli.html#configure-path-mappings) + should be used, set the value of the PHP_IDE_CONFIG environment variable to + `serverName=symfony`, where `symfony` is the name of the debug server configured + higher. + + Example: + + ```console + XDEBUG_SESSION=1 PHP_IDE_CONFIG="serverName=symfony" php bin/console ... + ``` + +## Debugging with Xdebug and Visual Studio Code + +1. Install necessary [PHP extension for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=DEVSENSE.phptools-vscode). +2. Add [debug configuration](https://code.visualstudio.com/docs/debugtest/debugging-configuration#_launch-configurations) + into your `.vscode\launch.json` file. + + Example: + + ```json + { + "version": "0.2.0", + "configurations": [ + { + "name": "Listen for Xdebug", + "type": "php", + "request": "launch", + "port": 9003, + "pathMappings": { + "/app": "${workspaceFolder}" + } + } + ] + } + ``` + +3. Use [Run and Debug](https://code.visualstudio.com/docs/debugtest/debugging#_start-a-debugging-session) + options and run `Listen for Xdebug` command to listen for upcomming connections + with [the **Xdebug extension**](https://xdebug.org/docs/step_debug#browser-extensions) + installed and active. ## Troubleshooting -Inspect the installation with the following command. The Xdebug version should be displayed. +Inspect the installation with the following command. +The Xdebug version should be displayed. ```console $ docker compose exec php php --version diff --git a/frankenphp/docker-entrypoint.sh b/frankenphp/docker-entrypoint.sh index 82cb1ff58..b7a0abf4e 100755 --- a/frankenphp/docker-entrypoint.sh +++ b/frankenphp/docker-entrypoint.sh @@ -52,7 +52,7 @@ if [ "$1" = 'frankenphp' ] || [ "$1" = 'php' ] || [ "$1" = 'bin/console' ]; then echo 'The database is now ready and reachable' fi - if [ "$( find ./migrations -iname '*.php' -print -quit )" ]; then + if [ "$(find ./migrations -iname '*.php' -print -quit)" ]; then php bin/console doctrine:migrations:migrate --no-interaction --all-or-nothing fi fi