diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..c592f47ef --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "weekly" + groups: + docker-updates: + update-types: + - "patch" + - "minor" diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 000000000..1b13f32ec --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,84 @@ +name: Test & build Docker image + +on: + push: + branches: [master] + tags: ["*"] + pull_request: + schedule: + - cron: "0 2 * * 6" + +env: + IMAGE_NAME: trafex/php-nginx + IMAGE_TAG: ${{ github.sha }} + DOCKER_BUILDKIT: 1 + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3 + + - name: Build image + run: |- + docker build -t $IMAGE_NAME:$IMAGE_TAG . + + - name: Smoke test image + run: |- + docker compose -f docker-compose.test.yml up -d app + sleep 2 + docker compose -f docker-compose.test.yml run sut + + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@master + with: + image-ref: "${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}" + format: "template" + template: "@/contrib/sarif.tpl" + output: "trivy-results.sarif" + + - name: Upload Trivy scan results to GitHub Security tab + if: github.ref == 'refs/heads/master' && (github.event_name == 'push' || github.event_name == 'schedule') + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: "trivy-results.sarif" + + - name: Login to Docker Hub + if: (github.ref == 'refs/heads/master' && (github.event_name == 'push' || github.event_name == 'schedule' )) || contains(github.ref, 'refs/tags/') + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build multi-arch image and push latest tag + if: github.ref == 'refs/heads/master' && (github.event_name == 'push' || github.event_name == 'schedule') + run: |- + docker buildx build \ + --cache-from=$IMAGE_NAME:latest \ + --push \ + -t $IMAGE_NAME:latest \ + --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 \ + . + + - name: Set tag in environment + if: contains(github.ref, 'refs/tags/') + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + + - name: Build multi-arch image and push release tag + if: contains(github.ref, 'refs/tags/') + run: |- + docker buildx build \ + --cache-from=$IMAGE_NAME:latest \ + --push \ + -t $IMAGE_NAME:$RELEASE_VERSION \ + --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 \ + . diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml deleted file mode 100644 index 332968243..000000000 --- a/.github/workflows/deploy.yaml +++ /dev/null @@ -1,63 +0,0 @@ -name: Test & build Docker image - -on: - push: - branches: [ master ] - tags: ['*'] - pull_request: - -env: - IMAGE_NAME: trafex/php-nginx - -jobs: - deploy: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Build image - run: |- - docker build -t $IMAGE_NAME . - docker tag $IMAGE_NAME:latest $IMAGE_NAME:${{ github.sha }} - - - name: Smoke test image - run: |- - docker-compose -f docker-compose.test.yml up -d app - sleep 2 - docker-compose -f docker-compose.test.yml run sut - - - name: Run Trivy vulnerability scanner - uses: aquasecurity/trivy-action@master - with: - image-ref: '${{ env.IMAGE_NAME }}:${{ github.sha }}' - format: 'template' - template: '@/contrib/sarif.tpl' - output: 'trivy-results.sarif' - - - name: Upload Trivy scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@v1 - with: - sarif_file: 'trivy-results.sarif' - - - name: Login to Docker Hub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Push latest image - if: github.ref == 'refs/heads/master' && github.event_name == 'push' - run: |- - docker push $IMAGE_NAME:latest - - - name: Set tag in environment - if: contains(github.ref, 'refs/tags/') - run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - - - name: Push tagged image - if: contains(github.ref, 'refs/tags/') - run: |- - docker tag $IMAGE_NAME:${{ github.sha }} $IMAGE_NAME:$RELEASE_VERSION - docker push $IMAGE_NAME:$RELEASE_VERSION diff --git a/.github/workflows/dockerhub-description.yaml b/.github/workflows/dockerhub-description.yaml new file mode 100644 index 000000000..1859be702 --- /dev/null +++ b/.github/workflows/dockerhub-description.yaml @@ -0,0 +1,21 @@ +name: Update Docker Hub Description +on: + push: + branches: + - master + paths: + - README.md + - .github/workflows/dockerhub-description.yml +jobs: + dockerHubDescription: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Docker Hub Description + uses: peter-evans/dockerhub-description@v4 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + repository: trafex/php-nginx + short-description: ${{ github.event.repository.description }} diff --git a/Dockerfile b/Dockerfile index d2d133741..5a7c5808a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,57 +1,56 @@ -FROM alpine:3.14 +ARG ALPINE_VERSION=3.21 +FROM alpine:${ALPINE_VERSION} LABEL Maintainer="Tim de Pater " -LABEL Description="Lightweight container with Nginx 1.20 & PHP 8.0 based on Alpine Linux." +LABEL Description="Lightweight container with Nginx 1.26 & PHP 8.4 based on Alpine Linux." +# Setup document root +WORKDIR /var/www/html # Install packages and remove default server definition -RUN apk --no-cache add \ +RUN apk add --no-cache \ curl \ nginx \ - php8 \ - php8-ctype \ - php8-curl \ - php8-dom \ - php8-fpm \ - php8-gd \ - php8-intl \ - php8-json \ - php8-mbstring \ - php8-mysqli \ - php8-opcache \ - php8-openssl \ - php8-phar \ - php8-session \ - php8-xml \ - php8-xmlreader \ - php8-zlib \ + php84 \ + php84-ctype \ + php84-curl \ + php84-dom \ + php84-fileinfo \ + php84-fpm \ + php84-gd \ + php84-intl \ + php84-mbstring \ + php84-mysqli \ + php84-opcache \ + php84-openssl \ + php84-phar \ + php84-session \ + php84-tokenizer \ + php84-xml \ + php84-xmlreader \ + php84-xmlwriter \ supervisor -# Create symlink so programs depending on `php` still function -RUN ln -s /usr/bin/php8 /usr/bin/php +RUN ln -s /usr/bin/php84 /usr/bin/php -# Configure nginx +# Configure nginx - http COPY config/nginx.conf /etc/nginx/nginx.conf +# Configure nginx - default server +COPY config/conf.d /etc/nginx/conf.d/ # Configure PHP-FPM -COPY config/fpm-pool.conf /etc/php8/php-fpm.d/www.conf -COPY config/php.ini /etc/php8/conf.d/custom.ini +ENV PHP_INI_DIR /etc/php84 +COPY config/fpm-pool.conf ${PHP_INI_DIR}/php-fpm.d/www.conf +COPY config/php.ini ${PHP_INI_DIR}/conf.d/custom.ini # Configure supervisord COPY config/supervisord.conf /etc/supervisor/conf.d/supervisord.conf -# Setup document root -RUN mkdir -p /var/www/html - # Make sure files/folders needed by the processes are accessable when they run under the nobody user -RUN chown -R nobody.nobody /var/www/html && \ - chown -R nobody.nobody /run && \ - chown -R nobody.nobody /var/lib/nginx && \ - chown -R nobody.nobody /var/log/nginx +RUN chown -R nobody:nobody /var/www/html /run /var/lib/nginx /var/log/nginx # Switch to use a non-root user from here on USER nobody # Add application -WORKDIR /var/www/html COPY --chown=nobody src/ /var/www/html/ # Expose the port nginx is reachable on @@ -61,4 +60,4 @@ EXPOSE 8080 CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"] # Configure a healthcheck to validate that everything is up&running -HEALTHCHECK --timeout=10s CMD curl --silent --fail http://127.0.0.1:8080/fpm-ping +HEALTHCHECK --timeout=10s CMD curl --silent --fail http://127.0.0.1:8080/fpm-ping || exit 1 diff --git a/README.md b/README.md index 749285dfb..5873002dd 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ -# Docker PHP-FPM 8.0 & Nginx 1.20 on Alpine Linux -Example PHP-FPM 8.0 & Nginx 1.20 container image for Docker, build on [Alpine Linux](https://www.alpinelinux.org/). +# Docker PHP-FPM 8.4 & Nginx 1.26 on Alpine Linux +Example PHP-FPM 8.4 & Nginx 1.26 container image for Docker, built on [Alpine Linux](https://www.alpinelinux.org/). Repository: https://github.com/TrafeX/docker-php-nginx * Built on the lightweight and secure Alpine Linux distribution +* Multi-platform, supporting AMD4, ARMv6, ARMv7, ARM64 * Very small Docker image size (+/-40MB) -* Uses PHP 8.0 for better performance, lower CPU usage & memory footprint +* Uses PHP 8.4 for the best performance, low CPU usage & memory footprint * Optimized for 100 concurrent users * Optimized to only use resources when there's traffic (by using PHP-FPM's `on-demand` process manager) * The services Nginx, PHP-FPM and supervisord run under a non-privileged user (nobody) to make it more secure @@ -14,10 +15,14 @@ Repository: https://github.com/TrafeX/docker-php-nginx * Follows the KISS principle (Keep It Simple, Stupid) to make it easy to understand and adjust the image to your needs [![Docker Pulls](https://img.shields.io/docker/pulls/trafex/php-nginx.svg)](https://hub.docker.com/r/trafex/php-nginx/) -![nginx 1.18.0](https://img.shields.io/badge/nginx-1.20-brightgreen.svg) -![php 8.0](https://img.shields.io/badge/php-8.0-brightgreen.svg) +![nginx 1.26](https://img.shields.io/badge/nginx-1.26-brightgreen.svg) +![php 8.4](https://img.shields.io/badge/php-8.4-brightgreen.svg) ![License MIT](https://img.shields.io/badge/license-MIT-blue.svg) +## [![Trafex Consultancy](https://timdepater.com/logo/mini-logo.png)](https://timdepater.com?mtm_campaign=github) +I can help you with [Containerization, Kubernetes, Monitoring, Infrastructure as Code and other DevOps challenges](https://timdepater.com/?mtm_campaign=github). + + ## Goal of this project The goal of this container image is to provide an example for running Nginx and PHP-FPM in a container which follows the best practices and is easy to understand and modify to your needs. @@ -34,11 +39,9 @@ Or mount your own code to be served by PHP-FPM & Nginx docker run -p 80:8080 -v ~/my-codebase:/var/www/html trafex/php-nginx -### Docker Hub repository name change -Since we switched to PHP8 the repository name [trafex/alpine-nginx-php7](https://hub.docker.com/r/trafex/alpine-nginx-php7) didn't make sense anymore. -Because you can't change the name of the repository on Docker Hub I created a new one. - -From now on this image can be pulled from Docker Hub under the name [trafex/php-nginx](https://hub.docker.com/r/trafex/php-nginx). +## Versioning +Major or minor changes are always published as a [release](https://github.com/TrafeX/docker-php-nginx/releases) with correspondending changelogs. +The `latest` tag is automatically updated weekly to include the latests patches from Alpine Linux. ## Configuration In [config/](config/) you'll find the default configuration files for Nginx, PHP and PHP-FPM. @@ -50,48 +53,18 @@ Nginx configuration: PHP configuration: - docker run -v "`pwd`/php-setting.ini:/etc/php7/conf.d/settings.ini" trafex/php-nginx + docker run -v "`pwd`/php-setting.ini:/etc/php84/conf.d/settings.ini" trafex/php-nginx PHP-FPM configuration: - docker run -v "`pwd`/php-fpm-settings.conf:/etc/php7/php-fpm.d/server.conf" trafex/php-nginx + docker run -v "`pwd`/php-fpm-settings.conf:/etc/php84/php-fpm.d/server.conf" trafex/php-nginx _Note; Because `-v` requires an absolute path I've added `pwd` in the example to return the absolute path to the current directory_ +## Documentation and examples +To modify this container to your specific needs please see the following examples; -## Adding composer - -If you need [Composer](https://getcomposer.org/) in your project, here's an easy way to add it. - -```Dockerfile -FROM trafex/php-nginx:latest - -# Install composer from the official image -COPY --from=composer /usr/bin/composer /usr/bin/composer - -# Run composer install to install the dependencies -RUN composer install --optimize-autoloader --no-interaction --no-progress -``` - -### Building with composer - -If you are building an image with source code in it and dependencies managed by composer then the definition can be improved. -The dependencies should be retrieved by the composer but the composer itself (`/usr/bin/composer`) is not necessary to be included in the image. - -```Dockerfile -FROM composer AS composer - -# copying the source directory and install the dependencies with composer -COPY / /app - -# run composer install to install the dependencies -RUN composer install \ - --optimize-autoloader \ - --no-interaction \ - --no-progress - -# continue stage build with the desired image and copy the source including the -# dependencies downloaded by composer -FROM trafex/php-nginx -COPY --chown=nginx --from=composer /app /var/www/html -``` +* [Adding xdebug support](https://github.com/TrafeX/docker-php-nginx/blob/master/docs/xdebug-support.md) +* [Adding composer](https://github.com/TrafeX/docker-php-nginx/blob/master/docs/composer-support.md) +* [Getting the real IP of the client behind a load balancer](https://github.com/TrafeX/docker-php-nginx/blob/master/docs/real-ip-behind-loadbalancer.md) +* [Sending e-mails](https://github.com/TrafeX/docker-php-nginx/blob/master/docs/sending-emails.md) \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md index f3b0abca3..2672b40fa 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,7 +5,8 @@ Only the latest version will be supported and receive security updates. | Version | Supported | | ------- | ------------------ | -| 2.x.x | :white_check_mark: | +| 3.x.x | :white_check_mark: | +| 2.x.x | :x: | | 1.x.x | :x: | ## Reporting a Vulnerability diff --git a/config/conf.d/default.conf b/config/conf.d/default.conf new file mode 100644 index 000000000..e0920f54f --- /dev/null +++ b/config/conf.d/default.conf @@ -0,0 +1,56 @@ +# Default server definition +server { + listen [::]:8080 default_server; + listen 8080 default_server; + server_name _; + + sendfile off; + tcp_nodelay on; + absolute_redirect off; + + root /var/www/html; + index index.php index.html; + + location / { + # First attempt to serve request as file, then + # as directory, then fall back to index.php + try_files $uri $uri/ /index.php$is_args$args; + } + + # Redirect server error pages to the static page /50x.html + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /var/lib/nginx/html; + } + + # Pass the PHP scripts to PHP-FPM listening on php-fpm.sock + location ~ \.php$ { + try_files $uri =404; + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:/run/php-fpm.sock; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_index index.php; + include fastcgi_params; + } + + # Set the cache-control headers on assets to cache for 5 days + location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ { + expires 5d; + } + + # Deny access to . files, for security + location ~ /\. { + log_not_found off; + deny all; + } + + # Allow fpm ping and status from localhost + location ~ ^/(fpm-status|fpm-ping)$ { + access_log off; + allow 127.0.0.1; + deny all; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + include fastcgi_params; + fastcgi_pass unix:/run/php-fpm.sock; + } +} diff --git a/config/fpm-pool.conf b/config/fpm-pool.conf index d4692868f..4be20613c 100644 --- a/config/fpm-pool.conf +++ b/config/fpm-pool.conf @@ -13,7 +13,7 @@ error_log = /dev/stderr ; (IPv6 and IPv4-mapped) on a specific port; ; '/path/to/unix/socket' - to listen on a unix socket. ; Note: This value is mandatory. -listen = 127.0.0.1:9000 +listen = /run/php-fpm.sock ; Enable status page pm.status_path = /fpm-status diff --git a/config/nginx.conf b/config/nginx.conf index 7e906596b..206334e31 100644 --- a/config/nginx.conf +++ b/config/nginx.conf @@ -8,6 +8,7 @@ events { http { include mime.types; + # Threat files with a unknown filetype as binary default_type application/octet-stream; # Define custom log format to include reponse times @@ -28,67 +29,19 @@ http { uwsgi_temp_path /tmp/uwsgi_temp; scgi_temp_path /tmp/scgi_temp; - # Default server definition - server { - listen [::]:8080 default_server; - listen 8080 default_server; - server_name _; + # Hide headers that identify the server to prevent information leakage + proxy_hide_header X-Powered-By; + fastcgi_hide_header X-Powered-By; + server_tokens off; - sendfile off; - - root /var/www/html; - index index.php index.html; - - location / { - # First attempt to serve request as file, then - # as directory, then fall back to index.php - try_files $uri $uri/ /index.php?q=$uri&$args; - } - - # Redirect server error pages to the static page /50x.html - error_page 500 502 503 504 /50x.html; - location = /50x.html { - root /var/lib/nginx/html; - } - - # Pass the PHP scripts to PHP-FPM listening on 127.0.0.1:9000 - location ~ \.php$ { - try_files $uri =404; - fastcgi_split_path_info ^(.+\.php)(/.+)$; - fastcgi_pass 127.0.0.1:9000; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param SCRIPT_NAME $fastcgi_script_name; - fastcgi_index index.php; - include fastcgi_params; - } - - location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ { - expires 5d; - } - - # Deny access to . files, for security - location ~ /\. { - log_not_found off; - deny all; - } - - # Allow fpm ping and status from localhost - location ~ ^/(fpm-status|fpm-ping)$ { - access_log off; - allow 127.0.0.1; - deny all; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - include fastcgi_params; - fastcgi_pass 127.0.0.1:9000; - } - } - + # Enable gzip compression by default gzip on; gzip_proxied any; - gzip_types text/plain application/xml text/css text/js text/xml application/x-javascript text/javascript application/json application/xml+rss; + # Based on CloudFlare's recommended settings + gzip_types text/richtext text/plain text/css text/x-script text/x-component text/x-java-source text/x-markdown application/javascript application/x-javascript text/javascript text/js image/x-icon image/vnd.microsoft.icon application/x-perl application/x-httpd-cgi text/xml application/xml application/rss+xml application/vnd.api+json application/x-protobuf application/json multipart/bag multipart/mixed application/xhtml+xml font/ttf font/otf font/x-woff image/svg+xml application/vnd.ms-fontobject application/ttf application/x-ttf application/otf application/x-otf application/truetype application/opentype application/x-opentype application/font-woff application/eot application/font application/font-sfnt application/wasm application/javascript-binast application/manifest+json application/ld+json application/graphql+json application/geo+json; gzip_vary on; gzip_disable "msie6"; - - # Include other server configs + + # Include server configs include /etc/nginx/conf.d/*.conf; } diff --git a/config/php.ini b/config/php.ini index 7bb1be5ea..d85d12acf 100644 --- a/config/php.ini +++ b/config/php.ini @@ -1,2 +1,3 @@ [Date] date.timezone="UTC" +expose_php= Off \ No newline at end of file diff --git a/config/supervisord.conf b/config/supervisord.conf index 216a38797..0922e2fd5 100644 --- a/config/supervisord.conf +++ b/config/supervisord.conf @@ -5,7 +5,7 @@ logfile_maxbytes=0 pidfile=/run/supervisord.pid [program:php-fpm] -command=php-fpm8 -F +command=php-fpm84 -F stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr diff --git a/docker-compose.test.yml b/docker-compose.test.yml index bc43092a9..3665aae06 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -1,9 +1,9 @@ -version: '3.5' services: app: + image: ${IMAGE_NAME}:${IMAGE_TAG} build: . sut: - image: alpine:3.13 + image: alpine:3.21 depends_on: - app command: /tmp/run_tests.sh diff --git a/docs/composer-support.md b/docs/composer-support.md new file mode 100644 index 000000000..784a3836c --- /dev/null +++ b/docs/composer-support.md @@ -0,0 +1,35 @@ +# Adding composer + +If you need [Composer](https://getcomposer.org/) in your project, here's an easy way to add it. + +```Dockerfile +FROM trafex/php-nginx:latest + +# Install composer from the official image +COPY --from=composer /usr/bin/composer /usr/bin/composer + +# Run composer install to install the dependencies +RUN composer install --optimize-autoloader --no-interaction --no-progress +``` + +## Building with composer + +If you are building an image with source code in it and dependencies managed by composer then the definition can be improved. +The dependencies should be retrieved by the composer but the composer itself (`/usr/bin/composer`) is not necessary to be included in the image. + +```Dockerfile +FROM composer AS composer + +# Copying the source directory and install the dependencies with composer +COPY / /app + +# Run composer install to install the dependencies +RUN composer install \ + --optimize-autoloader \ + --no-interaction \ + --no-progress + +# Continue stage build with the desired image and copy the source including the dependencies downloaded by composer +FROM trafex/php-nginx:latest +COPY --chown=nginx --from=composer /app /var/www/html +``` diff --git a/docs/enable-https.md b/docs/enable-https.md new file mode 100644 index 000000000..d5f8cb69c --- /dev/null +++ b/docs/enable-https.md @@ -0,0 +1,59 @@ +# Adding support for HTTPS/SSL + +> All the following instructions should be adapted to your personal needs + +If your plan to work locally only, first generate your self-signed cert and key: + +```bash +openssl req -x509 -nodes -newkey rsa:2048 -keyout https.key -out https.crt -subj "/CN=localhost" -days 5000 +``` + +Then copy your cert files on build stage of your Dockerfile: + +```Dockerfile +FROM trafex/php-nginx:latest + +# ... + +COPY https.crt /etc/nginx/ssl/default.crt +COPY https.key /etc/nginx/ssl/default.key + +# ... + +``` + +Edit your nginx.conf file. + +> Check [Nginx configuration](../config/nginx.conf) for more help: + + +```nginx +server { + listen [::]:443 ssl; + listen 443 ssl; + server_name localhost; + root /var/www/html/public; + + ssl_certificate /etc/nginx/ssl/default.crt; + ssl_certificate_key /etc/nginx/ssl/default.key; + + # ... the rest here +} +``` + +If you use docker-compose here is an example: + +```yaml + php-nginx: + build: ./api + networks: [ backend ] + ports: [ "443:443" ] + working_dir: /var/www/html + volumes: + - ./api:/var/www/html + - ./api/nginx.conf:/etc/nginx/conf.d/default.conf + restart: on-failure + +``` + +Finally rebuild and restart your docker/compose. diff --git a/docs/real-ip-behind-loadbalancer.md b/docs/real-ip-behind-loadbalancer.md new file mode 100644 index 000000000..47d72a2c1 --- /dev/null +++ b/docs/real-ip-behind-loadbalancer.md @@ -0,0 +1,13 @@ +# Getting the real IP of the client behind a load balancer +If you use this container behind a proxy or load balancer you might want to get the real IP of the client instead of the IP of the proxy or load balancer. + +To do this you can add the following configuration to the [Nginx configuration](../config/nginx.conf): + +```nginx +set_real_ip_from + +real_ip_header X-Forwarded-For; +real_ip_recursive on; +``` + +Where `` is the CIDR of your proxy or load balancer, see the [Nginx documentation](http://nginx.org/en/docs/http/ngx_http_realip_module.html#set_real_ip_from). The real IP of the client will now be available in PHP under `$_SERVER['REMOTE_ADDR']`. \ No newline at end of file diff --git a/docs/sending-emails.md b/docs/sending-emails.md new file mode 100644 index 000000000..6f46c3e73 --- /dev/null +++ b/docs/sending-emails.md @@ -0,0 +1,16 @@ +# Sending e-mails +To be able to use the `mail()` function in PHP you need to install a MTA (Mail Transfer Agent) in the container. + +The most simple approach is to install `ssmtp`. + +The `ssmtp.conf` file needs to be created based on the [documentation online](https://wiki.archlinux.org/title/SSMTP). + +```Dockerfile +FROM trafex/php-nginx:latest + +# Install ssmtp +RUN apk add --no-cache ssmtp + +# Add configuration +COPY ssmtp.conf /etc/ssmtp/ssmtp.conf +``` \ No newline at end of file diff --git a/docs/xdebug-support.md b/docs/xdebug-support.md new file mode 100644 index 000000000..34d8210a4 --- /dev/null +++ b/docs/xdebug-support.md @@ -0,0 +1,37 @@ +# Adding xdebug support + +Create the following file `xdebug.ini` + +```ini +zend_extension=xdebug.so +xdebug.mode=develop,debug +xdebug.discover_client_host=true +xdebug.start_with_request=yes +xdebug.trigger_value=PHPSTORM +xdebug.log_level=0 + +xdebug.var_display_max_children=10 +xdebug.var_display_max_data=10 +xdebug.var_display_max_depth=10 + +xdebug.client_host=host.docker.internal +xdebug.client_port=9003 +``` + +Create a new image with the following `Dockerfile` + +```Dockerfile +FROM trafex/php-nginx:latest + +# Temporary switch to root +USER root + +# Install xdebug +RUN apk add --no-cache php84-pecl-xdebug + +# Add configuration +COPY xdebug.ini ${PHP_INI_DIR}/conf.d/xdebug.ini + +# Switch back to non-root user +USER nobody +``` diff --git a/run_tests.sh b/run_tests.sh index 189ceba8b..818614738 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -1,3 +1,3 @@ #!/usr/bin/env sh apk --no-cache add curl -curl --silent --fail http://app:8080 | grep 'PHP 8.0' +curl --silent --fail http://app:8080 | grep 'PHP 8.4'