initial commit

This commit is contained in:
m0veax 2023-04-14 22:27:33 +02:00
commit 81f612c7d0
50 changed files with 3719 additions and 0 deletions

30
.dockerignore Normal file
View File

@ -0,0 +1,30 @@
**/*.log
**/*.md
**/*.php~
**/*.dist.php
**/*.dist
**/*.cache
**/._*
**/.dockerignore
**/.DS_Store
**/.git/
**/.gitattributes
**/.gitignore
**/.gitmodules
**/docker-compose.*.yaml
**/docker-compose.*.yml
**/docker-compose.yaml
**/docker-compose.yml
**/Dockerfile
**/Thumbs.db
.github/
docs/
public/bundles/
tests/
var/
vendor/
.editorconfig
.env.*.local
.env.local
.env.local.php
.env.test

72
.editorconfig Normal file
View File

@ -0,0 +1,72 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
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_style = space
indent_size = 2
[*.json]
indent_style = space
indent_size = 2
[*.md]
trim_trailing_whitespace = false
[*.php]
indent_style = space
indent_size = 4
[*.sh]
indent_style = tab
indent_size = 4
[*.xml{,.dist}]
indent_style = space
indent_size = 4
[*.{yaml,yml}]
indent_style = space
indent_size = 4
trim_trailing_whitespace = false
[.github/workflows/*.yml]
indent_style = space
indent_size = 2
[.gitmodules]
indent_style = tab
indent_size = 4
[.php_cs{,.dist}]
indent_style = space
indent_size = 4
[.travis.yml]
indent_style = space
indent_size = 2
[composer.json]
indent_style = space
indent_size = 4
[docker-compose{,.*}.{yaml,yml}]
indent_style = space
indent_size = 2
[Dockerfile]
indent_style = tab
indent_size = 4

20
.env Normal file
View File

@ -0,0 +1,20 @@
# In all environments, the following files are loaded if they exist,
# the latter taking precedence over the former:
#
# * .env contains default values for the environment variables needed by the app
# * .env.local uncommitted file with local overrides
# * .env.$APP_ENV committed environment-specific defaults
# * .env.$APP_ENV.local uncommitted environment-specific overrides
#
# Real environment variables win over .env files.
#
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
# https://symfony.com/doc/current/configuration/secrets.html
#
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=787ada016f98349a29beefa84d4c2a8b
###< symfony/framework-bundle ###

16
.gitattributes vendored Normal file
View File

@ -0,0 +1,16 @@
* text=auto eol=lf
*.conf text eol=lf
*.html text eol=lf
*.ini text eol=lf
*.js text eol=lf
*.json text eol=lf
*.md text eol=lf
*.php text eol=lf
*.sh text eol=lf
*.yaml text eol=lf
*.yml text eol=lf
bin/console text eol=lf
*.ico binary
*.png binary

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
github: [dunglas]

42
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,42 @@
name: CI
on:
push:
pull_request:
jobs:
lint:
name: Docker Lint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Lint Dockerfile
uses: hadolint/hadolint-action@master
with:
dockerfile: Dockerfile
ignore: DL3007,DL3018 # Ignore using latest on mlocati/php-extension-installer & version in apk add
build:
name: Docker build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Pull images
run: docker compose pull
- name: Start services
run: docker compose up --build -d
- name: Wait for services
run: |
while status="$(docker inspect --format="{{if .Config.Healthcheck}}{{print .State.Health.Status}}{{end}}" "$(docker compose ps -q php)")"; do
case $status in
starting) sleep 1;;
healthy) exit 0;;
unhealthy) exit 1;;
esac
done
exit 1
- name: Check HTTP reachability
run: curl http://localhost
- name: Check HTTPS reachability
run: curl -k https://localhost

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
###> symfony/framework-bundle ###
/.env.local
/.env.local.php
/.env.*.local
/config/secrets/prod/prod.decrypt.private.php
/public/bundles/
/var/
/vendor/
###< symfony/framework-bundle ###

8
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/wireweb.iml" filepath="$PROJECT_DIR$/.idea/wireweb.iml" />
</modules>
</component>
</project>

19
.idea/php.xml generated Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MessDetectorOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCSFixerOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCodeSnifferOptionsConfiguration">
<option name="highlightLevel" value="WARNING" />
<option name="transferred" value="true" />
</component>
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>

8
.idea/wireweb.iml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

130
Dockerfile Normal file
View File

@ -0,0 +1,130 @@
#syntax=docker/dockerfile:1.4
# The different stages of this Dockerfile are meant to be built into separate images
# https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage
# https://docs.docker.com/compose/compose-file/#target
# Builder images
FROM composer/composer:2-bin AS composer
FROM mlocati/php-extension-installer:latest AS php_extension_installer
# Build Caddy with the Mercure and Vulcain modules
FROM caddy:2.6-builder-alpine AS app_caddy_builder
RUN xcaddy build \
--with github.com/dunglas/mercure \
--with github.com/dunglas/mercure/caddy \
--with github.com/dunglas/vulcain \
--with github.com/dunglas/vulcain/caddy
# Prod image
FROM php:8.2-fpm-alpine AS app_php
# Allow to use development versions of Symfony
ARG STABILITY="stable"
ENV STABILITY ${STABILITY}
# Allow to select Symfony version
ARG SYMFONY_VERSION=""
ENV SYMFONY_VERSION ${SYMFONY_VERSION}
ENV APP_ENV=prod
WORKDIR /srv/app
# php extensions installer: https://github.com/mlocati/docker-php-extension-installer
COPY --from=php_extension_installer --link /usr/bin/install-php-extensions /usr/local/bin/
# persistent / runtime deps
RUN apk add --no-cache \
acl \
fcgi \
file \
gettext \
git \
;
RUN set -eux; \
install-php-extensions \
apcu \
intl \
opcache \
zip \
;
###> recipes ###
###< recipes ###
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
COPY --link docker/php/conf.d/app.ini $PHP_INI_DIR/conf.d/
COPY --link docker/php/conf.d/app.prod.ini $PHP_INI_DIR/conf.d/
COPY --link docker/php/php-fpm.d/zz-docker.conf /usr/local/etc/php-fpm.d/zz-docker.conf
RUN mkdir -p /var/run/php
COPY --link docker/php/docker-healthcheck.sh /usr/local/bin/docker-healthcheck
RUN chmod +x /usr/local/bin/docker-healthcheck
HEALTHCHECK --interval=10s --timeout=3s --retries=3 CMD ["docker-healthcheck"]
COPY --link docker/php/docker-entrypoint.sh /usr/local/bin/docker-entrypoint
RUN chmod +x /usr/local/bin/docker-entrypoint
ENTRYPOINT ["docker-entrypoint"]
CMD ["php-fpm"]
# https://getcomposer.org/doc/03-cli.md#composer-allow-superuser
ENV COMPOSER_ALLOW_SUPERUSER=1
ENV PATH="${PATH}:/root/.composer/vendor/bin"
COPY --from=composer --link /composer /usr/bin/composer
# prevent the reinstallation of vendors at every changes in the source code
COPY --link composer.* symfony.* ./
RUN set -eux; \
if [ -f composer.json ]; then \
composer install --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress; \
composer clear-cache; \
fi
# copy sources
COPY --link . ./
RUN rm -Rf docker/
RUN set -eux; \
mkdir -p var/cache var/log; \
if [ -f composer.json ]; then \
composer dump-autoload --classmap-authoritative --no-dev; \
composer dump-env prod; \
composer run-script --no-dev post-install-cmd; \
chmod +x bin/console; sync; \
fi
# Dev image
FROM app_php AS app_php_dev
ENV APP_ENV=dev XDEBUG_MODE=off
VOLUME /srv/app/var/
RUN rm "$PHP_INI_DIR/conf.d/app.prod.ini"; \
mv "$PHP_INI_DIR/php.ini" "$PHP_INI_DIR/php.ini-production"; \
mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
COPY --link docker/php/conf.d/app.dev.ini $PHP_INI_DIR/conf.d/
RUN set -eux; \
install-php-extensions \
xdebug \
;
RUN rm -f .env.local.php
# Caddy image
FROM caddy:2.6-alpine AS app_caddy
WORKDIR /srv/app
COPY --from=app_caddy_builder --link /usr/bin/caddy /usr/bin/caddy
COPY --from=app_php --link /srv/app/public public/
COPY --link docker/caddy/Caddyfile /etc/caddy/Caddyfile

19
LICENSE Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

46
README.md Normal file
View File

@ -0,0 +1,46 @@
# Symfony Docker
A [Docker](https://www.docker.com/)-based installer and runtime for the [Symfony](https://symfony.com) web framework, with full [HTTP/2](https://symfony.com/doc/current/weblink.html), HTTP/3 and HTTPS support.
![CI](https://github.com/dunglas/symfony-docker/workflows/CI/badge.svg)
## Getting Started
1. If not already done, [install Docker Compose](https://docs.docker.com/compose/install/) (v2.10+)
2. Run `docker compose build --pull --no-cache` to build fresh images
3. Run `docker compose up` (the logs will be displayed in the current shell)
4. Open `https://localhost` in your favorite web browser and [accept the auto-generated TLS certificate](https://stackoverflow.com/a/15076602/1352334)
5. Run `docker compose down --remove-orphans` to stop the Docker containers.
## Features
* Production, development and CI ready
* [Installation of extra Docker Compose services](docs/extra-services.md) with Symfony Flex
* Automatic HTTPS (in dev and in prod!)
* HTTP/2, HTTP/3 and [Preload](https://symfony.com/doc/current/web_link.html) support
* Built-in [Mercure](https://symfony.com/doc/current/mercure.html) hub
* [Vulcain](https://vulcain.rocks) support
* Native [XDebug](docs/xdebug.md) integration
* Just 2 services (PHP FPM and Caddy server)
* Super-readable configuration
**Enjoy!**
## Docs
1. [Build options](docs/build.md)
2. [Using Symfony Docker with an existing project](docs/existing-project.md)
3. [Support for extra services](docs/extra-services.md)
4. [Deploying in production](docs/production.md)
5. [Debugging with Xdebug](docs/xdebug.md)
6. [TLS Certificates](docs/tls.md)
7. [Using a Makefile](docs/makefile.md)
8. [Troubleshooting](docs/troubleshooting.md)
## License
Symfony Docker is available under the MIT License.
## Credits
Created by [Kévin Dunglas](https://dunglas.fr), co-maintained by [Maxime Helias](https://twitter.com/maxhelias) and sponsored by [Les-Tilleuls.coop](https://les-tilleuls.coop).

17
bin/console Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env php
<?php
use App\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;
if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) {
throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".');
}
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
return new Application($kernel);
};

68
composer.json Normal file
View File

@ -0,0 +1,68 @@
{
"name": "symfony/skeleton",
"type": "project",
"license": "MIT",
"description": "A minimal Symfony project recommended to create bare bones applications",
"minimum-stability": "stable",
"prefer-stable": true,
"require": {
"php": ">=8.2.5",
"ext-ctype": "*",
"ext-iconv": "*",
"symfony/console": "6.2.*",
"symfony/dotenv": "6.2.*",
"symfony/flex": "^2",
"symfony/framework-bundle": "6.2.*",
"symfony/runtime": "6.2.*",
"symfony/yaml": "6.2.*"
},
"config": {
"allow-plugins": {
"php-http/discovery": true,
"symfony/flex": true,
"symfony/runtime": true
},
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
},
"replace": {
"symfony/polyfill-ctype": "*",
"symfony/polyfill-iconv": "*",
"symfony/polyfill-php72": "*",
"symfony/polyfill-php73": "*",
"symfony/polyfill-php74": "*",
"symfony/polyfill-php80": "*",
"symfony/polyfill-php81": "*"
},
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
},
"post-install-cmd": [
"@auto-scripts"
],
"post-update-cmd": [
"@auto-scripts"
]
},
"conflict": {
"symfony/symfony": "*"
},
"extra": {
"symfony": {
"allow-contrib": false,
"require": "6.2.*",
"docker": true
}
}
}

2388
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

5
config/bundles.php Normal file
View File

@ -0,0 +1,5 @@
<?php
return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
];

View File

@ -0,0 +1,19 @@
framework:
cache:
# Unique name of your app: used to compute stable namespaces for cache keys.
#prefix_seed: your_vendor_name/app_name
# The "app" cache stores to the filesystem by default.
# The data in this cache should persist between deploys.
# Other options include:
# Redis
#app: cache.adapter.redis
#default_redis_provider: redis://localhost
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
#app: cache.adapter.apcu
# Namespaced pools use the above "app" backend by default
#pools:
#my.dedicated.cache: null

View File

@ -0,0 +1,25 @@
# see https://symfony.com/doc/current/reference/configuration/framework.html
framework:
secret: '%env(APP_SECRET)%'
#csrf_protection: true
http_method_override: false
handle_all_throwables: true
# Enables session support. Note that the session will ONLY be started if you read or write from it.
# Remove or comment this section to explicitly disable session support.
session:
handler_id: null
cookie_secure: auto
cookie_samesite: lax
storage_factory_id: session.storage.factory.native
#esi: true
#fragments: true
php_errors:
log: true
when@test:
framework:
test: true
session:
storage_factory_id: session.storage.factory.mock_file

View File

@ -0,0 +1,12 @@
framework:
router:
utf8: true
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
#default_uri: http://localhost
when@prod:
framework:
router:
strict_requirements: null

5
config/preload.php Normal file
View File

@ -0,0 +1,5 @@
<?php
if (file_exists(dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php')) {
require dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php';
}

5
config/routes.yaml Normal file
View File

@ -0,0 +1,5 @@
controllers:
resource:
path: ../src/Controller/
namespace: App\Controller
type: attribute

View File

@ -0,0 +1,4 @@
when@dev:
_errors:
resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
prefix: /_error

24
config/services.yaml Normal file
View File

@ -0,0 +1,24 @@
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters:
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones

View File

@ -0,0 +1,28 @@
version: "3.4"
# Development environment override
services:
php:
build:
target: app_php_dev
volumes:
- ./:/srv/app
- ./docker/php/conf.d/app.dev.ini:/usr/local/etc/php/conf.d/app.dev.ini:ro
# If you develop on Mac or Windows you can remove the vendor/ directory
# from the bind-mount for better performance by enabling the next line:
#- /srv/app/vendor
environment:
# See https://xdebug.org/docs/all_settings#mode
XDEBUG_MODE: "${XDEBUG_MODE:-off}"
extra_hosts:
# Ensure that host.docker.internal is correctly defined on Linux
- host.docker.internal:host-gateway
caddy:
command: ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile", "--watch"]
volumes:
- ./public:/srv/app/public:ro
- ./docker/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
###> symfony/mercure-bundle ###
###< symfony/mercure-bundle ###

13
docker-compose.prod.yml Normal file
View File

@ -0,0 +1,13 @@
version: "3.4"
# Production environment override
services:
php:
environment:
APP_SECRET: ${APP_SECRET}
MERCURE_JWT_SECRET: ${CADDY_MERCURE_JWT_SECRET}
caddy:
environment:
MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET}
MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET}

65
docker-compose.yml Normal file
View File

@ -0,0 +1,65 @@
version: "3.4"
services:
php:
build:
context: .
target: app_php
args:
SYMFONY_VERSION: ${SYMFONY_VERSION:-}
STABILITY: ${STABILITY:-stable}
restart: unless-stopped
volumes:
- php_socket:/var/run/php
healthcheck:
interval: 10s
timeout: 3s
retries: 3
start_period: 30s
environment:
# Run "composer require symfony/orm-pack" to install and configure Doctrine ORM
DATABASE_URL: postgresql://${POSTGRES_USER:-app}:${POSTGRES_PASSWORD:-!ChangeMe!}@database:5432/${POSTGRES_DB:-app}?serverVersion=${POSTGRES_VERSION:-14}&charset=${POSTGRES_CHARSET:-utf8}
# Run "composer require symfony/mercure-bundle" to install and configure the Mercure integration
MERCURE_URL: ${CADDY_MERCURE_URL:-http://caddy/.well-known/mercure}
MERCURE_PUBLIC_URL: https://${SERVER_NAME:-localhost}/.well-known/mercure
MERCURE_JWT_SECRET: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!}
caddy:
build:
context: .
target: app_caddy
depends_on:
- php
environment:
SERVER_NAME: ${SERVER_NAME:-localhost, caddy:80}
MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!}
MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!}
restart: unless-stopped
volumes:
- php_socket:/var/run/php
- caddy_data:/data
- caddy_config:/config
ports:
# HTTP
- target: 80
published: ${HTTP_PORT:-80}
protocol: tcp
# HTTPS
- target: 443
published: ${HTTPS_PORT:-443}
protocol: tcp
# HTTP/3
- target: 443
published: ${HTTP3_PORT:-443}
protocol: udp
# Mercure is installed as a Caddy module, prevent the Flex recipe from installing another service
###> symfony/mercure-bundle ###
###< symfony/mercure-bundle ###
volumes:
php_socket:
caddy_data:
caddy_config:
###> symfony/mercure-bundle ###
###< symfony/mercure-bundle ###

32
docker/caddy/Caddyfile Normal file
View File

@ -0,0 +1,32 @@
{
# Debug
{$CADDY_DEBUG}
}
{$SERVER_NAME}
{$CADDY_EXTRA_CONFIG}
log
route {
root * /srv/app/public
mercure {
# Transport to use (default to Bolt)
transport_url {$MERCURE_TRANSPORT_URL:bolt:///data/mercure.db}
# Publisher JWT key
publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
# Subscriber JWT key
subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
# Allow anonymous subscribers (double-check that it's what you want)
anonymous
# Enable the subscription API (double-check that it's what you want)
subscriptions
# Extra directives
{$MERCURE_EXTRA_DIRECTIVES}
}
vulcain
php_fastcgi unix//var/run/php/php-fpm.sock
encode zstd gzip
file_server
}

View File

@ -0,0 +1,5 @@
; See https://docs.docker.com/desktop/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host
; See https://github.com/docker/for-linux/issues/264
; The `client_host` below may optionally be replaced with `discover_client_host=yes`
; Add `start_with_request=yes` to start debug session on each request
xdebug.client_host = 'host.docker.internal'

13
docker/php/conf.d/app.ini Normal file
View File

@ -0,0 +1,13 @@
expose_php = 0
date.timezone = UTC
apc.enable_cli = 1
session.use_strict_mode = 1
zend.detect_unicode = 0
; https://symfony.com/doc/current/performance.html
realpath_cache_size = 4096K
realpath_cache_ttl = 600
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 20000
opcache.memory_consumption = 256
opcache.enable_file_override = 1

View File

@ -0,0 +1,2 @@
opcache.preload_user = www-data
opcache.preload = /srv/app/config/preload.php

68
docker/php/docker-entrypoint.sh Executable file
View File

@ -0,0 +1,68 @@
#!/bin/sh
set -e
# first arg is `-f` or `--some-option`
if [ "${1#-}" != "$1" ]; then
set -- php-fpm "$@"
fi
if [ "$1" = 'php-fpm' ] || [ "$1" = 'php' ] || [ "$1" = 'bin/console' ]; then
# Install the project the first time PHP is started
# After the installation, the following block can be deleted
if [ ! -f composer.json ]; then
CREATION=1
rm -Rf tmp/
composer create-project "symfony/skeleton $SYMFONY_VERSION" tmp --stability="$STABILITY" --prefer-dist --no-progress --no-interaction --no-install
cd tmp
composer require "php:>=$PHP_VERSION"
composer config --json extra.symfony.docker 'true'
cp -Rp . ..
cd -
rm -Rf tmp/
fi
if [ "$APP_ENV" != 'prod' ]; then
composer install --prefer-dist --no-progress --no-interaction
fi
if grep -q ^DATABASE_URL= .env; then
# After the installation, the following block can be deleted
if [ "$CREATION" = "1" ]; then
echo "To finish the installation please press Ctrl+C to stop Docker Compose and run: docker compose up --build"
sleep infinity
fi
echo "Waiting for db to be ready..."
ATTEMPTS_LEFT_TO_REACH_DATABASE=60
until [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ] || DATABASE_ERROR=$(bin/console dbal:run-sql "SELECT 1" 2>&1); do
if [ $? -eq 255 ]; then
# If the Doctrine command exits with 255, an unrecoverable error occurred
ATTEMPTS_LEFT_TO_REACH_DATABASE=0
break
fi
sleep 1
ATTEMPTS_LEFT_TO_REACH_DATABASE=$((ATTEMPTS_LEFT_TO_REACH_DATABASE - 1))
echo "Still waiting for db to be ready... Or maybe the db is not reachable. $ATTEMPTS_LEFT_TO_REACH_DATABASE attempts left"
done
if [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ]; then
echo "The database is not up or not reachable:"
echo "$DATABASE_ERROR"
exit 1
else
echo "The db is now ready and reachable"
fi
if [ "$( find ./migrations -iname '*.php' -print -quit )" ]; then
bin/console doctrine:migrations:migrate --no-interaction
fi
fi
setfacl -R -m u:www-data:rwX -m u:"$(whoami)":rwX var
setfacl -dR -m u:www-data:rwX -m u:"$(whoami)":rwX var
fi
exec docker-php-entrypoint "$@"

View File

@ -0,0 +1,8 @@
#!/bin/sh
set -e
if env -i REQUEST_METHOD=GET SCRIPT_NAME=/ping SCRIPT_FILENAME=/ping cgi-fcgi -bind -connect /var/run/php/php-fpm.sock; then
exit 0
fi
exit 1

View File

@ -0,0 +1,8 @@
[global]
daemonize = no
process_control_timeout = 20
[www]
listen = /var/run/php/php-fpm.sock
listen.mode = 0666
ping.path = /ping

49
docs/build.md Normal file
View File

@ -0,0 +1,49 @@
# Build Options
## Selecting a Specific Symfony Version
Use the `SYMFONY_VERSION` environment variable to select a specific Symfony version.
For instance, use the following command to install Symfony 5.4:
On Linux:
SYMFONY_VERSION=5.4.* docker compose up --build
On Windows:
set SYMFONY_VERSION=5.4.*&& docker compose up --build&set SYMFONY_VERSION=
## Installing Development Versions of Symfony
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 --build
On Windows:
set STABILITY=dev&& docker compose up --build&set STABILITY=
## Customizing the Server Name
Use the `SERVER_NAME` environment variable to define your custom server name(s).
SERVER_NAME="app.localhost, caddy:80" docker compose up --build
If you use Mercure, keep `caddy:80` in the list to allow the PHP container to request the caddy service.
*Tips: You can define your server name variable in your `.env` file to keep it at each up*
## Using custom HTTP ports
Use the environment variables `HTTP_PORT`, `HTTPS_PORT` and/or `HTTP3_PORT` to adjust the ports to your needs, e.g.
HTTP_PORT=8000 HTTPS_PORT=4443 HTTP3_PORT=4443 docker compose up --build
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.*

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

33
docs/existing-project.md Normal file
View File

@ -0,0 +1,33 @@
# Installing on an Existing Project
It's also possible to use Symfony Docker with existing projects!
First, [download this skeleton](https://github.com/dunglas/symfony-docker). If you clone the Git repository, be sure to remove the `.git` directory to prevent conflicts with the `.git` directory already in your existing project.
Then, copy the Docker-related files from the skeleton to your existing project:
cp -Rp symfony-docker/. my-existing-project/
Enable the Docker support of Symfony Flex:
composer config --json extra.symfony.docker 'true'
Re-execute the recipes to update the Docker-related files according to the packages you use
rm symfony.lock
composer symfony:sync-recipes --force --verbose
Double-check the changes, revert the changes that you don't want to keep:
git diff
...
Build the Docker images:
docker compose build --no-cache --pull
Start the project!
docker compose up -d
Browse `https://localhost`, your Docker configuration is ready!

12
docs/extra-services.md Normal file
View File

@ -0,0 +1,12 @@
# 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 `docker-compose.yml` 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 MailCatcher service
* `blackfireio/blackfire-symfony-meta`: install a Blackfire service

BIN
docs/gandi-dns.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

90
docs/makefile.md Normal file
View File

@ -0,0 +1,90 @@
# Makefile
Here is a Makefile template. It provides some shortcuts for the most common tasks.
To use it, create a new `Makefile` file at the root of your project. Copy/paste
the content in the template section. To view all the available commands, run `make`.
For example, in the [getting started section](/README.md#getting-started), the
`docker compose` commands could be replaced by:
1. Run `make build` to build fresh images
2. Run `make up` (detached mode without logs)
3. Run `make down` to stop the Docker containers
Of course, this template is basic for now. But, as your application is growing,
you will probably want to add some targets like running your tests as described
in [the Symfony book](https://symfony.com/doc/current/the-fast-track/en/17-tests.html#automating-your-workflow-with-a-makefile).
You can also find a more complete example in this [snippet](https://www.strangebuzz.com/en/snippets/the-perfect-makefile-for-symfony).
If you want to run make from within the `php` container, in the [Dockerfile](/Dockerfile),
add:
```diff
gettext \
git \
+make \
```
And rebuild the PHP image.
**PS**: If using Windows, you have to install [chocolatey.org](https://chocolatey.org/)
or use [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
```Makefile
# Executables (local)
DOCKER_COMP = docker compose
# Docker containers
PHP_CONT = $(DOCKER_COMP) exec php
# Executables
PHP = $(PHP_CONT) php
COMPOSER = $(PHP_CONT) composer
SYMFONY = $(PHP_CONT) bin/console
# Misc
.DEFAULT_GOAL = help
.PHONY : help build up start down logs sh composer vendor sf cc
## —— 🎵 🐳 The Symfony Docker Makefile 🐳 🎵 ——————————————————————————————————
help: ## Outputs this help screen
@grep -E '(^[a-zA-Z0-9\./_-]+:.*?##.*$$)|(^##)' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}{printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}' | sed -e 's/\[32m##/[33m/'
## —— Docker 🐳 ————————————————————————————————————————————————————————————————
build: ## Builds the Docker images
@$(DOCKER_COMP) build --pull --no-cache
up: ## Start the docker hub in detached mode (no logs)
@$(DOCKER_COMP) up --detach
start: build up ## Build and start the containers
down: ## Stop the docker hub
@$(DOCKER_COMP) down --remove-orphans
logs: ## Show live logs
@$(DOCKER_COMP) logs --tail=0 --follow
sh: ## Connect to the PHP FPM container
@$(PHP_CONT) sh
## —— Composer 🧙 ——————————————————————————————————————————————————————————————
composer: ## Run composer, pass the parameter "c=" to run a given command, example: make composer c='req symfony/orm-pack'
@$(eval c ?=)
@$(COMPOSER) $(c)
vendor: ## Install vendors according to the current composer.lock file
vendor: c=install --prefer-dist --no-dev --no-progress --no-scripts --no-interaction
vendor: composer
## —— Symfony 🎵 ———————————————————————————————————————————————————————————————
sf: ## List all Symfony commands or pass the parameter "c=" to run a given command, example: make sf c=about
@$(eval c ?=)
@$(SYMFONY) $(c)
cc: c=c:c ## Clear the cache
cc: sf
```

104
docs/production.md Normal file
View File

@ -0,0 +1,104 @@
# 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.
## 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!
To test, the cheapest plan will be enough, but for real production usage you'll probably want to pick a plan in the "general purpose" section that will 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 to 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:
```console
ssh root@<droplet-ip>
```
## Configuring a Domain Name
In most cases, you'll want to associate a domain name to your website.
If you don't own a domain name yet, you'll have to buy one through a registrar.
Use [this affiliate link](https://gandi.link/f/93650337) to redeem a 20% discount at Gandi.net.
Then create a DNS record of type `A` for your domain name pointing to the IP address of your server.
Example:
```dns
your-domain-name.example.com. IN A 207.154.233.113
````
Example in Gandi's UI:
![Creating a DNS record at Gandi.net](gandi-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.
## Deploying
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/).
Example with Git:
```console
git clone git@github.com:<username>/<project-name>.git
```
Go into the directory containing your project (`<project-name>`), and start the app in production mode:
```console
SERVER_NAME=your-domain-name.example.com \
APP_SECRET=ChangeMe \
CADDY_MERCURE_JWT_SECRET=ChangeThisMercureHubJWTSecretKey \
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
```
Be sure to replace `your-domain-name.example.com` by 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 Let's Encrypt HTTPS certificate has been automatically generated for you.
Go to `https://your-domain-name.example.com` and enjoy!
## Disabling HTTPS
Alternatively, if you don't want to expose an HTTPS server but only an HTTP one, run the following command:
```console
SERVER_NAME=:80 \
APP_SECRET=ChangeMe \
CADDY_MERCURE_JWT_SECRET=ChangeThisMercureHubJWTSecretKey \
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
```
## Deploying on Multiple Nodes
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.
## Configuring a Load Balancer or a Reverse Proxy
Since Caddy 2.5, XFF values of incoming requests will be ignored to prevent spoofing.
So if Caddy is not the first server being connected to by your clients (for example when a CDN is in front of Caddy), you may configure `trusted_proxies` with a list of IP ranges (CIDRs) from which incoming requests are trusted to have sent good values for these headers.
As a shortcut, `private_ranges` may be configured to trust all private IP ranges.
```diff
-php_fastcgi unix//var/run/php/php-fpm.sock
+php_fastcgi unix//var/run/php/php-fpm.sock {
+ trusted_proxies private_ranges
+}
```

38
docs/tls.md Normal file
View File

@ -0,0 +1,38 @@
# TLS Certificates
## 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 :
```
# Mac
$ docker cp $(docker compose ps -q caddy):/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 caddy):/data/caddy/pki/authorities/local/root.crt /usr/local/share/ca-certificates/root.crt && sudo update-ca-certificates
# Windows
$ docker compose cp caddy:/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.
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:
1. Locally install `mkcert`
2. Create the folder storing the certs:
`mkdir docker/caddy/certs -p`
3. Generate the certificates for your local host (example: "server-name.localhost"):
`mkcert -cert-file docker/caddy/certs/tls.pem -key-file docker/caddy/certs/tls.key "server-name.localhost"`
4. Add these lines to the `./docker-compose.override.yml` file about `CADDY_EXTRA_CONFIG` environment and volume for the `caddy` service :
```diff
caddy:
+ environment:
+ CADDY_EXTRA_CONFIG: "tls /etc/caddy/certs/tls.pem /etc/caddy/certs/tls.key"
volumes:
+ - ./docker/caddy/certs:/etc/caddy/certs:ro
- ./public:/srv/app/public:ro
```
5. Restart your `caddy` container

14
docs/troubleshooting.md Normal file
View File

@ -0,0 +1,14 @@
# Troubleshooting
## 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.
## HTTPs and Redirects
If Symfony is generating an internal redirect for an `https://` url, but the resulting url is `http://`, you have to uncomment the `TRUSTED_PROXIES` setting in your `.env` file.
For more details see the [Symfony internal redirect documentation](https://symfony.com/doc/current/routing.html#redirecting-to-urls-and-routes-directly-from-a-route).
## TLS/HTTPS Issues
See more in the [TLS section](tls.md)

58
docs/xdebug.md Normal file
View File

@ -0,0 +1,58 @@
# Using Xdebug
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.
It can be enabled by setting the `XDEBUG_MODE` environment variable to `debug`.
On Linux and Mac:
```
XDEBUG_MODE=debug docker compose up -d
```
On Windows:
```
set XDEBUG_MODE=debug&& docker compose up -d&set XDEBUG_MODE=
```
## 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: `/srv/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 ...
```
## Troubleshooting
Inspect the installation with the following command. The Xdebug version should be displayed.
```console
$ docker compose exec php php --version
PHP ...
with Xdebug v3.x.x ...
```

0
public/.gitignore vendored Normal file
View File

9
public/index.php Normal file
View File

@ -0,0 +1,9 @@
<?php
use App\Kernel;
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
};

0
src/Controller/.gitignore vendored Normal file
View File

11
src/Kernel.php Normal file
View File

@ -0,0 +1,11 @@
<?php
namespace App;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
class Kernel extends BaseKernel
{
use MicroKernelTrait;
}

58
symfony.lock Normal file
View File

@ -0,0 +1,58 @@
{
"symfony/console": {
"version": "6.2",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.3",
"ref": "da0c8be8157600ad34f10ff0c9cc91232522e047"
},
"files": [
"bin/console"
]
},
"symfony/flex": {
"version": "2.2",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "1.0",
"ref": "146251ae39e06a95be0fe3d13c807bcf3938b172"
},
"files": [
".env"
]
},
"symfony/framework-bundle": {
"version": "6.2",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "6.2",
"ref": "af47254c5e4cd543e6af3e4508298ffebbdaddd3"
},
"files": [
"config/packages/cache.yaml",
"config/packages/framework.yaml",
"config/preload.php",
"config/routes/framework.yaml",
"config/services.yaml",
"public/index.php",
"src/Controller/.gitignore",
"src/Kernel.php"
]
},
"symfony/routing": {
"version": "6.2",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "6.2",
"ref": "e0a11b4ccb8c9e70b574ff5ad3dfdcd41dec5aa6"
},
"files": [
"config/packages/routing.yaml",
"config/routes.yaml"
]
}
}