diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..cb3e39c --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,81 @@ +--- +name: CVE Analysis + +on: + push: + branches: [main, dev] + pull_request: + branches: [main, dev] + workflow_dispatch: {} + +jobs: + analyze: + name: Upstream Images Scan + runs-on: ubuntu-latest + environment: "open source" + + permissions: + contents: read + pull-requests: write + + env: + DOCKER_USER: ${{ secrets.DOCKER_USER }} + DOCKER_PAT: ${{ secrets.DOCKER_PAT }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ env.DOCKER_USER }} + password: ${{ env.DOCKER_PAT }} + + - name: Scan FrankenPHP Upstream + uses: docker/scout-action@v1 + with: + command: cves + image: dunglas/frankenphp:1-php8.5 + only-severities: critical,high + exit-code: false + write-comment: true + github-token: ${{ secrets.GITHUB_TOKEN }} + output: frankenphp-report.md + + - name: Scan Debian Base + uses: docker/scout-action@v1 + with: + command: cves + image: debian:13-slim + only-severities: critical,high + exit-code: false + write-comment: true + github-token: ${{ secrets.GITHUB_TOKEN }} + output: debian-report.md + + - name: Publish Results to Summary + if: always() + run: | + { + echo "# 🛡️ CVE Analysis Summary" + echo "Scan performed on $(date +'%Y-%m-%d %H:%M')" + echo "" + if [ -s frankenphp-report.md ]; then + echo "## 🐘 FrankenPHP Upstream" + echo "" + cat frankenphp-report.md + echo "" + fi + if [ -s debian-report.md ]; then + echo "## 🐧 Debian Base" + echo "" + cat debian-report.md + echo "" + fi + if [ ! -s frankenphp-report.md ] && [ ! -s debian-report.md ]; then + echo "> ✅ Reports were integrated directly by Docker Scout above." + fi + } >> "$GITHUB_STEP_SUMMARY" \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 046b866..2f456a3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -70,6 +70,7 @@ RUN <<-EOF iptables \ jq \ sudo + install-php-extensions xdebug rm -rf /var/lib/apt/lists/* useradd -m -s /bin/bash nonroot @@ -91,22 +92,28 @@ 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 -EOF +COPY --link src/composer.* /app/src/ +RUN composer install \ + --working-dir=/app/src \ + --no-cache \ + --prefer-dist \ + --no-dev \ + --no-autoloader \ + --no-scripts \ + --no-progress + +COPY --link src/ /app/src/ + +RUN composer dump-autoload \ + --working-dir=/app/src \ + --classmap-authoritative \ + --no-dev # 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 pstree procps net- + apt-get install -y --no-install-recommends libtree mkdir -p /tmp/libs BINARIES=(frankenphp php file) touch my_log.txt @@ -141,11 +148,7 @@ COPY --from=frankenphp_prod_builder /usr/local/etc/php/php.ini /usr/local/etc/ph 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 /usr/bin/file /usr/bin/file -COPY --from=frankenphp_prod_builder /usr/lib/file/magic.mgc /usr/lib/file/magic.mgc ENV XDG_CONFIG_HOME=/config XDG_DATA_HOME=/data @@ -156,7 +159,7 @@ RUN <<-EOF find / -perm /6000 -type f -exec chmod a-s {} + 2>/dev/null || true EOF -COPY --link --exclude=var --from=frankenphp_prod_builder /app /app +COPY --link --from=frankenphp_prod_builder /app /app COPY --chown=www-data:www-data --from=frankenphp_prod_builder /app/src/logs /app/src/logs COPY --link --chmod=755 frankenphp/docker-entrypoint.sh /usr/local/bin/docker-entrypoint diff --git a/LICENSE b/LICENSE index 38a3b3c..20e2ae1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017-2025 Laurent LEGAZ +Copyright (c) 2026 Laurent LEGAZ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index e400081..add0e28 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![CI](https://github.com/llegaz/frankenphp-slim/actions/workflows/ci.yaml/badge.svg)](https://github.com/llegaz/frankenphp-slim/actions/workflows/ci.yaml) -This project is largely inspired from [Kévin Dunglas](https://dunglas.dev)'s project Symfony Docker. it aims to provide a ready to use install for a slim project using frankenPHP server and vulcain / mercure technologies for SSE as well. +This project is largely inspired from [Kévin Dunglas](https://dunglas.dev)'s project [Symfony Docker](https://github.com/dunglas/symfony-docker), it aims to provide a ready to use install for a slim project using frankenPHP server and vulcain / mercure technologies for SSE and hot reloading. ## Getting Started @@ -19,7 +19,7 @@ This project is largely inspired from [Kévin Dunglas](https://dunglas.dev)'s pr 4. Open `https://localhost` in your favorite web browser 5. Run `docker compose down --remove-orphans` to stop the Docker containers. -## Set the freshly generated Caddy certificate into your local browser +## Add the authority to the trust store of the host ```bash docker cp :/data/caddy/pki/authorities/local/root.crt ./caddy-root.crt ``` @@ -50,15 +50,91 @@ sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keyc - [Vulcain](https://vulcain.rocks) support - [Hot Reloading](https://frankenphp.dev/docs/hot-reload/) - Rootless, slim production image -- This project should have a native [XDebug](docs/xdebug.md) integration (but I did not test it yet) +- This project should have a native [XDebug](docs/xdebug.md) integration (sole point that I did not test here yet) **Enjoy!** +## 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:/.git +``` + +Go into the directory containing your project (``), +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=Key \ +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 + # ... +``` + ## License frankenphp-slim is available under the MIT License. ## Credits -By [Laurent Legaz](http://laurent.legaz.eu), largely inspired from [Kévin Dunglas](https://dunglas.dev)'s project Symfony Docker. +By [Laurent Legaz](http://laurent.legaz.eu), largely inspired from [Kévin Dunglas](https://dunglas.dev)'s project [Symfony Docker](https://github.com/dunglas/symfony-docker).