49 changed files with 5386 additions and 0 deletions
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
**/*.log |
||||
**/*.md |
||||
**/*.php~ |
||||
**/*.dist.php |
||||
**/*.dist |
||||
**/*.cache |
||||
**/._* |
||||
**/.dockerignore |
||||
**/.DS_Store |
||||
**/.git/ |
||||
**/.gitattributes |
||||
**/.gitignore |
||||
**/.gitmodules |
||||
**/compose.*.yaml |
||||
**/compose.*.yml |
||||
**/compose.yaml |
||||
**/compose.yml |
||||
**/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 |
||||
@ -0,0 +1,57 @@
@@ -0,0 +1,57 @@
|
||||
# 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_size = 2 |
||||
|
||||
[*.json] |
||||
indent_size = 2 |
||||
|
||||
[*.md] |
||||
trim_trailing_whitespace = false |
||||
|
||||
[*.sh] |
||||
indent_style = tab |
||||
|
||||
[*.xml.dist] |
||||
indent_style = space |
||||
indent_size = 4 |
||||
|
||||
[*.{yaml,yml}] |
||||
trim_trailing_whitespace = false |
||||
|
||||
[.github/workflows/*.yml] |
||||
indent_size = 2 |
||||
|
||||
[.gitmodules] |
||||
indent_style = tab |
||||
|
||||
[.php_cs.dist] |
||||
indent_style = space |
||||
indent_size = 4 |
||||
|
||||
[composer.json] |
||||
indent_size = 4 |
||||
|
||||
[{compose,docker-compose}.*.{yaml,yml}] |
||||
indent_size = 2 |
||||
|
||||
[*.*Dockerfile] |
||||
indent_style = tab |
||||
|
||||
[*.*Caddyfile] |
||||
indent_style = tab |
||||
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
# 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=9e287f1ad737386dde46d51e80487236 |
||||
###< symfony/framework-bundle ### |
||||
###> docker ### |
||||
SERVER_NAME=dn.localhost |
||||
CADDY_MERCURE_JWT_SECRET=!NotSoSecretMercureHubJWTSecretKey! |
||||
POSTGRES_DB=newsroom_db |
||||
POSTGRES_USER=dn_user |
||||
POSTGRES_PASSWORD=!uip0567$ |
||||
POSTGRES_VERSION=15 |
||||
POSTGRES_CHARSET=utf8 |
||||
###< docker ### |
||||
|
||||
###> doctrine/doctrine-bundle ### |
||||
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url |
||||
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml |
||||
DATABASE_URL="postgresql://dn_user:!uip0567$}@database:5432/newsroom_db?serverVersion=15&charset=utf8" |
||||
###< doctrine/doctrine-bundle ### |
||||
@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
|
||||
* 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 |
||||
composer.lock text eol=lf merge=ours |
||||
|
||||
*.ico binary |
||||
*.png binary |
||||
@ -0,0 +1,76 @@
@@ -0,0 +1,76 @@
|
||||
name: CI |
||||
|
||||
on: |
||||
push: |
||||
branches: |
||||
- main |
||||
pull_request: ~ |
||||
workflow_dispatch: ~ |
||||
|
||||
concurrency: |
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} |
||||
cancel-in-progress: true |
||||
|
||||
jobs: |
||||
tests: |
||||
name: Tests |
||||
runs-on: ubuntu-latest |
||||
steps: |
||||
- |
||||
name: Checkout |
||||
uses: actions/checkout@v4 |
||||
- |
||||
name: Set up Docker Buildx |
||||
uses: docker/setup-buildx-action@v3 |
||||
- |
||||
name: Build Docker images |
||||
uses: docker/bake-action@v4 |
||||
with: |
||||
pull: true |
||||
load: true |
||||
files: | |
||||
compose.yaml |
||||
compose.override.yaml |
||||
set: | |
||||
*.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 |
||||
run: docker compose up --wait --no-build |
||||
- |
||||
name: Check HTTP reachability |
||||
run: curl -v --fail-with-body http://localhost |
||||
- |
||||
name: Check HTTPS reachability |
||||
if: false # Remove this line when the homepage will be configured, or change the path to check |
||||
run: curl -vk --fail-with-body https://localhost |
||||
- |
||||
name: Check Mercure reachability |
||||
run: curl -vkI --fail-with-body https://localhost/.well-known/mercure?topic=test |
||||
- |
||||
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 |
||||
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 |
||||
if: false # Remove this line if PHPUnit is installed |
||||
run: docker compose exec -T php bin/phpunit |
||||
- |
||||
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 |
||||
runs-on: ubuntu-latest |
||||
steps: |
||||
- |
||||
name: Checkout |
||||
uses: actions/checkout@v4 |
||||
- |
||||
name: Lint Dockerfile |
||||
uses: hadolint/hadolint-action@v3.1.0 |
||||
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
/.idea/ |
||||
###> symfony/framework-bundle ### |
||||
/.env.local |
||||
/.env.local.php |
||||
/.env.*.local |
||||
/config/secrets/prod/prod.decrypt.private.php |
||||
/public/bundles/ |
||||
/var/ |
||||
/vendor/ |
||||
###< symfony/framework-bundle ### |
||||
@ -0,0 +1,97 @@
@@ -0,0 +1,97 @@
|
||||
#syntax=docker/dockerfile:1 |
||||
|
||||
# Versions |
||||
FROM dunglas/frankenphp:1-php8.3 AS frankenphp_upstream |
||||
|
||||
# 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 |
||||
|
||||
|
||||
# Base FrankenPHP image |
||||
FROM frankenphp_upstream AS frankenphp_base |
||||
|
||||
WORKDIR /app |
||||
|
||||
VOLUME /app/var/ |
||||
|
||||
# persistent / runtime deps |
||||
# hadolint ignore=DL3008 |
||||
RUN apt-get update && apt-get install -y --no-install-recommends \ |
||||
acl \ |
||||
file \ |
||||
gettext \ |
||||
git \ |
||||
&& rm -rf /var/lib/apt/lists/* |
||||
|
||||
RUN set -eux; \ |
||||
install-php-extensions \ |
||||
@composer \ |
||||
apcu \ |
||||
intl \ |
||||
opcache \ |
||||
zip \ |
||||
; |
||||
|
||||
# https://getcomposer.org/doc/03-cli.md#composer-allow-superuser |
||||
ENV COMPOSER_ALLOW_SUPERUSER=1 |
||||
|
||||
ENV PHP_INI_SCAN_DIR=":$PHP_INI_DIR/app.conf.d" |
||||
|
||||
###> recipes ### |
||||
###> doctrine/doctrine-bundle ### |
||||
RUN install-php-extensions pdo_pgsql |
||||
###< doctrine/doctrine-bundle ### |
||||
###< recipes ### |
||||
|
||||
COPY --link frankenphp/conf.d/10-app.ini $PHP_INI_DIR/app.conf.d/ |
||||
COPY --link --chmod=755 frankenphp/docker-entrypoint.sh /usr/local/bin/docker-entrypoint |
||||
COPY --link frankenphp/Caddyfile /etc/caddy/Caddyfile |
||||
|
||||
ENTRYPOINT ["docker-entrypoint"] |
||||
|
||||
HEALTHCHECK --start-period=60s CMD curl -f http://localhost:2019/metrics || exit 1 |
||||
CMD [ "frankenphp", "run", "--config", "/etc/caddy/Caddyfile" ] |
||||
|
||||
# Dev FrankenPHP image |
||||
FROM frankenphp_base AS frankenphp_dev |
||||
|
||||
ENV APP_ENV=dev XDEBUG_MODE=off |
||||
|
||||
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" |
||||
|
||||
RUN set -eux; \ |
||||
install-php-extensions \ |
||||
xdebug \ |
||||
; |
||||
|
||||
COPY --link frankenphp/conf.d/20-app.dev.ini $PHP_INI_DIR/app.conf.d/ |
||||
|
||||
CMD [ "frankenphp", "run", "--config", "/etc/caddy/Caddyfile", "--watch" ] |
||||
|
||||
# Prod FrankenPHP image |
||||
FROM frankenphp_base AS frankenphp_prod |
||||
|
||||
ENV APP_ENV=prod |
||||
ENV FRANKENPHP_CONFIG="import worker.Caddyfile" |
||||
|
||||
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" |
||||
|
||||
COPY --link frankenphp/conf.d/20-app.prod.ini $PHP_INI_DIR/app.conf.d/ |
||||
COPY --link frankenphp/worker.Caddyfile /etc/caddy/worker.Caddyfile |
||||
|
||||
# prevent the reinstallation of vendors at every changes in the source code |
||||
COPY --link composer.* symfony.* ./ |
||||
RUN set -eux; \ |
||||
composer install --no-cache --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress |
||||
|
||||
# copy sources |
||||
COPY --link . ./ |
||||
RUN rm -Rf frankenphp/ |
||||
|
||||
RUN set -eux; \ |
||||
mkdir -p var/cache var/log; \ |
||||
composer dump-autoload --classmap-authoritative --no-dev; \ |
||||
composer dump-env prod; \ |
||||
composer run-script --no-dev post-install-cmd; \ |
||||
chmod +x bin/console; sync; |
||||
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env php |
||||
<?php |
||||
|
||||
use App\Kernel; |
||||
use Symfony\Bundle\FrameworkBundle\Console\Application; |
||||
|
||||
if (!is_dir(dirname(__DIR__).'/vendor')) { |
||||
throw new LogicException('Dependencies are missing. Try running "composer install".'); |
||||
} |
||||
|
||||
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); |
||||
}; |
||||
@ -0,0 +1,30 @@
@@ -0,0 +1,30 @@
|
||||
# Development environment override |
||||
services: |
||||
php: |
||||
build: |
||||
context: . |
||||
target: frankenphp_dev |
||||
volumes: |
||||
- ./:/app |
||||
- ./frankenphp/Caddyfile:/etc/caddy/Caddyfile:ro |
||||
- ./frankenphp/conf.d/20-app.dev.ini:/usr/local/etc/php/app.conf.d/20-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: |
||||
- /app/vendor |
||||
environment: |
||||
MERCURE_EXTRA_DIRECTIVES: demo |
||||
# 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 |
||||
tty: true |
||||
|
||||
###> symfony/mercure-bundle ### |
||||
###< symfony/mercure-bundle ### |
||||
|
||||
###> doctrine/doctrine-bundle ### |
||||
database: |
||||
ports: |
||||
- "5432" |
||||
###< doctrine/doctrine-bundle ### |
||||
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
# Production environment override |
||||
services: |
||||
php: |
||||
build: |
||||
context: . |
||||
target: frankenphp_prod |
||||
environment: |
||||
APP_SECRET: ${APP_SECRET} |
||||
MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET} |
||||
MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET} |
||||
@ -0,0 +1,65 @@
@@ -0,0 +1,65 @@
|
||||
services: |
||||
php: |
||||
restart: unless-stopped |
||||
build: |
||||
context: . |
||||
dockerfile: Dockerfile |
||||
environment: |
||||
SERVER_NAME: ${SERVER_NAME:-localhost}, php:80 |
||||
MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!} |
||||
MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!} |
||||
# 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:-15}&charset=${POSTGRES_CHARSET:-utf8} |
||||
# Run "composer require symfony/mercure-bundle" to install and configure the Mercure integration |
||||
MERCURE_URL: ${CADDY_MERCURE_URL:-http://php/.well-known/mercure} |
||||
MERCURE_PUBLIC_URL: ${CADDY_MERCURE_PUBLIC_URL:-https://${SERVER_NAME:-localhost}/.well-known/mercure} |
||||
MERCURE_JWT_SECRET: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!} |
||||
volumes: |
||||
- 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 ### |
||||
|
||||
###> doctrine/doctrine-bundle ### |
||||
database: |
||||
image: postgres:${POSTGRES_VERSION:-16}-alpine |
||||
environment: |
||||
POSTGRES_DB: ${POSTGRES_DB:-app} |
||||
# You should definitely change the password in production |
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-!ChangeMe!} |
||||
POSTGRES_USER: ${POSTGRES_USER:-app} |
||||
healthcheck: |
||||
test: ["CMD", "pg_isready", "-d", "${POSTGRES_DB:-app}", "-U", "${POSTGRES_USER:-app}"] |
||||
timeout: 5s |
||||
retries: 5 |
||||
start_period: 60s |
||||
volumes: |
||||
- database_data:/var/lib/postgresql/data:rw |
||||
# You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data! |
||||
# - ./docker/db/data:/var/lib/postgresql/data:rw |
||||
###< doctrine/doctrine-bundle ### |
||||
|
||||
volumes: |
||||
caddy_data: |
||||
caddy_config: |
||||
###> symfony/mercure-bundle ### |
||||
###< symfony/mercure-bundle ### |
||||
|
||||
###> doctrine/doctrine-bundle ### |
||||
database_data: |
||||
###< doctrine/doctrine-bundle ### |
||||
@ -0,0 +1,74 @@
@@ -0,0 +1,74 @@
|
||||
{ |
||||
"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.3.13", |
||||
"ext-ctype": "*", |
||||
"ext-iconv": "*", |
||||
"doctrine/dbal": "^3", |
||||
"doctrine/doctrine-bundle": "^2.13", |
||||
"doctrine/doctrine-migrations-bundle": "^3.3", |
||||
"doctrine/orm": "^3.3", |
||||
"runtime/frankenphp-symfony": "^0.2.0", |
||||
"symfony/console": "7.1.*", |
||||
"symfony/dotenv": "7.1.*", |
||||
"symfony/flex": "^2", |
||||
"symfony/framework-bundle": "7.1.*", |
||||
"symfony/runtime": "7.1.*", |
||||
"symfony/yaml": "7.1.*" |
||||
}, |
||||
"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": "*", |
||||
"symfony/polyfill-php82": "*" |
||||
}, |
||||
"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": "7.1.*", |
||||
"docker": true |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
<?php |
||||
|
||||
return [ |
||||
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], |
||||
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], |
||||
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], |
||||
]; |
||||
@ -0,0 +1,19 @@
@@ -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 |
||||
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
doctrine: |
||||
dbal: |
||||
url: '%env(resolve:DATABASE_URL)%' |
||||
|
||||
# IMPORTANT: You MUST configure your server version, |
||||
# either here or in the DATABASE_URL env var (see .env file) |
||||
#server_version: '16' |
||||
|
||||
profiling_collect_backtrace: '%kernel.debug%' |
||||
use_savepoints: true |
||||
orm: |
||||
auto_generate_proxy_classes: true |
||||
enable_lazy_ghost_objects: true |
||||
report_fields_where_declared: true |
||||
validate_xml_mapping: true |
||||
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware |
||||
identity_generation_preferences: |
||||
Doctrine\DBAL\Platforms\PostgreSQLPlatform: identity |
||||
auto_mapping: true |
||||
mappings: |
||||
App: |
||||
type: attribute |
||||
is_bundle: false |
||||
dir: '%kernel.project_dir%/src/Entity' |
||||
prefix: 'App\Entity' |
||||
alias: App |
||||
controller_resolver: |
||||
auto_mapping: false |
||||
|
||||
when@test: |
||||
doctrine: |
||||
dbal: |
||||
# "TEST_TOKEN" is typically set by ParaTest |
||||
dbname_suffix: '_test%env(default::TEST_TOKEN)%' |
||||
|
||||
when@prod: |
||||
doctrine: |
||||
orm: |
||||
auto_generate_proxy_classes: false |
||||
proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies' |
||||
query_cache_driver: |
||||
type: pool |
||||
pool: doctrine.system_cache_pool |
||||
result_cache_driver: |
||||
type: pool |
||||
pool: doctrine.result_cache_pool |
||||
|
||||
framework: |
||||
cache: |
||||
pools: |
||||
doctrine.result_cache_pool: |
||||
adapter: cache.app |
||||
doctrine.system_cache_pool: |
||||
adapter: cache.system |
||||
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
doctrine_migrations: |
||||
migrations_paths: |
||||
# namespace is arbitrary but should be different from App\Migrations |
||||
# as migrations classes should NOT be autoloaded |
||||
'DoctrineMigrations': '%kernel.project_dir%/migrations' |
||||
enable_profiler: false |
||||
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
# see https://symfony.com/doc/current/reference/configuration/framework.html |
||||
framework: |
||||
secret: '%env(APP_SECRET)%' |
||||
#csrf_protection: true |
||||
|
||||
# Note that the session will be started ONLY if you read or write from it. |
||||
session: true |
||||
|
||||
#esi: true |
||||
#fragments: true |
||||
|
||||
when@test: |
||||
framework: |
||||
test: true |
||||
session: |
||||
storage_factory_id: session.storage.factory.mock_file |
||||
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
framework: |
||||
router: |
||||
# 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 |
||||
@ -0,0 +1,5 @@
@@ -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'; |
||||
} |
||||
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
controllers: |
||||
resource: |
||||
path: ../src/Controller/ |
||||
namespace: App\Controller |
||||
type: attribute |
||||
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
when@dev: |
||||
_errors: |
||||
resource: '@FrameworkBundle/Resources/config/routing/errors.xml' |
||||
prefix: /_error |
||||
@ -0,0 +1,24 @@
@@ -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 |
||||
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
# Using Alpine Linux Instead of Debian |
||||
|
||||
By default, Symfony Docker uses Debian-based FrankenPHP Docker images. |
||||
This is the recommended solution. |
||||
|
||||
Alternatively, it's possible to use Alpine-based images, which are smaller but |
||||
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 |
||||
|
||||
-# hadolint ignore=DL3008 |
||||
-RUN apt-get update && apt-get install -y --no-install-recommends \ |
||||
- acl \ |
||||
- file \ |
||||
- gettext \ |
||||
- git \ |
||||
- && rm -rf /var/lib/apt/lists/* |
||||
+# hadolint ignore=DL3018 |
||||
+RUN apk add --no-cache \ |
||||
+ acl \ |
||||
+ file \ |
||||
+ gettext \ |
||||
+ git \ |
||||
+ ; |
||||
``` |
||||
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 159 KiB |
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
# 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 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. |
||||
|
||||
git archive --format=tar HEAD | tar -xC my-existing-project/ |
||||
|
||||
If you downloaded the skeleton as a zip you can just copy the extracted files: |
||||
|
||||
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 recipes:install --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! |
||||
|
||||
> [!NOTE] |
||||
> If you want to use the worker mode of FrankenPHP, make sure you required the `runtime/frankenphp-symfony` package. |
||||
|
||||
> [!NOTE] |
||||
> The worker mode of FrankenPHP is enabled by default in prod. To disabled it, add the env var FRANKENPHP_CONFIG as empty to the compose.prod.yaml file. |
||||
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
# 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. |
||||
|
||||
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 |
||||
|
||||
> [!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 |
||||
@ -0,0 +1,97 @@
@@ -0,0 +1,97 @@
|
||||
# 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. |
||||
|
||||
> [!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 |
||||
|
||||
```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) bin/console |
||||
|
||||
# Misc |
||||
.DEFAULT_GOAL = help |
||||
.PHONY : help build up start down logs sh composer vendor sf cc test |
||||
|
||||
## —— 🎵 🐳 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 FrankenPHP container |
||||
@$(PHP_CONT) sh |
||||
|
||||
bash: ## Connect to the FrankenPHP container via bash so up and down arrows go to previous commands |
||||
@$(PHP_CONT) bash |
||||
|
||||
test: ## Start tests with phpunit, pass the parameter "c=" to add options to phpunit, example: make test c="--group e2e --stop-on-failure" |
||||
@$(eval c ?=) |
||||
@$(DOCKER_COMP) exec -e APP_ENV=test php bin/phpunit $(c) |
||||
|
||||
|
||||
## —— 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 |
||||
``` |
||||
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
# Using MySQL |
||||
|
||||
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` |
||||
|
||||
## Docker Configuration |
||||
Change the database image to use MySQL instead of PostgreSQL in `compose.yaml`: |
||||
|
||||
```diff |
||||
###> doctrine/doctrine-bundle ### |
||||
- image: postgres:${POSTGRES_VERSION:-15}-alpine |
||||
+ image: mysql:${MYSQL_VERSION:-8} |
||||
environment: |
||||
- POSTGRES_DB: ${POSTGRES_DB:-app} |
||||
+ MYSQL_DATABASE: ${MYSQL_DATABASE:-app} |
||||
# You should definitely change the password in production |
||||
+ MYSQL_RANDOM_ROOT_PASSWORD: "true" |
||||
- POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-!ChangeMe!} |
||||
+ MYSQL_PASSWORD: ${MYSQL_PASSWORD:-!ChangeMe!} |
||||
- POSTGRES_USER: ${POSTGRES_USER:-app} |
||||
+ MYSQL_USER: ${MYSQL_USER:-app} |
||||
healthcheck: |
||||
- test: ["CMD", "pg_isready", "-d", "${POSTGRES_DB:-app}", "-U", "${POSTGRES_USER:-app}"] |
||||
+ test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] |
||||
timeout: 5s |
||||
retries: 5 |
||||
start_period: 60s |
||||
volumes: |
||||
- - database_data:/var/lib/postgresql/data:rw |
||||
+ - database_data:/var/lib/mysql:rw |
||||
# You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data! |
||||
- # - ./docker/db/data:/var/lib/postgresql/data:rw |
||||
+ # - ./docker/db/data:/var/lib/mysql:rw |
||||
###< doctrine/doctrine-bundle ### |
||||
``` |
||||
|
||||
Depending on the database configuration, modify the environment in the same file at `services.php.environment.DATABASE_URL` |
||||
``` |
||||
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: |
||||
ports: |
||||
- - "5432" |
||||
+ - "3306" |
||||
###< doctrine/doctrine-bundle ### |
||||
``` |
||||
|
||||
Last but not least, we need to install the MySQL driver in `Dockerfile`: |
||||
```diff |
||||
###> doctrine/doctrine-bundle ### |
||||
-RUN install-php-extensions pdo_pgsql |
||||
+RUN install-php-extensions pdo_mysql |
||||
###< doctrine/doctrine-bundle ### |
||||
``` |
||||
|
||||
## Change Environment |
||||
Change the database configuration in `.env`: |
||||
|
||||
```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 |
||||
docker compose down --remove-orphans && docker compose build --pull --no-cache |
||||
``` |
||||
|
||||
Start the services: |
||||
```shell |
||||
docker compose up -d |
||||
``` |
||||
|
||||
Test your setup: |
||||
```shell |
||||
docker compose exec php bin/console dbal:run-sql -q "SELECT 1" && echo "OK" || echo "Connection is not working" |
||||
``` |
||||
@ -0,0 +1,72 @@
@@ -0,0 +1,72 @@
|
||||
# Docker Build Options |
||||
|
||||
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. |
||||
|
||||
## 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 6.4: |
||||
|
||||
On Linux: |
||||
|
||||
SYMFONY_VERSION=6.4.* docker compose up -d --wait |
||||
On Windows: |
||||
|
||||
set SYMFONY_VERSION=6.4.* && docker compose up -d --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. |
||||
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 -d --wait |
||||
|
||||
On Windows: |
||||
|
||||
set STABILITY=dev && docker compose up -d --wait&set STABILITY= |
||||
|
||||
## 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 -d --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. |
||||
|
||||
|
||||
## Caddyfile Options |
||||
|
||||
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 |
||||
|
||||
| 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` | |
||||
| `MERCURE_TRANSPORT_URL` | the value passed to the `transport_url` directive | `bolt://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` | |
||||
| `MERCURE_SUBSCRIBER_JWT_KEY` | the JWT key to use for subscribers | | |
||||
| `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: |
||||
|
||||
SERVER_NAME="app.localhost" docker compose up -d --wait |
||||
@ -0,0 +1,110 @@
@@ -0,0 +1,110 @@
|
||||
# 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! |
||||
|
||||
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. |
||||
|
||||
 |
||||
|
||||
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. |
||||
|
||||
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 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: |
||||
|
||||
```dns |
||||
your-domain-name.example.com. IN A 207.154.233.113 |
||||
``` |
||||
|
||||
Example with the DigitalOcean Domains service ("Networking" > "Domains"): |
||||
|
||||
 |
||||
|
||||
> [!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 compose.yaml -f compose.prod.yaml up -d --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. |
||||
|
||||
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. |
||||
|
||||
> [!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. |
||||
|
||||
## 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 compose.yaml -f compose.prod.yaml up -d --wait |
||||
``` |
||||
|
||||
## 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. |
||||
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 |
||||
|
||||
By default, `.env.local` and `.env.*.local` files are excluded from production images. |
||||
If you want to pass them to your containers, you can use the [`env_file` attribute](https://docs.docker.com/compose/environment-variables/set-environment-variables/#use-the-env_file-attribute): |
||||
|
||||
```yaml |
||||
# compose.prod.yml |
||||
|
||||
services: |
||||
php: |
||||
env_file: |
||||
- .env.prod.local |
||||
# ... |
||||
``` |
||||
@ -0,0 +1,51 @@
@@ -0,0 +1,51 @@
|
||||
# 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 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 |
||||
``` |
||||
|
||||
## 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 frankenphp/certs -p` |
||||
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 |
||||
php: |
||||
environment: |
||||
+ CADDY_SERVER_EXTRA_DIRECTIVES: "tls /etc/caddy/certs/tls.pem /etc/caddy/certs/tls.key" |
||||
# ... |
||||
volumes: |
||||
+ - ./frankenphp/certs:/etc/caddy/certs:ro |
||||
- ./public:/app/public: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: |
||||
|
||||
```bash |
||||
SERVER_NAME=http://localhost \ |
||||
MERCURE_PUBLIC_URL=http://localhost/.well-known/mercure \ |
||||
docker compose up --pull always -d --wait |
||||
``` |
||||
|
||||
Ensure your application is accessible over HTTP by visiting `http://localhost` in your web browser. |
||||
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
# 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. |
||||
|
||||
## TLS/HTTPS Issues |
||||
|
||||
See more in the [TLS section](tls.md) |
||||
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
# 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): |
||||
|
||||
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 |
||||
``` |
||||
|
||||
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). |
||||
@ -0,0 +1,58 @@
@@ -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: `/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,0 +1,57 @@
@@ -0,0 +1,57 @@
|
||||
{ |
||||
{$CADDY_GLOBAL_OPTIONS} |
||||
|
||||
frankenphp { |
||||
{$FRANKENPHP_CONFIG} |
||||
} |
||||
} |
||||
|
||||
{$CADDY_EXTRA_CONFIG} |
||||
|
||||
{$SERVER_NAME:localhost} { |
||||
log { |
||||
{$CADDY_SERVER_LOG_OPTIONS} |
||||
# Redact the authorization query parameter that can be set by Mercure |
||||
format filter { |
||||
request>uri query { |
||||
replace authorization REDACTED |
||||
} |
||||
} |
||||
} |
||||
|
||||
root /app/public |
||||
encode zstd br gzip |
||||
|
||||
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 |
||||
|
||||
{$CADDY_SERVER_EXTRA_DIRECTIVES} |
||||
|
||||
# Disable Topics tracking if not enabled explicitly: https://github.com/jkarlin/topics |
||||
header ?Permissions-Policy "browsing-topics=()" |
||||
|
||||
@phpRoute { |
||||
not path /.well-known/mercure* |
||||
not file {path} |
||||
} |
||||
rewrite @phpRoute index.php |
||||
|
||||
@frontController path index.php |
||||
php @frontController |
||||
|
||||
file_server |
||||
} |
||||
@ -0,0 +1,13 @@
@@ -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 |
||||
@ -0,0 +1,5 @@
@@ -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 |
||||
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
opcache.preload_user = root |
||||
opcache.preload = /app/config/preload.php |
||||
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
#!/bin/sh |
||||
set -e |
||||
|
||||
if [ "$1" = 'frankenphp' ] || [ "$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 |
||||
rm -Rf tmp/ |
||||
composer create-project "symfony/skeleton $SYMFONY_VERSION" tmp --stability="$STABILITY" --prefer-dist --no-progress --no-interaction --no-install |
||||
|
||||
cd tmp |
||||
cp -Rp . .. |
||||
cd - |
||||
rm -Rf tmp/ |
||||
|
||||
composer require "php:>=$PHP_VERSION" runtime/frankenphp-symfony |
||||
composer config --json extra.symfony.docker 'true' |
||||
|
||||
if grep -q ^DATABASE_URL= .env; then |
||||
echo 'To finish the installation please press Ctrl+C to stop Docker Compose and run: docker compose up --build -d --wait' |
||||
sleep infinity |
||||
fi |
||||
fi |
||||
|
||||
if [ -z "$(ls -A 'vendor/' 2>/dev/null)" ]; then |
||||
composer install --prefer-dist --no-progress --no-interaction |
||||
fi |
||||
|
||||
if grep -q ^DATABASE_URL= .env; then |
||||
echo 'Waiting for database to be ready...' |
||||
ATTEMPTS_LEFT_TO_REACH_DATABASE=60 |
||||
until [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ] || DATABASE_ERROR=$(php bin/console dbal:run-sql -q "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 database to be ready... Or maybe the database 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 database is now ready and reachable' |
||||
fi |
||||
|
||||
if [ "$( find ./migrations -iname '*.php' -print -quit )" ]; then |
||||
php bin/console doctrine:migrations:migrate --no-interaction --all-or-nothing |
||||
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 "$@" |
||||
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
worker { |
||||
file ./public/index.php |
||||
env APP_RUNTIME Runtime\FrankenPhpSymfony\Runtime |
||||
} |
||||
@ -0,0 +1,9 @@
@@ -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,0 +1,11 @@
@@ -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; |
||||
} |
||||
@ -0,0 +1,85 @@
@@ -0,0 +1,85 @@
|
||||
{ |
||||
"doctrine/doctrine-bundle": { |
||||
"version": "2.13", |
||||
"recipe": { |
||||
"repo": "github.com/symfony/recipes", |
||||
"branch": "main", |
||||
"version": "2.13", |
||||
"ref": "8d96c0b51591ffc26794d865ba3ee7d193438a83" |
||||
}, |
||||
"files": [ |
||||
"./config/packages/doctrine.yaml", |
||||
"./src/Entity/.gitignore", |
||||
"./src/Repository/.gitignore" |
||||
] |
||||
}, |
||||
"doctrine/doctrine-migrations-bundle": { |
||||
"version": "3.3", |
||||
"recipe": { |
||||
"repo": "github.com/symfony/recipes", |
||||
"branch": "main", |
||||
"version": "3.1", |
||||
"ref": "1d01ec03c6ecbd67c3375c5478c9a423ae5d6a33" |
||||
}, |
||||
"files": [ |
||||
"./config/packages/doctrine_migrations.yaml", |
||||
"./migrations/.gitignore" |
||||
] |
||||
}, |
||||
"symfony/console": { |
||||
"version": "7.1", |
||||
"recipe": { |
||||
"repo": "github.com/symfony/recipes", |
||||
"branch": "main", |
||||
"version": "5.3", |
||||
"ref": "1781ff40d8a17d87cf53f8d4cf0c8346ed2bb461" |
||||
}, |
||||
"files": [ |
||||
"bin/console" |
||||
] |
||||
}, |
||||
"symfony/flex": { |
||||
"version": "2.4", |
||||
"recipe": { |
||||
"repo": "github.com/symfony/recipes", |
||||
"branch": "main", |
||||
"version": "1.0", |
||||
"ref": "146251ae39e06a95be0fe3d13c807bcf3938b172" |
||||
}, |
||||
"files": [ |
||||
".env" |
||||
] |
||||
}, |
||||
"symfony/framework-bundle": { |
||||
"version": "7.1", |
||||
"recipe": { |
||||
"repo": "github.com/symfony/recipes", |
||||
"branch": "main", |
||||
"version": "7.0", |
||||
"ref": "6356c19b9ae08e7763e4ba2d9ae63043efc75db5" |
||||
}, |
||||
"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": "7.1", |
||||
"recipe": { |
||||
"repo": "github.com/symfony/recipes", |
||||
"branch": "main", |
||||
"version": "7.0", |
||||
"ref": "21b72649d5622d8f7da329ffb5afb232a023619d" |
||||
}, |
||||
"files": [ |
||||
"config/packages/routing.yaml", |
||||
"config/routes.yaml" |
||||
] |
||||
} |
||||
} |
||||
Loading…
Reference in new issue