init
This commit is contained in:
@@ -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,22 @@
|
||||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[**/{Dockerfile,Caddyfile,*.sh}]
|
||||
indent_style = tab
|
||||
|
||||
[{compose.*yaml,.devcontainer/compose.*yaml,.github/**/*.yaml}]
|
||||
indent_size = 2
|
||||
|
||||
[**.md]
|
||||
indent_size = unset
|
||||
indent_style = unset
|
||||
@@ -0,0 +1,27 @@
|
||||
# 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=
|
||||
APP_SHARE_DIR=var/share
|
||||
###< symfony/framework-bundle ###
|
||||
|
||||
###> symfony/routing ###
|
||||
# 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
|
||||
###< symfony/routing ###
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
###> symfony/framework-bundle ###
|
||||
APP_SECRET=721f1c073aa9c56fd3c03089e7297bde
|
||||
###< symfony/framework-bundle ###
|
||||
@@ -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
|
||||
+10
@@ -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 ###
|
||||
Generated
+10
@@ -0,0 +1,10 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Ignored default folder with query files
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
Generated
+70
@@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="App\" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="App\Tests\" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/collections" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/dbal" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/deprecations" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/event-manager" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/inflector" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/instantiator" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/lexer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/orm" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/persistence" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/nikic/php-parser" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/clock" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/container" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/event-dispatcher" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/log" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/cache-contracts" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/clock" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/config" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/console" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/dependency-injection" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/deprecation-contracts" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/dotenv" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/error-handler" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher-contracts" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/filesystem" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/finder" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/flex" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/framework-bundle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-foundation" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-kernel" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/maker-bundle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/password-hasher" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-deepclone" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php85" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/process" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/property-access" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/property-info" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/routing" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/runtime" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-bundle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-core" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-csrf" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-http" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/service-contracts" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/string" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/translation-contracts" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/twig-bridge" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/twig-bundle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/type-info" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-dumper" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-exporter" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/yaml" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/twig" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/gym-tracker.iml" filepath="$PROJECT_DIR$/.idea/gym-tracker.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+88
@@ -0,0 +1,88 @@
|
||||
<?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="PhpIncludePathManager">
|
||||
<include_path>
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/dotenv" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/runtime" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/cache-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/yaml" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/flex" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/var-exporter" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-kernel" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/var-dumper" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/framework-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-deepclone" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/filesystem" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/string" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/dependency-injection" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/config" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/console" />
|
||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/log" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php85" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/collections" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/inflector" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/lexer" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/event-manager" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/deprecations" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/persistence" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/dbal" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/orm" />
|
||||
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/clock" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/type-info" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/property-info" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/property-access" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/twig-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/process" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/clock" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/password-hasher" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-csrf" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/twig-bridge" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-core" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/maker-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/twig/twig" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-http" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="8.5" />
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpUnit">
|
||||
<phpunit_settings>
|
||||
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" />
|
||||
</phpunit_settings>
|
||||
</component>
|
||||
<component name="PsalmOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
#syntax=docker/dockerfile:1
|
||||
|
||||
# Versions
|
||||
FROM dunglas/frankenphp:1-php8.5 AS frankenphp_upstream
|
||||
|
||||
# The different stages of this Dockerfile are meant to be built into separate images
|
||||
# https://docs.docker.com/build/building/multi-stage/#stop-at-a-specific-build-stage
|
||||
# https://docs.docker.com/reference/compose-file/build/#target
|
||||
|
||||
|
||||
# Base FrankenPHP image
|
||||
FROM frankenphp_upstream AS frankenphp_base
|
||||
|
||||
SHELL ["/bin/bash", "-euxo", "pipefail", "-c"]
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# persistent deps
|
||||
# hadolint ignore=DL3008
|
||||
RUN <<-EOF
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends \
|
||||
file \
|
||||
git
|
||||
install-php-extensions \
|
||||
@composer \
|
||||
apcu \
|
||||
intl \
|
||||
opcache \
|
||||
zip
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
EOF
|
||||
|
||||
# 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 ###
|
||||
###< 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/frankenphp/Caddyfile
|
||||
|
||||
ENTRYPOINT ["docker-entrypoint"]
|
||||
|
||||
HEALTHCHECK --start-period=60s CMD php -r 'exit(false === @file_get_contents("http://localhost:2019/metrics", context: stream_context_create(["http" => ["timeout" => 5]])) ? 1 : 0);'
|
||||
CMD [ "frankenphp", "run", "--config", "/etc/frankenphp/Caddyfile" ]
|
||||
|
||||
# Dev FrankenPHP image
|
||||
FROM frankenphp_base AS frankenphp_dev
|
||||
|
||||
ENV APP_ENV=dev
|
||||
ENV XDEBUG_MODE=off
|
||||
ENV FRANKENPHP_WORKER_CONFIG=watch
|
||||
|
||||
# dev dependencies
|
||||
# hadolint ignore=DL3008
|
||||
RUN <<-EOF
|
||||
mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends \
|
||||
aggregate \
|
||||
curl \
|
||||
dnsmasq \
|
||||
dnsutils \
|
||||
iproute2 \
|
||||
ipset \
|
||||
iptables \
|
||||
jq \
|
||||
sudo
|
||||
install-php-extensions xdebug
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
useradd -m -s /bin/bash nonroot
|
||||
echo "nonroot ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/nonroot
|
||||
git config --system --add safe.directory /app
|
||||
EOF
|
||||
|
||||
COPY --link frankenphp/conf.d/20-app.dev.ini $PHP_INI_DIR/app.conf.d/
|
||||
|
||||
CMD [ "frankenphp", "run", "--config", "/etc/frankenphp/Caddyfile", "--watch" ]
|
||||
|
||||
# Builder for the prod FrankenPHP image
|
||||
FROM frankenphp_base AS frankenphp_prod_builder
|
||||
|
||||
ENV APP_ENV=prod
|
||||
|
||||
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/
|
||||
|
||||
# prevent the reinstallation of vendors at every changes in the source code
|
||||
COPY --link composer.* symfony.* ./
|
||||
RUN composer install --no-cache --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress
|
||||
|
||||
# copy sources
|
||||
COPY --link --exclude=frankenphp/ . ./
|
||||
|
||||
RUN <<-EOF
|
||||
mkdir -p var/cache var/log var/share
|
||||
composer dump-autoload --classmap-authoritative --no-dev
|
||||
composer dump-env prod
|
||||
composer run-script --no-dev post-install-cmd
|
||||
if [ -f importmap.php ]; then
|
||||
php bin/console asset-map:compile
|
||||
fi
|
||||
chmod +x bin/console
|
||||
chmod -R g=u var
|
||||
sync
|
||||
EOF
|
||||
|
||||
# Collect shared libraries needed by FrankenPHP and PHP extensions
|
||||
# hadolint ignore=DL3008,SC3054,DL4006
|
||||
RUN <<-'EOF'
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends libtree
|
||||
mkdir -p /tmp/libs
|
||||
BINARIES=(frankenphp php file)
|
||||
for target in $(printf '%s\n' "${BINARIES[@]}" | xargs -I{} which {}) \
|
||||
$(find "$(php -r 'echo ini_get("extension_dir");')" -maxdepth 2 -name "*.so"); do
|
||||
libtree -pv "$target" 2>/dev/null | grep -oP '(?:── )\K/\S+(?= \[)' | while IFS= read -r lib; do
|
||||
[ -f "$lib" ] && cp -n "$lib" /tmp/libs/
|
||||
done
|
||||
done
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
EOF
|
||||
|
||||
# Prod FrankenPHP image
|
||||
FROM debian:13-slim AS frankenphp_prod
|
||||
|
||||
SHELL ["/bin/bash", "-euxo", "pipefail", "-c"]
|
||||
|
||||
ENV APP_ENV=prod
|
||||
ENV PHP_INI_SCAN_DIR=":/usr/local/etc/php/app.conf.d"
|
||||
|
||||
COPY --from=frankenphp_prod_builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp
|
||||
COPY --from=frankenphp_prod_builder /usr/local/bin/php /usr/local/bin/php
|
||||
COPY --from=frankenphp_prod_builder /usr/local/bin/docker-php-entrypoint /usr/local/bin/docker-php-entrypoint
|
||||
COPY --from=frankenphp_prod_builder /usr/local/lib/php/extensions /usr/local/lib/php/extensions
|
||||
COPY --from=frankenphp_prod_builder /tmp/libs /usr/lib
|
||||
|
||||
COPY --from=frankenphp_prod_builder /usr/local/etc/php/conf.d /usr/local/etc/php/conf.d
|
||||
COPY --from=frankenphp_prod_builder /usr/local/etc/php/php.ini /usr/local/etc/php/php.ini
|
||||
COPY --from=frankenphp_prod_builder /usr/local/etc/php/app.conf.d /usr/local/etc/php/app.conf.d
|
||||
|
||||
COPY --from=frankenphp_prod_builder /etc/frankenphp/Caddyfile /etc/frankenphp/Caddyfile
|
||||
|
||||
# CA certificates for TLS, file/libmagic for Symfony MIME type detection
|
||||
COPY --from=frankenphp_prod_builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||
COPY --from=frankenphp_prod_builder /etc/ssl/openssl.cnf /etc/ssl/openssl.cnf
|
||||
COPY --from=frankenphp_prod_builder /usr/bin/file /usr/bin/file
|
||||
COPY --from=frankenphp_prod_builder /usr/lib/file/magic.mgc /usr/lib/file/magic.mgc
|
||||
|
||||
ENV OPENSSL_CONF=/etc/ssl/openssl.cnf XDG_CONFIG_HOME=/config XDG_DATA_HOME=/data
|
||||
|
||||
RUN <<-EOF
|
||||
mkdir -p /data/caddy /config/caddy
|
||||
chown -R www-data:www-data /data /config
|
||||
# Remove setuid/setgid bits
|
||||
find / -perm /6000 -type f -exec chmod a-s {} + 2>/dev/null || true
|
||||
EOF
|
||||
|
||||
COPY --link --exclude=var --from=frankenphp_prod_builder /app /app
|
||||
# Group 0 + g=u for arbitrary-UID runtimes (e.g. OpenShift).
|
||||
COPY --chown=www-data:0 --from=frankenphp_prod_builder /app/var /app/var
|
||||
RUN chmod g=u /app/var
|
||||
|
||||
COPY --link --chmod=755 frankenphp/docker-entrypoint.sh /usr/local/bin/docker-entrypoint
|
||||
|
||||
USER www-data
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ENTRYPOINT ["docker-entrypoint"]
|
||||
|
||||
HEALTHCHECK --start-period=60s CMD php -r 'exit(false === @file_get_contents("http://localhost:2019/metrics", context: stream_context_create(["http" => ["timeout" => 5]])) ? 1 : 0);'
|
||||
CMD [ "frankenphp", "run", "--config", "/etc/frankenphp/Caddyfile" ]
|
||||
@@ -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.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Symfony Docker
|
||||
|
||||
A [Docker](https://www.docker.com/)-based installer and runtime for the [Symfony](https://symfony.com) web framework,
|
||||
with [FrankenPHP](https://frankenphp.dev) and [Caddy](https://caddyserver.com/) inside!
|
||||
|
||||
Specially tailored for coding agents: ships with a [Dev Container](https://containers.dev/) configuration
|
||||
that lets [Claude Code](https://claude.ai/claude-code) (and other AI coding assistants) run in fully autonomous
|
||||
mode inside a sandboxed environment.
|
||||
|
||||

|
||||
|
||||
## 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 --wait` to set up and start a fresh Symfony project
|
||||
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
|
||||
- Just 1 service by default
|
||||
- Super-readable configuration
|
||||
- Blazing-fast performance thanks to [the worker mode of FrankenPHP](https://frankenphp.dev/docs/worker/)
|
||||
- [Installation of extra Docker Compose services](docs/extra-services.md) with Symfony Flex
|
||||
- Automatic HTTPS (in dev and prod)
|
||||
- HTTP/3 and [Early Hints](https://symfony.com/blog/new-in-symfony-6-3-early-hints) support
|
||||
- Real-time messaging thanks to a built-in [Mercure hub](https://symfony.com/doc/current/mercure.html)
|
||||
- [Vulcain](https://vulcain.rocks) support
|
||||
- Native [XDebug](docs/xdebug.md) integration
|
||||
- [Hot Reloading](https://frankenphp.dev/docs/hot-reload/)
|
||||
- [Dev Container](https://containers.dev/) support, optimized for AI coding agents
|
||||
- [AI coding agents](docs/agents.md) with sandboxing out of the box
|
||||
- Rootless, slim production image
|
||||
|
||||
**Enjoy!**
|
||||
|
||||
## Docs
|
||||
|
||||
1. [Options available](docs/options.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 MySQL instead of PostgreSQL](docs/mysql.md)
|
||||
8. [Using Alpine Linux instead of Debian](docs/alpine.md)
|
||||
9. [Using a Makefile](docs/makefile.md)
|
||||
10. [Updating the template](docs/updating.md)
|
||||
11. [Troubleshooting](docs/troubleshooting.md)
|
||||
12. [Using AI Coding Agents](docs/agents.md)
|
||||
|
||||
## License
|
||||
|
||||
Symfony Docker is available under the MIT License.
|
||||
|
||||
## Credits
|
||||
|
||||
Created by [Kévin Dunglas](https://dunglas.dev), co-maintained by [Maxime Helias](https://twitter.com/maxhelias) and sponsored by [Les-Tilleuls.coop](https://les-tilleuls.coop).
|
||||
Executable
+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 @@
|
||||
---
|
||||
# Development environment override
|
||||
services:
|
||||
php:
|
||||
image: ${IMAGES_PREFIX:-}app-php-dev
|
||||
build:
|
||||
context: .
|
||||
target: frankenphp_dev
|
||||
volumes:
|
||||
- ./:/app
|
||||
- ./frankenphp/Caddyfile:/etc/frankenphp/Caddyfile:ro
|
||||
- ./frankenphp/conf.d/20-app.dev.ini:/usr/local/etc/php/app.conf.d/20-app.dev.ini:ro
|
||||
# Keep var/ off the bind-mount for faster I/O on Mac/Windows; comment to inspect from the host.
|
||||
- /app/var
|
||||
# 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:
|
||||
FRANKENPHP_WORKER_CONFIG: watch
|
||||
FRANKENPHP_SITE_CONFIG: hot_reload
|
||||
MERCURE_EXTRA_DIRECTIVES: demo
|
||||
# See https://xdebug.org/docs/all_settings#mode
|
||||
XDEBUG_MODE: "${XDEBUG_MODE:-develop}"
|
||||
APP_ENV: "${APP_ENV:-dev}"
|
||||
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 ###
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
# Production environment override
|
||||
services:
|
||||
php:
|
||||
image: ${IMAGES_PREFIX:-}app-php-prod
|
||||
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,41 @@
|
||||
---
|
||||
services:
|
||||
php:
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
SERVER_NAME: ${SERVER_NAME:-localhost}, php:80
|
||||
DEFAULT_URI: https://${SERVER_NAME:-localhost}:${HTTPS_PORT:-443}
|
||||
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}:${HTTPS_PORT:-443}/.well-known/mercure}
|
||||
MERCURE_JWT_SECRET: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!}
|
||||
volumes:
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
ports:
|
||||
- name: http
|
||||
target: 80
|
||||
published: ${HTTP_PORT:-80}
|
||||
protocol: tcp
|
||||
- name: https
|
||||
target: 443
|
||||
published: ${HTTPS_PORT:-443}
|
||||
protocol: tcp
|
||||
- name: http3
|
||||
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:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
###> symfony/mercure-bundle ###
|
||||
###< symfony/mercure-bundle ###
|
||||
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"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.5.7",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"doctrine/orm": "^3.6",
|
||||
"symfony/console": "8.1.*",
|
||||
"symfony/dotenv": "8.1.*",
|
||||
"symfony/flex": "^2",
|
||||
"symfony/framework-bundle": "8.1.*",
|
||||
"symfony/runtime": "8.1.*",
|
||||
"symfony/security-bundle": "8.1.*",
|
||||
"symfony/twig-bundle": "8.1.*",
|
||||
"symfony/yaml": "8.1.*"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"php-http/discovery": true,
|
||||
"symfony/flex": true,
|
||||
"symfony/runtime": true
|
||||
},
|
||||
"bump-after-update": 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": "*",
|
||||
"symfony/polyfill-php83": "*",
|
||||
"symfony/polyfill-php84": "*"
|
||||
},
|
||||
"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": "8.1.*",
|
||||
"docker": true
|
||||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/maker-bundle": "^1.67"
|
||||
}
|
||||
}
|
||||
Generated
+4723
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
|
||||
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
||||
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||
];
|
||||
@@ -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,15 @@
|
||||
# see https://symfony.com/doc/current/reference/configuration/framework.html
|
||||
framework:
|
||||
secret: '%env(APP_SECRET)%'
|
||||
|
||||
# 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,3 @@
|
||||
framework:
|
||||
property_info:
|
||||
with_constructor_extractor: true
|
||||
@@ -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: '%env(DEFAULT_URI)%'
|
||||
|
||||
when@prod:
|
||||
framework:
|
||||
router:
|
||||
strict_requirements: null
|
||||
@@ -0,0 +1,39 @@
|
||||
security:
|
||||
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
|
||||
password_hashers:
|
||||
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
|
||||
|
||||
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
|
||||
providers:
|
||||
users_in_memory: { memory: null }
|
||||
|
||||
firewalls:
|
||||
dev:
|
||||
# Ensure dev tools and static assets are always allowed
|
||||
pattern: ^/(_profiler|_wdt|assets|build)/
|
||||
security: false
|
||||
main:
|
||||
lazy: true
|
||||
provider: users_in_memory
|
||||
|
||||
# Activate different ways to authenticate:
|
||||
# https://symfony.com/doc/current/security.html#the-firewall
|
||||
|
||||
# https://symfony.com/doc/current/security/impersonating_user.html
|
||||
# switch_user: true
|
||||
|
||||
# Note: Only the *first* matching rule is applied
|
||||
access_control:
|
||||
# - { path: ^/admin, roles: ROLE_ADMIN }
|
||||
# - { path: ^/profile, roles: ROLE_USER }
|
||||
|
||||
when@test:
|
||||
security:
|
||||
password_hashers:
|
||||
# Password hashers are resource-intensive by design to ensure security.
|
||||
# In tests, it's safe to reduce their cost to improve performance.
|
||||
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
|
||||
algorithm: auto
|
||||
cost: 4 # Lowest possible value for bcrypt
|
||||
time_cost: 3 # Lowest possible value for argon
|
||||
memory_cost: 10 # Lowest possible value for argon
|
||||
@@ -0,0 +1,6 @@
|
||||
twig:
|
||||
file_name_pattern: '*.twig'
|
||||
|
||||
when@test:
|
||||
twig:
|
||||
strict_variables: true
|
||||
@@ -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';
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
# yaml-language-server: $schema=../vendor/symfony/routing/Loader/schema/routing.schema.json
|
||||
|
||||
# This file is the entry point to configure the routes of your app.
|
||||
# Methods with the #[Route] attribute are automatically imported.
|
||||
# See also https://symfony.com/doc/current/routing.html
|
||||
|
||||
# To list all registered routes, run the following command:
|
||||
# bin/console debug:router
|
||||
|
||||
controllers:
|
||||
resource: routing.controllers
|
||||
@@ -0,0 +1,4 @@
|
||||
when@dev:
|
||||
_errors:
|
||||
resource: '@FrameworkBundle/Resources/config/routing/errors.php'
|
||||
prefix: /_error
|
||||
@@ -0,0 +1,3 @@
|
||||
_security_logout:
|
||||
resource: security.route_loader.logout
|
||||
type: service
|
||||
@@ -0,0 +1,23 @@
|
||||
# yaml-language-server: $schema=../vendor/symfony/dependency-injection/Loader/schema/services.schema.json
|
||||
|
||||
# This file is the entry point to configure your own services.
|
||||
# Files in the packages/ subdirectory configure your dependencies.
|
||||
# See also https://symfony.com/doc/current/service_container/import.html
|
||||
|
||||
# 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/'
|
||||
|
||||
# add more service definitions when explicit configuration is needed
|
||||
# please note that last definitions always *replace* previous ones
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
# Using AI Coding Agents with Dev Containers
|
||||
|
||||
This project ships with a [Dev Container](https://containers.dev/) configuration that enables
|
||||
AI coding agents to run autonomously inside a sandboxed environment with network-level restrictions.
|
||||
|
||||
[Claude Code](https://claude.ai/claude-code) is pre-installed and configured out of the box,
|
||||
but the setup also works with other agents such as [OpenAI Codex CLI](https://github.com/openai/codex)
|
||||
and [opencode](https://opencode.ai).
|
||||
|
||||
This setup is ideal for letting AI agents work on your Symfony project autonomously
|
||||
while ensuring they cannot reach arbitrary internet hosts.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [Docker Desktop](https://www.docker.com/products/docker-desktop/) (or any Docker-compatible runtime)
|
||||
- [Visual Studio Code](https://code.visualstudio.com/) with the [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension
|
||||
- A valid subscription or API key for the agent you want to use
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Open the project in Visual Studio Code.
|
||||
2. When prompted "Reopen in Container", click **Reopen in Container**.
|
||||
Alternatively, open the Command Palette (`Ctrl+Shift+P` / `Cmd+Shift+P`) and run
|
||||
**Dev Containers: Reopen in Container**.
|
||||
3. Wait for the container to build and start. On each container start, the
|
||||
`postStartCommand` configures the firewall automatically.
|
||||
4. Claude Code is pre-installed and configured in YOLO mode — open the Claude Code
|
||||
panel in Visual Studio Code or run `claude` in the integrated terminal to start using it.
|
||||
|
||||
That's it. Claude Code will run without permission prompts, and the firewall ensures
|
||||
network access is restricted to only the necessary services.
|
||||
|
||||
## What Is YOLO Mode?
|
||||
|
||||
YOLO mode (also known as "bypass permissions" mode) allows Claude Code to execute
|
||||
commands, edit files, and perform actions without asking for confirmation at each step.
|
||||
This dramatically speeds up autonomous coding workflows.
|
||||
|
||||
The Dev Container configuration enables this via two Visual Studio Code settings:
|
||||
|
||||
```json
|
||||
{
|
||||
"claudeCode.allowDangerouslySkipPermissions": true,
|
||||
"claudeCode.initialPermissionMode": "bypassPermissions"
|
||||
}
|
||||
```
|
||||
|
||||
## Network Sandboxing
|
||||
|
||||
Running an AI agent with full autonomy requires guardrails. The Dev Container includes
|
||||
a firewall script (`.devcontainer/init-firewall.sh`) that locks down outbound network
|
||||
access using `iptables` and `ipset`. Only the following destinations are allowed:
|
||||
|
||||
| Destination | Reason |
|
||||
| ------------------------------------------------- | ------------------------------- |
|
||||
| GitHub (`github.com`, `api.github.com`) | Git operations, API access |
|
||||
| Anthropic (`anthropic.com`) | Claude Code backend |
|
||||
| npm registry (`registry.npmjs.org`) | Node.js dependencies |
|
||||
| Packagist (`packagist.org`, `repo.packagist.org`) | PHP/Composer dependencies |
|
||||
| Visual Studio Code Marketplace | Extension downloads |
|
||||
| Sentry, Statsig | Telemetry (used by Claude Code) |
|
||||
| Host gateway IP | Communication with Docker host |
|
||||
|
||||
All other outbound connections are **rejected**. The firewall uses
|
||||
[dnsmasq](https://thekelleys.org.uk/dnsmasq/doc.html) to dynamically resolve
|
||||
and whitelist IPs for allowed domains, handling CDN IP rotation gracefully.
|
||||
|
||||
Inbound connections from the host gateway IP are allowed on all ports,
|
||||
and ports 80, 443 (TCP), and 443 (UDP/HTTP3) are open to any source
|
||||
so you can access your Symfony app from the host browser.
|
||||
|
||||
## Customizing the Allowed Domains
|
||||
|
||||
To allow additional domains (e.g., a private registry or API), edit
|
||||
`.devcontainer/init-firewall.sh` and add them to the `ipset` line in the
|
||||
dnsmasq configuration section:
|
||||
|
||||
```bash
|
||||
# Domains are '/'-separated, ending with the ipset name
|
||||
ipset=/github.com/anthropic.com/your-domain.com/allowed-domains
|
||||
```
|
||||
|
||||
Then rebuild the Dev Container for the changes to take effect.
|
||||
|
||||
## Using Other Agents
|
||||
|
||||
The Dev Container's network sandbox and project context (`.devcontainer/AGENTS.md`) work
|
||||
with any AI coding agent. You just need to install the agent and whitelist the domains it
|
||||
needs to reach.
|
||||
|
||||
### OpenAI Codex CLI
|
||||
|
||||
1. Add the OpenAI API domain to the firewall allowlist in `.devcontainer/init-firewall.sh`
|
||||
(see [Customizing the Allowed Domains](#customizing-the-allowed-domains)):
|
||||
|
||||
```bash
|
||||
ipset=/.../api.openai.com/allowed-domains
|
||||
```
|
||||
|
||||
2. Install and run Codex inside the container:
|
||||
|
||||
```console
|
||||
npm install -g @openai/codex
|
||||
export OPENAI_API_KEY=your-key
|
||||
codex --full-auto
|
||||
```
|
||||
|
||||
### opencode
|
||||
|
||||
1. Add the required API domain to the firewall allowlist (e.g., `api.anthropic.com`,
|
||||
`api.openai.com`, or your provider's domain).
|
||||
|
||||
2. Install and run opencode inside the container:
|
||||
|
||||
```console
|
||||
curl -fsSL https://opencode.ai/install | bash
|
||||
opencode
|
||||
```
|
||||
|
||||
### Other Agents
|
||||
|
||||
For any other agent, follow the same pattern:
|
||||
|
||||
1. Add the agent's API domain(s) to the firewall allowlist.
|
||||
2. Install the agent inside the container.
|
||||
3. Run it — the `.devcontainer/AGENTS.md` file provides project context
|
||||
to agents that support the convention.
|
||||
|
||||
## Using Without Visual Studio Code
|
||||
|
||||
The Dev Container configuration works with any tool that supports the
|
||||
[Dev Container specification](https://containers.dev/), including:
|
||||
|
||||
- [Dev Container CLI](https://github.com/devcontainers/cli) (`devcontainer up`)
|
||||
- [GitHub Codespaces](https://github.com/features/codespaces)
|
||||
- JetBrains IDEs (with the Dev Containers plugin)
|
||||
|
||||
To use Claude Code from the terminal inside the container:
|
||||
|
||||
```console
|
||||
claude
|
||||
```
|
||||
|
||||
To start directly in YOLO mode from the CLI:
|
||||
|
||||
```console
|
||||
claude --dangerously-skip-permissions
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Firewall blocks a required domain
|
||||
|
||||
If your agent or Composer/npm fails to reach a service, check the firewall
|
||||
logs and add the domain to the dnsmasq allowlist as described above.
|
||||
|
||||
### Container fails to start
|
||||
|
||||
Ensure Docker is running and that you have allocated enough resources
|
||||
(at least 2 GB of RAM for the container). The firewall setup requires
|
||||
`NET_ADMIN` capability, which the Dev Container configures automatically
|
||||
via Docker Compose.
|
||||
@@ -0,0 +1,61 @@
|
||||
# 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`:
|
||||
|
||||
<!-- markdownlint-disable MD010 -->
|
||||
|
||||
```diff
|
||||
-FROM dunglas/frankenphp:1-php8.5 AS frankenphp_upstream
|
||||
+FROM dunglas/frankenphp:1-php8.5-alpine AS frankenphp_upstream
|
||||
|
||||
-SHELL ["/bin/bash", "-euxo", "pipefail", "-c"]
|
||||
+SHELL ["/bin/ash", "-euxo", "-c"]
|
||||
|
||||
-# hadolint ignore=DL3008
|
||||
-RUN <<-EOF
|
||||
- apt-get update
|
||||
- apt-get install -y --no-install-recommends \
|
||||
- file \
|
||||
- git
|
||||
+# hadolint ignore=DL3018
|
||||
+RUN <<-EOF
|
||||
+ apk add --no-cache \
|
||||
+ file \
|
||||
+ git
|
||||
install-php-extensions \
|
||||
|
||||
-# hadolint ignore=DL3008,SC3054,DL4006
|
||||
-RUN <<-'EOF'
|
||||
- apt-get update
|
||||
- apt-get install -y --no-install-recommends libtree
|
||||
+# hadolint ignore=DL3018,SC3054,DL4006
|
||||
+RUN <<-'EOF'
|
||||
+ apk add --no-cache libtree
|
||||
mkdir -p /tmp/libs
|
||||
- BINARIES=(frankenphp php file)
|
||||
- for target in $(printf '%s\n' "${BINARIES[@]}" | xargs -I{} which {}) \
|
||||
+ BINARIES="frankenphp php file"
|
||||
+ for target in $(printf '%s\n' $BINARIES | xargs -I{} which {}) \
|
||||
|
||||
- libtree -pv "$target" 2>/dev/null | grep -oP '(?:── )\K/\S+(?= \[)' | while IFS= read -r lib; do
|
||||
+ libtree -pv "$target" 2>/dev/null | sed -n 's/.*── \(\/[^ ]*\) \[.*/\1/p' | while IFS= read -r lib; do
|
||||
|
||||
- rm -rf /var/lib/apt/lists/*
|
||||
|
||||
-FROM debian:13-slim AS frankenphp_prod
|
||||
+FROM alpine:3 AS frankenphp_prod
|
||||
|
||||
-SHELL ["/bin/bash", "-euxo", "pipefail", "-c"]
|
||||
+SHELL ["/bin/ash", "-euxo", "-c"]
|
||||
|
||||
-COPY --from=frankenphp_prod_builder /usr/lib/file/magic.mgc /usr/lib/file/magic.mgc
|
||||
+COPY --from=frankenphp_prod_builder /usr/share/misc/magic.mgc /usr/share/misc/magic.mgc
|
||||
```
|
||||
|
||||
<!-- markdownlint-enable MD010 -->
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 126 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 159 KiB |
@@ -0,0 +1,81 @@
|
||||
# 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 uncommitted changes.
|
||||
|
||||
```console
|
||||
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:
|
||||
|
||||
```console
|
||||
cp -Rp symfony-docker/. my-existing-project/
|
||||
```
|
||||
|
||||
Enable the Docker support of Symfony Flex:
|
||||
|
||||
```console
|
||||
composer config --json extra.symfony.docker 'true'
|
||||
```
|
||||
|
||||
The [worker mode of FrankenPHP](https://frankenphp.dev/docs/worker/) is enabled by default.
|
||||
To use it with Symfony ≤ 7.3, install the FrankenPHP runtime:
|
||||
|
||||
```console
|
||||
composer require runtime/frankenphp-symfony
|
||||
```
|
||||
|
||||
Then update worker configuration:
|
||||
|
||||
<!-- markdownlint-disable MD010 -->
|
||||
|
||||
```diff
|
||||
worker {
|
||||
file ./public/index.php
|
||||
+ env APP_RUNTIME Runtime\FrankenPhpSymfony\Runtime
|
||||
{$FRANKENPHP_WORKER_CONFIG}
|
||||
}
|
||||
```
|
||||
|
||||
<!-- markdownlint-enable MD010 -->
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> You can disable worker mode by removing the `worker` directive from the `frankenphp`
|
||||
> global option in your `Caddyfile`.
|
||||
|
||||
Re-execute the recipes to update the Docker-related files according to
|
||||
the packages you use:
|
||||
|
||||
```console
|
||||
rm symfony.lock
|
||||
composer recipes:install --force --verbose
|
||||
```
|
||||
|
||||
Double-check the changes, revert the changes that you don't want to keep:
|
||||
|
||||
```console
|
||||
git diff
|
||||
```
|
||||
|
||||
Build the Docker images:
|
||||
|
||||
```console
|
||||
docker compose build --pull --no-cache
|
||||
```
|
||||
|
||||
Start the project!
|
||||
|
||||
```console
|
||||
docker compose up --wait
|
||||
```
|
||||
|
||||
Browse `https://localhost`, your Docker configuration is ready!
|
||||
@@ -0,0 +1,25 @@
|
||||
# Support for Extra Services
|
||||
|
||||
Symfony Docker is extensible.
|
||||
When you install a compatible Composer package using Symfony Flex,
|
||||
the recipe will automatically modify the `Dockerfile` and `compose.yaml` files
|
||||
to fulfill the requirements of this package.
|
||||
|
||||
The currently supported packages are:
|
||||
|
||||
- `symfony/orm-pack`: install a PostgreSQL service
|
||||
- `symfony/mercure-bundle`: use the Mercure.rocks module shipped with Caddy
|
||||
- `symfony/panther`: install Chromium and its 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,129 @@
|
||||
# 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:
|
||||
|
||||
<!-- markdownlint-disable MD010 -->
|
||||
|
||||
```diff
|
||||
gettext \
|
||||
git \
|
||||
+ make \
|
||||
```
|
||||
|
||||
<!-- markdownlint-enable MD010 -->
|
||||
|
||||
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
|
||||
|
||||
<!-- markdownlint-disable MD010 MD013 -->
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
<!-- markdownlint-enable MD010 MD013 -->
|
||||
|
||||
## Adding and Modifying Jobs
|
||||
|
||||
Make sure to add this configuration to the [.editorconfig](/.editorconfig) file,
|
||||
so that it forces your editor to use tabs instead of spaces.
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> Makefiles are not compatible with spaces by default.
|
||||
|
||||
```.editorconfig
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
```
|
||||
|
||||
If you still want to use space, you can configure the prefix in the Makefile itself.
|
||||
See [this answer on Stack Exchange](https://retrocomputing.stackexchange.com/a/20303).
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
# 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:
|
||||
|
||||
```console
|
||||
docker compose exec php composer req symfony/orm-pack
|
||||
```
|
||||
|
||||
## Docker Configuration
|
||||
|
||||
Change the database image to use MySQL instead of PostgreSQL in `compose.yaml`:
|
||||
|
||||
<!-- markdownlint-disable MD013 -->
|
||||
|
||||
```diff
|
||||
###> doctrine/doctrine-bundle ###
|
||||
- image: postgres:${POSTGRES_VERSION:-16}-alpine
|
||||
+ image: mysql:${MYSQL_VERSION:-8.0.32}
|
||||
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 ###
|
||||
```
|
||||
|
||||
<!-- markdownlint-enable MD013 -->
|
||||
|
||||
Depending on the database configuration,
|
||||
modify the environment in the same file at `services.php.environment.DATABASE_URL`:
|
||||
|
||||
```yaml
|
||||
DATABASE_URL: mysql://${MYSQL_USER:-app}:${MYSQL_PASSWORD:-!ChangeMe!}@database:3306/${MYSQL_DATABASE:-app}?serverVersion=${MYSQL_VERSION:-8.0.32}&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.0.32}&charset=${MYSQL_CHARSET:-utf8mb4}
|
||||
```
|
||||
|
||||
## Final steps
|
||||
|
||||
Rebuild the Docker environment:
|
||||
|
||||
```console
|
||||
docker compose down --remove-orphans && docker compose build --pull --no-cache
|
||||
```
|
||||
|
||||
Start the services:
|
||||
|
||||
```console
|
||||
docker compose up --wait
|
||||
```
|
||||
|
||||
Test your setup:
|
||||
|
||||
<!-- markdownlint-disable MD013 -->
|
||||
|
||||
```console
|
||||
docker compose exec php bin/console dbal:run-sql -q "SELECT 1" && echo "OK" || echo "Connection is not working"
|
||||
```
|
||||
|
||||
<!-- markdownlint-enable MD013 -->
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
# 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:
|
||||
|
||||
```console
|
||||
SYMFONY_VERSION=6.4.* docker compose up --wait
|
||||
```
|
||||
|
||||
On Windows:
|
||||
|
||||
```console
|
||||
set SYMFONY_VERSION=6.4.* && docker compose up --wait&set SYMFONY_VERSION=
|
||||
```
|
||||
|
||||
<!-- markdownlint-disable MD010 -->
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> If you're using Symfony 7.3 or earlier with FrankenPHP in worker mode, you also need to follow these steps
|
||||
>
|
||||
> ```console
|
||||
> composer require runtime/frankenphp-symfony
|
||||
> ```
|
||||
>
|
||||
> Add `env APP_RUNTIME Runtime\FrankenPhpSymfony\Runtime` in the `frankenphp/Caddyfile` in the `worker` section.
|
||||
>
|
||||
> ```diff
|
||||
> worker {
|
||||
> file ./public/index.php
|
||||
> + env APP_RUNTIME Runtime\FrankenPhpSymfony\Runtime
|
||||
> {$FRANKENPHP_WORKER_CONFIG}
|
||||
> }
|
||||
> ```
|
||||
|
||||
<!-- markdownlint-enable MD010 -->
|
||||
|
||||
## 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:
|
||||
|
||||
```console
|
||||
STABILITY=dev docker compose up --wait
|
||||
```
|
||||
|
||||
On Windows:
|
||||
|
||||
```console
|
||||
set STABILITY=dev && docker compose up --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.
|
||||
|
||||
```console
|
||||
HTTP_PORT=8000 HTTPS_PORT=4443 HTTP3_PORT=4443 docker compose up --wait
|
||||
```
|
||||
|
||||
to access your application on [https://localhost:4443](https://localhost:4443).
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> Let's Encrypt only supports the standard HTTP and HTTPS ports.
|
||||
> Creating a Let's Encrypt certificate for another port will not work,
|
||||
> you have to use the standard ports or to configure Caddy to use another provider.
|
||||
|
||||
## `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.
|
||||
|
||||
<!-- markdownlint-disable MD013 -->
|
||||
|
||||
| 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 global directives](https://frankenphp.dev/docs/config/#caddyfile-config), one per line | |
|
||||
| `FRANKENPHP_WORKER_CONFIG` | a list of extra [FrankenPHP worker directives](https://frankenphp.dev/docs/config/#caddyfile-config), one per line | |
|
||||
| `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 | |
|
||||
|
||||
<!-- markdownlint-enable MD013 -->
|
||||
|
||||
### Customizing the Server Name
|
||||
|
||||
```console
|
||||
SERVER_NAME="app.localhost" docker compose up --wait
|
||||
```
|
||||
@@ -0,0 +1,140 @@
|
||||
# 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/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
|
||||
# Build fresh production image
|
||||
docker compose -f compose.yaml -f compose.prod.yaml build --pull --no-cache
|
||||
|
||||
# Start container
|
||||
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 --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!
|
||||
|
||||
> [!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 issues.
|
||||
|
||||
## 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 --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/how-tos/environment-variables/set-environment-variables/#use-the-env_file-attribute):
|
||||
|
||||
```yaml
|
||||
# compose.prod.yaml
|
||||
|
||||
services:
|
||||
php:
|
||||
env_file:
|
||||
- .env.prod.local
|
||||
# ...
|
||||
```
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
# 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.
|
||||
|
||||
<!-- markdownlint-disable MD013 -->
|
||||
|
||||
### Linux
|
||||
|
||||
```console
|
||||
docker cp $(docker compose ps -q php):/data/caddy/pki/authorities/local/root.crt /usr/local/share/ca-certificates/root.crt && sudo update-ca-certificates
|
||||
```
|
||||
|
||||
### Mac
|
||||
|
||||
```console
|
||||
docker cp $(docker compose ps -q php):/data/caddy/pki/authorities/local/root.crt /tmp/root.crt && sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /tmp/root.crt
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
```console
|
||||
docker compose cp php:/data/caddy/pki/authorities/local/root.crt %TEMP%/root.crt && certutil -addstore -f "ROOT" %TEMP%/root.crt
|
||||
```
|
||||
|
||||
<!-- markdownlint-enable MD013 -->
|
||||
|
||||
## 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:
|
||||
|
||||
```console
|
||||
mkdir -p frankenphp/certs
|
||||
```
|
||||
|
||||
3. Generate the certificates for your local host (example: "server-name.localhost"):
|
||||
|
||||
<!-- markdownlint-disable MD013 -->
|
||||
|
||||
```console
|
||||
mkcert -cert-file frankenphp/certs/tls.pem -key-file frankenphp/certs/tls.key "server-name.localhost"
|
||||
```
|
||||
|
||||
<!-- markdownlint-enable MD013 -->
|
||||
|
||||
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_EXTRA_CONFIG: |
|
||||
+ https:// {
|
||||
+ tls /etc/caddy/certs/tls.pem /etc/caddy/certs/tls.key
|
||||
+ }
|
||||
# ...
|
||||
volumes:
|
||||
+ - ./frankenphp/certs:/etc/caddy/certs:ro
|
||||
# ...
|
||||
```
|
||||
|
||||
5. Restart your `php` service
|
||||
|
||||
## Disabling HTTPS for Local Development
|
||||
|
||||
To disable HTTPS, configure your environment to use HTTP by setting the following
|
||||
variables and starting the project with this command:
|
||||
|
||||
```console
|
||||
SERVER_NAME=http://localhost \
|
||||
MERCURE_PUBLIC_URL=http://localhost/.well-known/mercure \
|
||||
docker compose up --wait
|
||||
```
|
||||
|
||||
Ensure your application is accessible over HTTP by visiting `http://localhost`
|
||||
in your web browser.
|
||||
@@ -0,0 +1,53 @@
|
||||
# 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 the following command
|
||||
to set yourself as owner of the project files that were created by the Docker container:
|
||||
|
||||
```console
|
||||
docker compose run --rm php chown -R $(id -u):$(id -g) .
|
||||
```
|
||||
|
||||
## TLS/HTTPS Issues
|
||||
|
||||
See the [TLS section](tls.md) for more details.
|
||||
|
||||
## Production Issues
|
||||
|
||||
### How To Properly Build Fresh Images for Production Use
|
||||
|
||||
Remember that, by default, if you run `docker compose up --wait`,
|
||||
only the files `compose.yaml` and `compose.override.yaml` will be used.
|
||||
See ["How Compose works"](https://docs.docker.com/compose/intro/compose-application-model)
|
||||
and ["Merge Compose files"](https://docs.docker.com/compose/how-tos/multiple-compose-files/merge).
|
||||
|
||||
If you need to build images for production environment, you have to use the following
|
||||
command:
|
||||
|
||||
```console
|
||||
docker compose -f compose.yaml -f compose.prod.yaml build --pull --no-cache
|
||||
```
|
||||
|
||||
### Building Dev and Prod Images
|
||||
|
||||
Dev and prod images use distinct image names (`app-php-dev` and `app-php-prod`),
|
||||
so they won't conflict with each other.
|
||||
|
||||
To build and start the dev image:
|
||||
|
||||
```console
|
||||
docker compose up --wait
|
||||
```
|
||||
|
||||
To build and start the prod image:
|
||||
|
||||
```console
|
||||
docker compose -f compose.yaml -f compose.prod.yaml build --pull --no-cache
|
||||
docker compose -f compose.yaml -f compose.prod.yaml up --wait
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
>
|
||||
> The order of `-f` arguments matters.
|
||||
@@ -0,0 +1,19 @@
|
||||
# Updating Your Project
|
||||
|
||||
To import the changes made to the _Symfony Docker_ template into your project,
|
||||
we recommend using [_template-sync_](https://github.com/coopTilleuls/template-sync):
|
||||
|
||||
1. Run the script to synchronize your project with the latest version of the skeleton:
|
||||
|
||||
<!-- markdownlint-disable MD013 -->
|
||||
|
||||
```console
|
||||
curl -sSL https://raw.githubusercontent.com/coopTilleuls/template-sync/main/template-sync.sh | sh -s -- https://github.com/dunglas/symfony-docker
|
||||
```
|
||||
|
||||
<!-- markdownlint-enable MD013 -->
|
||||
|
||||
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,98 @@
|
||||
# Using Xdebug
|
||||
|
||||
The default development image is shipped with [Xdebug](https://xdebug.org/),
|
||||
a popular debugger and profiler for PHP.
|
||||
|
||||
When using [Dev Containers](https://containers.dev/), Xdebug is pre-configured and works out of the box.
|
||||
Open the **Run and Debug** panel in Visual Studio Code and start the **Debug PHP** launch configuration, then set your breakpoints and load a page.
|
||||
|
||||
For other setups, because it has a significant performance overhead, the step-by-step debugger
|
||||
is disabled by default.
|
||||
It can be enabled by including `debug` in the values of the `XDEBUG_MODE` environment variable.
|
||||
|
||||
On Linux and Mac:
|
||||
|
||||
```console
|
||||
XDEBUG_MODE=develop,debug docker compose up --wait
|
||||
```
|
||||
|
||||
On Windows:
|
||||
|
||||
```console
|
||||
set XDEBUG_MODE=develop,debug&& docker compose up --wait&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 the 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
|
||||
above.
|
||||
|
||||
Example:
|
||||
|
||||
```console
|
||||
XDEBUG_SESSION=1 PHP_IDE_CONFIG="serverName=symfony" php bin/console ...
|
||||
```
|
||||
|
||||
## Debugging with Xdebug and Visual Studio Code
|
||||
|
||||
1. Install necessary [PHP extension for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=DEVSENSE.phptools-vscode).
|
||||
2. Add [debug configuration](https://code.visualstudio.com/docs/debugtest/debugging-configuration#_launch-configurations)
|
||||
into your `.vscode\launch.json` file.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug PHP",
|
||||
"type": "php",
|
||||
"request": "launch",
|
||||
"pathMappings": {
|
||||
"/app": "${workspaceFolder}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
3. Use [Run and Debug](https://code.visualstudio.com/docs/debugtest/debugging#_start-a-debugging-session)
|
||||
options and run `Debug PHP` to listen for upcoming connections
|
||||
with [the **Xdebug extension**](https://xdebug.org/docs/step_debug#browser-extensions)
|
||||
installed and active.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Inspect the installation with the following command.
|
||||
The Xdebug version should be displayed.
|
||||
|
||||
```console
|
||||
$ docker compose exec php php --version
|
||||
|
||||
PHP ...
|
||||
with Xdebug v3.x.x ...
|
||||
```
|
||||
@@ -0,0 +1,66 @@
|
||||
{
|
||||
skip_install_trust
|
||||
|
||||
{$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 {
|
||||
# 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 {
|
||||
{$FRANKENPHP_SITE_CONFIG}
|
||||
|
||||
worker {
|
||||
file ./public/index.php
|
||||
{$FRANKENPHP_WORKER_CONFIG}
|
||||
}
|
||||
}
|
||||
|
||||
file_server {
|
||||
hide *.php
|
||||
}
|
||||
}
|
||||
@@ -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 = 32531
|
||||
opcache.memory_consumption = 256
|
||||
opcache.enable_file_override = 1
|
||||
@@ -0,0 +1,5 @@
|
||||
; See https://docs.docker.com/desktop/features/networking/networking-how-tos/#connect-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,5 @@
|
||||
; https://symfony.com/doc/current/performance.html#use-the-opcache-class-preloading
|
||||
opcache.preload_user = www-data
|
||||
opcache.preload = /app/config/preload.php
|
||||
; https://symfony.com/doc/current/performance.html#don-t-check-php-files-timestamps
|
||||
opcache.validate_timestamps = 0
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
if [ "$1" = 'frankenphp' ] || [ "$1" = 'php' ] || [ "$1" = 'bin/console' ]; then
|
||||
|
||||
if [ -z "$(ls -A 'vendor/' 2>/dev/null)" ]; then
|
||||
composer install --prefer-dist --no-progress --no-interaction
|
||||
fi
|
||||
|
||||
# Display information about the current project
|
||||
# Or about an error in project initialization
|
||||
php bin/console -V
|
||||
|
||||
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
|
||||
|
||||
echo 'PHP app ready!'
|
||||
fi
|
||||
|
||||
exec docker-php-entrypoint "$@"
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
use App\Kernel;
|
||||
|
||||
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
|
||||
|
||||
return static function (array $context) {
|
||||
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
|
||||
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
|
||||
|
||||
class Kernel extends BaseKernel
|
||||
{
|
||||
use MicroKernelTrait;
|
||||
|
||||
/**
|
||||
* @return list<string> An array of allowed values for APP_ENV
|
||||
*/
|
||||
private function getAllowedEnvs(): array
|
||||
{
|
||||
return ['prod', 'dev', 'test'];
|
||||
}
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"doctrine/deprecations": {
|
||||
"version": "1.1",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "1.0",
|
||||
"ref": "fdd756167454623e21f1d769c5b814b243782a67"
|
||||
}
|
||||
},
|
||||
"symfony/console": {
|
||||
"version": "8.1",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "5.3",
|
||||
"ref": "1781ff40d8a17d87cf53f8d4cf0c8346ed2bb461"
|
||||
},
|
||||
"files": [
|
||||
"bin/console"
|
||||
]
|
||||
},
|
||||
"symfony/flex": {
|
||||
"version": "2.11",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "2.4",
|
||||
"ref": "52e9754527a15e2b79d9a610f98185a1fe46622a"
|
||||
},
|
||||
"files": [
|
||||
".env",
|
||||
".env.dev"
|
||||
]
|
||||
},
|
||||
"symfony/framework-bundle": {
|
||||
"version": "8.1",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "8.1",
|
||||
"ref": "312027aea160796a50bf2d185503afdb5d71f570"
|
||||
},
|
||||
"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",
|
||||
".editorconfig"
|
||||
]
|
||||
},
|
||||
"symfony/maker-bundle": {
|
||||
"version": "1.67",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "1.0",
|
||||
"ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
|
||||
}
|
||||
},
|
||||
"symfony/property-info": {
|
||||
"version": "8.1",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "7.3",
|
||||
"ref": "dae70df71978ae9226ae915ffd5fad817f5ca1f7"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/property_info.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/routing": {
|
||||
"version": "8.1",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "7.4",
|
||||
"ref": "bc94c4fd86f393f3ab3947c18b830ea343e51ded"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/routing.yaml",
|
||||
"config/routes.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/security-bundle": {
|
||||
"version": "8.1",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "7.4",
|
||||
"ref": "c42fee7802181cdd50f61b8622715829f5d2335c"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/security.yaml",
|
||||
"config/routes/security.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/twig-bundle": {
|
||||
"version": "8.1",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "6.4",
|
||||
"ref": "f250159ebe99153d0c640a3e7742876fc7453f2c"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/twig.yaml",
|
||||
"templates/base.html.twig"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}Welcome!{% endblock %}</title>
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
|
||||
{% block stylesheets %}
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
{% endblock %}
|
||||
|
||||
{% set frankenphpHotReload = app.request.server.get('FRANKENPHP_HOT_RELOAD') %}
|
||||
{% if frankenphpHotReload %}
|
||||
<meta name="frankenphp-hot-reload:url" content="{{ frankenphpHotReload }}">
|
||||
<script src="https://cdn.jsdelivr.net/npm/idiomorph"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/frankenphp-hot-reload/+esm" type="module"></script>
|
||||
{% endif %}
|
||||
</head>
|
||||
<body>
|
||||
{% block body %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user