Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,25 @@ We like to customize our images on a per app basis using environment variables.
`AUTORUN_LARAVEL_ROUTE_CACHE`<br />*Default: "true"*|Automatically run "php artisan route:cache" on container start. <br />ℹ️ Requires `AUTORUN_ENABLED = true` to run.| all
`AUTORUN_LARAVEL_STORAGE_LINK`<br />*Default: "true"*|Automatically run "php artisan storage:link" on container start. <br />ℹ️ Requires `AUTORUN_ENABLED = true` to run.| all
`AUTORUN_LARAVEL_VIEW_CACHE`<br />*Default: "true"*|Automatically run "php artisan view:cache" on container start. <br />ℹ️ Requires `AUTORUN_ENABLED = true` to run.| all
`CADDY_ADMIN`<br />*Default: "off"*|Enable Caddy admin interface. (<a target="_blank" href="https://caddyserver.com/docs/caddyfile/options#admin">Official docs</a>)|frankenphp
`CADDY_APP_PUBLIC_PATH`<br />*Default: "/var/www/html/public"*|The path to your public directory for your app. (<a target="_blank" href="https://caddyserver.com/docs/caddyfile/directives/root">Official docs</a>)|frankenphp
`CADDY_AUTO_HTTPS`<br />*Default: "off"*|Enable automatic HTTPS. (<a target="_blank" href="https://caddyserver.com/docs/caddyfile/options#auto-https">Official docs</a>)|frankenphp
`CADDY_GLOBAL_OPTIONS`<br />*Default: ""*|Set global options for the Caddy server. (<a target="_blank" href="https://caddyserver.com/docs/caddyfile/options">Official docs</a>)|frankenphp
`CADDY_HTTP_PORT`<br />*Default: "8080"*|Set the port for HTTP. (<a target="_blank" href="https://caddyserver.com/docs/caddyfile/options#http-port">Official docs</a>)|frankenphp
`CADDY_HTTPS_PORT`<br />*Default: "8443"*|Set the port for HTTPS. (<a target="_blank" href="https://caddyserver.com/docs/caddyfile/options#https-port">Official docs</a>)|frankenphp
`CADDY_HTTP_SERVER_ADDRESS`<br />*Default: "http://"*|Set the server address for HTTP. (<a target="_blank" href="https://caddyserver.com/docs/caddyfile/concepts#addresses">Official docs</a>)|frankenphp
`CADDY_HTTPS_SERVER_ADDRESS`<br />*Default: "https://"*|Set the server address for HTTPS. (<a target="_blank" href="https://caddyserver.com/docs/caddyfile/concepts#addresses">Official docs</a>)|frankenphp
`CADDY_LOG_FORMAT`<br />*Default: "console"*|Set the format for the Caddy log. (<a target="_blank" href="https://caddyserver.com/docs/caddyfile/directives/log#format-modules">Official docs</a>)|frankenphp
`CADDY_GLOBAL_LOG_LEVEL`<br />*Default: "warn"*|Set the global log level for the Caddy server. This can also be changed with `LOG_OUTPUT_LEVEL`, but `CADDY_GLOBAL_LOG_LEVEL` takes precedence. (<a target="_blank" href="https://caddyserver.com/docs/caddyfile/options#log">Official docs</a>)|frankenphp
`CADDY_SERVER_LOG_LEVEL`<br />*Default: "warn"*|Set the server log level for the Caddy server. This can also be changed with `LOG_OUTPUT_LEVEL`, but `CADDY_SERVER_LOG_LEVEL` takes precedence. (<a target="_blank" href="https://caddyserver.com/docs/caddyfile/directives/log#format-modules">Official docs</a>)|frankenphp
`CADDY_LOG_OUTPUT`<br />*Default: "stdout"*|Set the output for the Caddy log. (<a target="_blank" href="https://caddyserver.com/docs/caddyfile/directives/log#output-modules">Official docs</a>)|frankenphp
`CADDY_PHP_SERVER_OPTIONS`<br />*Default: ""*|Set PHP server options for the Caddy server. (<a target="_blank" href="https://frankenphp.dev/docs/config/#caddyfile-config">Official docs</a>)|frankenphp
`CADDY_SERVER_EXTRA_DIRECTIVES`<br />*Default: ""*|Set extra directives for the Caddy server. (<a target="_blank" href="https://caddyserver.com/docs/caddyfile/directives">Official docs</a>)|frankenphp
`COMPOSER_ALLOW_SUPERUSER`<br />*Default: "1"*|Disable warning about running as super-user|all
`COMPOSER_HOME`<br />*Default: "/composer"*|The COMPOSER_HOME variable allows you to change the Composer home directory. This is a hidden, global (per-user on the machine) directory that is shared between all projects.|all
`COMPOSER_MAX_PARALLEL_HTTP`<br />*Default: "24"*|Set to an integer to configure how many files can be downloaded in parallel. Composer ships with 12 by default and must be between 1 and 50. If your proxy has issues with concurrency maybe you want to lower this. Increasing it should generally not result in performance gains.|all
`DISABLE_DEFAULT_CONFIG`<br />*Default: "false"*|Get full customization of the image and disable all default configurations and automations.| all
`FRANKENPHP_CONFIG`<br />*Default: ""*|Set the configuration for FrankenPHP. (<a target="_blank" href="https://frankenphp.dev/docs/config/#caddyfile-config">Official docs</a>)|frankenphp
`HEALTHCHECK_PATH`<br />*Default: "/healthcheck"*|Set the path for the health check endpoint. (<a target="_blank" href="https://docs.docker.com/engine/reference/builder/#healthcheck">Official docs</a>)|all (except `cli` and `frankenphp`)
`LOG_OUTPUT_LEVEL`<br />*Default: "warn"*|Set your container output different verbosity levels: debug, info, off |all
`NGINX_FASTCGI_BUFFERS`<br />*Default: "8 8k"*|Sets the number and size of the buffers used for reading a response from a FastCGI server. (<a target="_blank" href="https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_buffers">Official Docs</a>)|fpm-nginx
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ case "$OS" in
DIRS="
/composer
/var/www
/etc/ssl/private
$PHP_INI_DIR/conf.d/zzz-serversideup-docker-php-debug.ini"
;;
*)
Expand Down Expand Up @@ -180,6 +181,7 @@ case "$OS" in
DIRS="
/composer
/var/www
/etc/ssl/private
$PHP_INI_DIR/conf.d/zzz-serversideup-docker-php-debug.ini"
;;
*)
Expand Down
36 changes: 28 additions & 8 deletions src/variations/frankenphp/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ RUN set -eux; \
/var/www/config/caddy \
/var/www/data/caddy \
/etc/caddy \
/etc/frankenphp/ssl-modes \
/etc/frankenphp/ssl-mode \
/etc/frankenphp/log-level \
/etc/frankenphp/caddyfile.d; \
# Create default index.php
echo '<?php phpinfo();' > /var/www/html/public/index.php; \
Expand Down Expand Up @@ -109,6 +110,8 @@ RUN if cat /etc/os-release | grep -q 'debian'; then \
# FrankenPHP Final
####################
FROM common AS final
ARG DEPENDENCY_PACKAGES_ALPINE='shadow libstdc++'
ARG DEPENDENCY_PACKAGES_DEBIAN='libstdc++6'
ARG DEPENDENCY_PHP_EXTENSIONS='opcache pcntl pdo_mysql pdo_pgsql redis zip'

LABEL org.opencontainers.image.title="serversideup/php (frankenphp)" \
Expand All @@ -121,11 +124,22 @@ LABEL org.opencontainers.image.title="serversideup/php (frankenphp)" \
org.opencontainers.image.version="${REPOSITORY_BUILD_VERSION}" \
org.opencontainers.image.licenses="GPL-3.0-or-later"

ENV APP_BASE_DIR=/var/www/html \
ENV APP_BASE_DIR=/var/www/html \
CADDY_ADMIN="off" \
CADDY_APP_PUBLIC_PATH="/var/www/html/public" \
CADDY_AUTO_HTTPS="off" \
CADDY_GLOBAL_OPTIONS="" \
CADDY_HTTP_PORT="8080" \
CADDY_HTTPS_PORT="8443" \
CADDY_HTTP_SERVER_ADDRESS="http://" \
CADDY_HTTPS_SERVER_ADDRESS="https://" \
CADDY_PHP_SERVER_OPTIONS="" \
CADDY_SERVER_EXTRA_DIRECTIVES="" \
COMPOSER_ALLOW_SUPERUSER=1 \
COMPOSER_HOME=/composer \
COMPOSER_MAX_PARALLEL_HTTP=24 \
DISABLE_DEFAULT_CONFIG=false \
FRANKEN_PHP_CONFIG="" \
LOG_OUTPUT_LEVEL=warn \
HEALTHCHECK_PATH="/healthcheck" \
PHP_DATE_TIMEZONE="UTC" \
Expand Down Expand Up @@ -153,8 +167,8 @@ ENV APP_BASE_DIR=/var/www/html \
PHP_UPLOAD_MAX_FILE_SIZE="100M" \
SHOW_WELCOME_MESSAGE=true \
SSL_MODE=off \
SSL_CERTIFICATE_FILE=/etc/ssl/private/self-signed-web.crt \
SSL_PRIVATE_KEY_FILE=/etc/ssl/private/self-signed-web.key \
SSL_CERTIFICATE_FILE="/etc/ssl/private/self-signed-web.crt" \
SSL_CERTIFICATE_KEY_FILE="/etc/ssl/private/self-signed-web.key" \
XDG_CONFIG_HOME=/config \
XDG_DATA_HOME=/data

Expand All @@ -165,12 +179,12 @@ COPY --from=frankenphp-build /usr/local/bin/frankenphp /usr/local/bin/frankenphp
COPY --from=frankenphp-build /usr/local/lib/libwatcher* /usr/local/lib/

COPY src/variations/frankenphp/etc/frankenphp/ /etc/frankenphp/

COPY src/variations/frankenphp/etc/entrypoint.d/ /etc/entrypoint.d/

RUN \
docker-php-serversideup-dep-install-alpine "${DEPENDENCY_PACKAGES_ALPINE}"; \
docker-php-serversideup-dep-install-debian "${DEPENDENCY_PACKAGES_DEBIAN}"; \
# Fix for the file watcher on arm
docker-php-serversideup-dep-install-alpine "libstdc++"; \
docker-php-serversideup-dep-install-debian "libstdc++6"; \
if cat /etc/os-release | grep -q 'alpine'; then \
ldconfig /usr/local/lib; \
elif cat /etc/os-release | grep -q 'debian'; then \
Expand All @@ -179,10 +193,16 @@ RUN \
echo "Unsupported OS"; \
exit 1; \
fi; \
# Make composer cache directory
mkdir -p "${COMPOSER_HOME}" && \
chown -R www-data:www-data "${COMPOSER_HOME}" && \
\
# Install PHP Extension installer
docker-php-serversideup-install-php-ext-installer; \
# Install default PHP extensions
install-php-extensions "${DEPENDENCY_PHP_EXTENSIONS}"
install-php-extensions "${DEPENDENCY_PHP_EXTENSIONS}"; \
# Ensure permissions are set for www-data
docker-php-serversideup-set-file-permissions --owner www-data:www-data --service frankenphp

WORKDIR ${APP_BASE_DIR}

Expand Down
38 changes: 38 additions & 0 deletions src/variations/frankenphp/etc/entrypoint.d/10-generate-ssl.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/sh
###################################################
# Usage: 10-generate-ssl.sh
###################################################
# This script generates a self-signed SSL certificate and key for the container.
script_name="generate-ssl"

SSL_CERTIFICATE_FILE=${SSL_CERTIFICATE_FILE:-"/etc/ssl/private/self-signed-web.crt"}
SSL_PRIVATE_KEY_FILE=${SSL_PRIVATE_KEY_FILE:-"/etc/ssl/private/self-signed-web.key"}
SSL_MODE=${SSL_MODE:-"off"}

if [ "$SSL_MODE" = "off" ]; then
echo "ℹ️ NOTICE ($script_name): SSL mode is off, so we'll not generate a self-signed SSL certificate and key."
return 0
fi

if [ -z "$SSL_CERTIFICATE_FILE" ] || [ -z "$SSL_PRIVATE_KEY_FILE" ]; then
echo "🛑 ERROR ($script_name): SSL_CERTIFICATE_FILE or SSL_PRIVATE_KEY_FILE is not set."
return 1
fi

if ([ -f "$SSL_CERTIFICATE_FILE" ] && [ ! -f "$SSL_PRIVATE_KEY_FILE" ]) ||
([ ! -f "$SSL_CERTIFICATE_FILE" ] && [ -f "$SSL_PRIVATE_KEY_FILE" ]); then
echo "🛑 ERROR ($script_name): Only one of the SSL certificate or private key exists. Check the SSL_CERTIFICATE_FILE and SSL_PRIVATE_KEY_FILE variables and try again."
echo "🛑 ERROR ($script_name): SSL_CERTIFICATE_FILE: $SSL_CERTIFICATE_FILE"
echo "🛑 ERROR ($script_name): SSL_PRIVATE_KEY_FILE: $SSL_PRIVATE_KEY_FILE"
return 1
fi

if [ -f "$SSL_CERTIFICATE_FILE" ] && [ -f "$SSL_PRIVATE_KEY_FILE" ]; then
echo "ℹ️ NOTICE ($script_name): SSL certificate and private key already exist, so we'll use the existing files."
return 0
fi

echo "🔐 SSL Keypair not found. Generating self-signed SSL keypair..."
openssl req -x509 -subj "/C=US/ST=Wisconsin/L=Milwaukee/O=IT/CN=*.dev.test,*.test,*.gitpod.io,*.ngrok.io,*.nip.io" -nodes -newkey rsa:2048 -keyout "$SSL_PRIVATE_KEY_FILE" -out "$SSL_CERTIFICATE_FILE" -days 365 >/dev/null 2>&1

exit 0
163 changes: 123 additions & 40 deletions src/variations/frankenphp/etc/frankenphp/Caddyfile
Original file line number Diff line number Diff line change
@@ -1,59 +1,142 @@
# The Caddyfile is an easy way to configure FrankenPHP and the Caddy web server.
#
# https://frankenphp.dev/docs/config
# https://caddyserver.com/docs/caddyfile

{
# Global Caddy configuration
admin {$CADDY_ADMIN:off}
auto_https {$CADDY_AUTO_HTTPS:off}

http_port {$CADDY_HTTP_PORT:8080}
https_port {$CADDY_HTTPS_PORT:8443}

skip_install_trust

{$CADDY_GLOBAL_OPTIONS}
# Match serversideup/php log levels to Caddy global log levels
import log-level/global/{$LOG_OUTPUT_LEVEL:info}.caddyfile

frankenphp {
{$FRANKENPHP_CONFIG}
}
}

{$CADDY_EXTRA_CONFIG}
servers {
# Trust Docker/private networks + loopback + Cloudflare ranges
trusted_proxies static \
10.0.0.0/8 \
172.16.0.0/12 \
192.168.0.0/16 \
127.0.0.1/8 \
::1 \
fd00::/8 \
173.245.48.0/20 \
103.21.244.0/22 \
103.22.200.0/22 \
103.31.4.0/22 \
141.101.64.0/18 \
108.162.192.0/18 \
190.93.240.0/20 \
188.114.96.0/20 \
197.234.240.0/22 \
198.41.128.0/17 \
162.158.0.0/15 \
104.16.0.0/13 \
104.24.0.0/14 \
172.64.0.0/13 \
131.0.72.0/22 \
2400:cb00::/32 \
2606:4700::/32 \
2803:f800::/32 \
2405:b500::/32 \
2405:8100::/32 \
2a06:98c0::/29 \
2c0f:f248::/32

# Prefer Cloudflare's header; keep XFF as fallback
client_ip_headers CF-Connecting-IP X-Forwarded-For
}

{$CADDY_GLOBAL_OPTIONS}
}

{$SERVER_NAME:localhost}:8443 {
#log {
# # Redact the authorization query parameter that can be set by Mercure
# format filter {
# request>uri query {
# replace authorization REDACTED
# }
# }
#}
# Common app logic; reused across all SSL modes
(app-common) {
root * {$CADDY_APP_PUBLIC_PATH:/var/www/html/public}

root {$SERVER_ROOT:public/}
encode zstd br gzip

# Uncomment the following lines to enable Mercure and Vulcain modules
#mercure {
# # Transport to use (default to Bolt)
# transport_url {$MERCURE_TRANSPORT_URL:bolt:///data/mercure.db}
# # Publisher JWT key
# publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
# # Subscriber JWT key
# subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
# # Allow anonymous subscribers (double-check that it's what you want)
# anonymous
# # Enable the subscription API (double-check that it's what you want)
# subscriptions
# # Extra directives
# {$MERCURE_EXTRA_DIRECTIVES}
#}
#vulcain
# Match serversideup/php log levels to Caddy address log levels
import log-level/address/{$LOG_OUTPUT_LEVEL:info}.caddyfile

{$CADDY_SERVER_EXTRA_DIRECTIVES}
# Healthcheck endpoint
@health {
path /healthcheck
}
respond @health "OK" 200
log_skip @health

php_server {
#worker /path/to/your/worker.php
{$CADDY_PHP_SERVER_OPTIONS}
}
file_server

import performance
import security

{$CADDY_SERVER_EXTRA_DIRECTIVES}
}

(performance) {
# Favicon/robots: skip noisy logs
@meta path /favicon.ico /robots.txt
log_skip @meta

# Static assets (long cache)
@static {
path *.css *.css.map *.js *.js.map *.jpg *.jpeg *.png *.gif *.ico *.cur *.heic *.webp *.tif *.tiff *.mp3 *.m4a *.aac *.ogg *.midi *.mid *.wav *.mp4 *.mov *.webm *.mpeg *.mpg *.avi *.ogv *.flv *.wmv *.htc *.gz *.svg *.svgz *.woff2 *.woff
}
header @static Cache-Control "public, immutable, stale-while-revalidate, max-age=31536000"

# Fonts/SVG: allow cross-origin usage (cache header inherited from @static)
@fonts {
path *.svg *.svgz *.ttf *.ttc *.otf *.eot *.woff *.woff2
}
header @fonts Access-Control-Allow-Origin "*"

# Short-lived static
@staticshort {
path *.json *.xml *.rss
}
header @staticshort Cache-Control "no-cache, max-age=3600"
}

(security) {
# Reject dot files and certain file extensions
@rejected path *.bak *.conf *.dist *.fla *.ini *.inc *.inci *.log *.orig *.psd *.sh *.sql *.swo *.swp *.swop */.*

# Return 403 Forbidden for rejected files
respond @rejected 403

# Security headers
header {
defer
# Prevent IFRAME spoofing attacks
X-Frame-Options "SAMEORIGIN"
# Prevent MIME type sniffing
X-Content-Type-Options "nosniff"
# Prevent referrer leakage
Referrer-Policy "strict-origin-when-cross-origin"
# Prevent server header leakage
-Server
# Prevent powered by header leakage
-X-Powered-By
}
}

(security-https) {
header {
defer
Strict-Transport-Security "max-age=31536000; includeSubDomains"
}
}

# As an alternative to editing the above site block, you can add your own site
# block files in the Caddyfile.d directory, and they will be included as long
# as they use the .caddyfile extension.
# Pull in the per-mode listeners (off|mixed|full)
import ssl-mode/{$SSL_MODE:off}.caddyfile

import Caddyfile.d/*.caddyfile
# Add your web servers here
import caddyfile.d/*.caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
log {
format {$CADDY_LOG_FORMAT:console}
output {$CADDY_LOG_OUTPUT:stdout}
level {$CADDY_SERVER_LOG_LEVEL:ERROR}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
log {
format {$CADDY_LOG_FORMAT:console}
output {$CADDY_LOG_OUTPUT:stdout}
level {$CADDY_SERVER_LOG_LEVEL:ERROR}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
log {
format {$CADDY_LOG_FORMAT:console}
output {$CADDY_LOG_OUTPUT:stdout}
level {$CADDY_SERVER_LOG_LEVEL:INFO}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
log {
format {$CADDY_LOG_FORMAT:console}
output {$CADDY_LOG_OUTPUT:stdout}
level {$CADDY_SERVER_LOG_LEVEL:ERROR}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
log {
format {$CADDY_LOG_FORMAT:console}
output {$CADDY_LOG_OUTPUT:stdout}
level {$CADDY_SERVER_LOG_LEVEL:ERROR}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
log {
format {$CADDY_LOG_FORMAT:console}
output {$CADDY_LOG_OUTPUT:stdout}
level {$CADDY_SERVER_LOG_LEVEL:INFO}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
log {
format {$CADDY_LOG_FORMAT:console}
output {$CADDY_LOG_OUTPUT:stdout}
level {$CADDY_SERVER_LOG_LEVEL:INFO}
}
Loading