Date: Thu, 16 Apr 2026 14:14:53 -0500
Subject: [PATCH 17/24] Changed sponsor URL
---
.github/workflows/scheduled-task_update-sponsors.yml | 4 ++--
README.md | 8 ++++----
docs/app/app.config.ts | 2 +-
docs/app/components/Badges.vue | 2 +-
docs/app/components/Sponsors.vue | 2 +-
docs/app/pages/[...slug].vue | 2 +-
docs/content/docs/1.getting-started/9.about.md | 2 +-
7 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/.github/workflows/scheduled-task_update-sponsors.yml b/.github/workflows/scheduled-task_update-sponsors.yml
index 3d1d233b1..c309277e9 100644
--- a/.github/workflows/scheduled-task_update-sponsors.yml
+++ b/.github/workflows/scheduled-task_update-sponsors.yml
@@ -16,7 +16,7 @@ jobs:
organization: true
minimum: 4900
maximum: 5100
- fallback: 'No bronze sponsors yet. Become a sponsor â'
+ fallback: 'No bronze sponsors yet. Become a sponsor â'
token: ${{ secrets.SPONSORS_README_ACTION_PERSONAL_ACCESS_TOKEN }}
marker: 'bronze'
template: '
'
@@ -27,7 +27,7 @@ jobs:
with:
organization: true
maximum: 500
- fallback: '
'
+ fallback: '
'
token: ${{ secrets.SPONSORS_README_ACTION_PERSONAL_ACCESS_TOKEN }}
marker: 'supporters'
template: '
'
diff --git a/README.md b/README.md
index bc350c7aa..2d4e819f1 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
-
+
@@ -141,13 +141,13 @@ Need help getting started? Join our Discord community and we'll help you out!
## Our Sponsors
All of our software is free and open to the world. None of this can be brought to you without the financial backing of our sponsors.
-

+
### Black Level Sponsors
#### Bronze Sponsors
-No bronze sponsors yet. Become a sponsor â
+No bronze sponsors yet. Become a sponsor â
#### Infrastructure Sponsors
This project requires significant computing power to build and maintain over 8,000 different Docker image tags. We're extremely grateful for the following sponsors:
@@ -176,7 +176,7 @@ We're [Dan](https://x.com/danpastori) and [Jay](https://x.com/jaydrogers) - a tw
* **đģ [GitHub](https://github.com/serversideup)** - Check out our other open source projects.
* **đĢ [Newsletter](https://serversideup.net/subscribe)** - Skip the algorithms and get quality content right to your inbox.
* **đĨ [Twitter](https://x.com/serversideup)** - You can also follow [Dan](https://x.com/danpastori) and [Jay](https://x.com/jaydrogers).
-* **â¤ī¸ [Sponsor Us](https://github.com/sponsors/serversideup)** - Please consider sponsoring us so we can create more helpful resources.
+* **â¤ī¸ [Sponsor Us](https://serversideup.net/sponsor/)** - Please consider sponsoring us so we can create more helpful resources.
## Our Products
If you appreciate this project, be sure to check out our other projects.
diff --git a/docs/app/app.config.ts b/docs/app/app.config.ts
index 8fe6a9bb7..4646d4997 100644
--- a/docs/app/app.config.ts
+++ b/docs/app/app.config.ts
@@ -116,7 +116,7 @@ export default defineAppConfig({
},{
'trailingIcon': 'i-lucide-heart',
'label': 'Sponsor',
- 'to': 'https://github.com/sponsors/serversideup',
+ 'to': 'https://serversideup.net/sponsor/',
'target': '_blank',
'aria-label': 'Sponsor',
'size': 'xl',
diff --git a/docs/app/components/Badges.vue b/docs/app/components/Badges.vue
index 498535522..6cc6c1aac 100644
--- a/docs/app/components/Badges.vue
+++ b/docs/app/components/Badges.vue
@@ -3,6 +3,6 @@
-
+
\ No newline at end of file
diff --git a/docs/app/components/Sponsors.vue b/docs/app/components/Sponsors.vue
index bc157a2da..def702673 100644
--- a/docs/app/components/Sponsors.vue
+++ b/docs/app/components/Sponsors.vue
@@ -7,7 +7,7 @@
-
+
Become a Sponsor
diff --git a/docs/app/pages/[...slug].vue b/docs/app/pages/[...slug].vue
index b818cf0e9..4fd1f2157 100644
--- a/docs/app/pages/[...slug].vue
+++ b/docs/app/pages/[...slug].vue
@@ -65,7 +65,7 @@
:links="[{
label: 'Become a Sponsor',
icon: 'i-lucide-heart',
- to: 'https://github.com/sponsors/serversideup',
+ to: 'https://serversideup.net/sponsor/',
target: '_blank'
}]"
/>
diff --git a/docs/content/docs/1.getting-started/9.about.md b/docs/content/docs/1.getting-started/9.about.md
index a88d67a40..f58cc1f4a 100644
--- a/docs/content/docs/1.getting-started/9.about.md
+++ b/docs/content/docs/1.getting-started/9.about.md
@@ -26,7 +26,7 @@ We're [Dan](https://x.com/danpastori){target="_blank"} and [Jay](https://x.com/j
* **đģ [GitHub](https://github.com/serversideup){target="_blank"}** - Check out our other open source projects.
* **đĢ [Newsletter](https://serversideup.net/subscribe){target="_blank"}** - Skip the algorithms and get quality content right to your inbox.
* **đĨ [Twitter](https://x.com/serversideup){target="_blank"}** - You can also follow [Dan](https://x.com/danpastori){target="_blank"} and [Jay](https://x.com/jaydrogers){target="_blank"}.
-* **â¤ī¸ [Sponsor Us](https://github.com/sponsors/serversideup){target="_blank"}** - Please consider sponsoring us so we can create more helpful resources.
+* **â¤ī¸ [Sponsor Us](https://serversideup.net/sponsor/){target="_blank"}** - Please consider sponsoring us so we can create more helpful resources.
## Our products
If you appreciate this project, be sure to check out our other projects.
From e5c1e68c762a01287dbd397e85e7c5642fc3d748 Mon Sep 17 00:00:00 2001
From: Jay Rogers
Date: Mon, 27 Apr 2026 13:37:40 -0500
Subject: [PATCH 18/24] Add AUTORUN_LARAVEL_SKIP_IF_NOT_FOUND environment
variable
- Introduced `AUTORUN_LARAVEL_SKIP_IF_NOT_FOUND` to allow the Laravel Automations script to exit gracefully if Laravel is not detected in `APP_BASE_DIR`, preventing container failure.
- Updated documentation to reflect this new variable and its usage, particularly in shared image scenarios before the first `composer install`.
- Enhanced the entrypoint script to support this new behavior, improving flexibility for development environments.
---
.../docs/3.framework-guides/1.laravel/1.automations.md | 3 +++
.../docs/8.reference/1.environment-variable-specification.md | 1 +
src/common/etc/entrypoint.d/50-laravel-automations.sh | 5 +++++
3 files changed, 9 insertions(+)
diff --git a/docs/content/docs/3.framework-guides/1.laravel/1.automations.md b/docs/content/docs/3.framework-guides/1.laravel/1.automations.md
index 6f88dbfc4..c320ba38e 100644
--- a/docs/content/docs/3.framework-guides/1.laravel/1.automations.md
+++ b/docs/content/docs/3.framework-guides/1.laravel/1.automations.md
@@ -31,6 +31,7 @@ In order for this script to run,`AUTORUN_ENABLED` must be set to `true`. Once th
| `AUTORUN_LARAVEL_MIGRATION_TIMEOUT` | `30` | Number of seconds to wait for database connection before timing out during migrations. |
| `AUTORUN_LARAVEL_OPTIMIZE` | `true` | `php artisan optimize`: Optimizes the application. |
| `AUTORUN_LARAVEL_ROUTE_CACHE` | `true` | `php artisan route:cache`: Caches the routes. |
+| `AUTORUN_LARAVEL_SKIP_IF_NOT_FOUND` | `false` | When `true`, the script will exit gracefully (without error) if Laravel is not detected in `APP_BASE_DIR`, instead of failing the container. Useful when `AUTORUN_ENABLED=true` is set on a shared image where Laravel may not always be present (e.g. before the first `composer install`). |
| `AUTORUN_LARAVEL_STORAGE_LINK` | `true` | `php artisan storage:link`: Creates a symbolic link from `public/storage` to `storage/app/public`. |
| `AUTORUN_LARAVEL_VIEW_CACHE` | `true` | `php artisan view:cache`: Caches the views. |
@@ -153,6 +154,8 @@ In most cases, this is due to a bug in their application code that causes a migr
If a failure occurs in the Laravel Automations script, it will exit with a non-zero exit code -- preventing the container from starting.
::
+If you need the container to start even when Laravel is not yet present (for example, before the first `composer install` in development), set `AUTORUN_LARAVEL_SKIP_IF_NOT_FOUND=true`. The script will exit silently with a zero exit code instead of failing. The skip will be logged when `AUTORUN_DEBUG=true` or `LOG_OUTPUT_LEVEL=debug` is set.
+
If you are experiencing issues, you can enable the `AUTORUN_DEBUG` environment variable to get more detailed output of what could be going wrong.
If you need even more information, you can set `LOG_OUTPUT_LEVEL` to `debug` to get **A TON** of output of what's exactly happening.
diff --git a/docs/content/docs/8.reference/1.environment-variable-specification.md b/docs/content/docs/8.reference/1.environment-variable-specification.md
index 8094dd528..279f97d72 100644
--- a/docs/content/docs/8.reference/1.environment-variable-specification.md
+++ b/docs/content/docs/8.reference/1.environment-variable-specification.md
@@ -42,6 +42,7 @@ Setting environment variables all depends on what method you're using to run you
`AUTORUN_LARAVEL_MIGRATION_SKIP_DB_CHECK`
*Default: "false"*|Skip the database connection check before running migrations.
âšī¸ Requires `AUTORUN_ENABLED = true` to run.| all
`AUTORUN_LARAVEL_MIGRATION_TIMEOUT`
*Default: "30"*|The number of seconds to wait for the database to come online before attempting `php artisan migrate`..
âšī¸ Requires `AUTORUN_ENABLED = true` to run.| all
`AUTORUN_LARAVEL_ROUTE_CACHE`
*Default: "true"*|Automatically run "php artisan route:cache" on container start.
âšī¸ Requires `AUTORUN_ENABLED = true` to run.| all
+`AUTORUN_LARAVEL_SKIP_IF_NOT_FOUND`
*Default: "false"*|When set to `true`, the Laravel Automations script will exit gracefully (without error) if Laravel is not detected in `APP_BASE_DIR`, instead of failing the container. Useful when `AUTORUN_ENABLED=true` is set on a shared image where Laravel may not always be present (e.g. before the first `composer install`).
âšī¸ Requires `AUTORUN_ENABLED = true` to have any effect.| all
`AUTORUN_LARAVEL_STORAGE_LINK`
*Default: "true"*|Automatically run "php artisan storage:link" on container start.
âšī¸ Requires `AUTORUN_ENABLED = true` to run.| all
`AUTORUN_LARAVEL_VIEW_CACHE`
*Default: "true"*|Automatically run "php artisan view:cache" on container start.
âšī¸ Requires `AUTORUN_ENABLED = true` to run.| all
`CADDY_ADMIN`
*Default: "off"*|Enable Caddy admin interface. (Official docs)|frankenphp
diff --git a/src/common/etc/entrypoint.d/50-laravel-automations.sh b/src/common/etc/entrypoint.d/50-laravel-automations.sh
index 3634c0a12..857f76fab 100644
--- a/src/common/etc/entrypoint.d/50-laravel-automations.sh
+++ b/src/common/etc/entrypoint.d/50-laravel-automations.sh
@@ -9,6 +9,7 @@ script_name="laravel-automations"
# Set default values for Laravel automations
: "${AUTORUN_ENABLED:=false}"
: "${AUTORUN_DEBUG:=false}"
+: "${AUTORUN_LARAVEL_SKIP_IF_NOT_FOUND:=false}"
# Set default values for storage link
: "${AUTORUN_LARAVEL_STORAGE_LINK:=true}"
@@ -469,6 +470,10 @@ if laravel_is_installed; then
artisan_optimize
fi
else
+ if [ "$AUTORUN_LARAVEL_SKIP_IF_NOT_FOUND" = "true" ]; then
+ debug_log "Laravel not detected in $APP_BASE_DIR. Skipping automations (AUTORUN_LARAVEL_SKIP_IF_NOT_FOUND=true)."
+ exit 0
+ fi
echo "â $script_name: Could not detect Laravel installation."
echo "âšī¸ Check that the application is installed in $APP_BASE_DIR"
exit 1
From a9f3c6c3ef045b476690bfac59fc4853abcb65e7 Mon Sep 17 00:00:00 2001
From: Jay Rogers
Date: Mon, 27 Apr 2026 14:02:02 -0500
Subject: [PATCH 19/24] Refactor logging in Laravel automation script
- Replaced echo statements with debug_log calls for improved logging in the `artisan_storage_link` and automation check sections of the entrypoint script.
- This change enhances the verbosity of log output, aiding in debugging and monitoring of Laravel automations.
---
src/common/etc/entrypoint.d/50-laravel-automations.sh | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/common/etc/entrypoint.d/50-laravel-automations.sh b/src/common/etc/entrypoint.d/50-laravel-automations.sh
index 857f76fab..6f4a811a9 100644
--- a/src/common/etc/entrypoint.d/50-laravel-automations.sh
+++ b/src/common/etc/entrypoint.d/50-laravel-automations.sh
@@ -154,7 +154,7 @@ artisan_migrate() {
artisan_storage_link() {
if [ -d "$APP_BASE_DIR/public/storage" ]; then
- echo "â
Storage already linked..."
+ debug_log "â
Storage already linked..."
return 0
else
echo "đ Running storage link: \"php artisan storage:link\"..."
@@ -453,7 +453,7 @@ if laravel_is_installed; then
done
fi
- echo "đ¤ Checking for Laravel automations..."
+ debug_log "đ¤ Checking for Laravel automations..."
if [ "$AUTORUN_LARAVEL_STORAGE_LINK" = "true" ]; then
artisan_storage_link
fi
From c26ce9ec47052f3e51f6381d34c03068f8da03e3 Mon Sep 17 00:00:00 2001
From: Jay Rogers
Date: Tue, 4 Aug 2026 17:57:37 -0500
Subject: [PATCH 20/24] Add short-lived SSL support for IP addresses and other
Let's Encrypt profiles
- Added details on using Let's Encrypt short-lived certificates and the `CADDY_ACME_PROFILE` environment variable in the documentation.
- Updated the Dockerfile to set the default value for `CADDY_ACME_PROFILE` to "off".
- Modified the Caddyfile to include the option for selecting a Let's Encrypt ACME certificate profile.
These changes improve clarity on SSL options and enhance the configuration flexibility for users.
---
.../docs/2.image-variations/frankenphp.md | 3 +++
.../4.configuring-ssl.md | 24 +++++++++++++++++++
.../1.environment-variable-specification.md | 1 +
src/variations/frankenphp/Dockerfile | 1 +
.../frankenphp/etc/frankenphp/Caddyfile | 5 +++-
.../frankenphp/acme-profile/classic.caddyfile | 7 ++++++
.../etc/frankenphp/acme-profile/off.caddyfile | 5 ++++
.../acme-profile/shortlived.caddyfile | 12 ++++++++++
.../acme-profile/tlsserver.caddyfile | 7 ++++++
9 files changed, 64 insertions(+), 1 deletion(-)
create mode 100644 src/variations/frankenphp/etc/frankenphp/acme-profile/classic.caddyfile
create mode 100644 src/variations/frankenphp/etc/frankenphp/acme-profile/off.caddyfile
create mode 100644 src/variations/frankenphp/etc/frankenphp/acme-profile/shortlived.caddyfile
create mode 100644 src/variations/frankenphp/etc/frankenphp/acme-profile/tlsserver.caddyfile
diff --git a/docs/content/docs/2.image-variations/frankenphp.md b/docs/content/docs/2.image-variations/frankenphp.md
index 278d601c7..6d5e43515 100644
--- a/docs/content/docs/2.image-variations/frankenphp.md
+++ b/docs/content/docs/2.image-variations/frankenphp.md
@@ -304,6 +304,8 @@ services:
Automatic HTTPS requires a public domain name and ports 80/443 accessible from the internet for Let's Encrypt validation. For local development, use self-signed certificates with `SSL_MODE`.
::
+Need Let's Encrypt short-lived certificates or IP-address certificates? Set `CADDY_ACME_PROFILE: "shortlived"`. See [Short-lived & IP-address certificates](/docs/deployment-and-production/configuring-ssl#short-lived--ip-address-certificates) for the trade-offs and the `default_sni` setup for SNI-less access.
+
### SSL Modes for Development
For local development, use the `SSL_MODE` environment variable:
@@ -339,6 +341,7 @@ The FrankenPHP variation supports extensive customization through environment va
| `FRANKENPHP_CONFIG` | `""` | FrankenPHP-specific configuration (e.g., worker mode) |
| `CADDY_SERVER_ROOT` | `/var/www/html/public` | Document root for the application |
| `CADDY_AUTO_HTTPS` | `off` | Enable automatic HTTPS (`on`/`off`) |
+| `CADDY_ACME_PROFILE` | `off` | Let's Encrypt certificate profile: `off`, `shortlived`, `tlsserver`, or `classic` |
| `CADDY_HTTP_PORT` | `8080` | HTTP port |
| `CADDY_HTTPS_PORT` | `8443` | HTTPS port |
| `CADDY_ADMIN` | `off` | Caddy admin API endpoint |
diff --git a/docs/content/docs/4.deployment-and-production/4.configuring-ssl.md b/docs/content/docs/4.deployment-and-production/4.configuring-ssl.md
index 940688ff5..f84bbe846 100644
--- a/docs/content/docs/4.deployment-and-production/4.configuring-ssl.md
+++ b/docs/content/docs/4.deployment-and-production/4.configuring-ssl.md
@@ -150,6 +150,30 @@ phpinfo();
You can achieve zero-downtime deployments with FrankenPHP by placing a reverse proxy in front of the container.
::
+#### Short-lived & IP-address certificates
+Let's Encrypt offers a [`shortlived` certificate profile](https://letsencrypt.org/docs/profiles/){target="_blank"} that issues ~6-day certificates. Because they expire so quickly, they don't rely on revocation (OCSP/CRL). This same profile is also **required** for [IP-address certificates](https://letsencrypt.org/2026/01/15/6day-and-ip-general-availability){target="_blank"}.
+
+Enable it with the `CADDY_ACME_PROFILE` environment variable:
+
+| Variable | Expected Value | Description |
+|----------|----------------|----------------|
+| `CADDY_ACME_PROFILE`
*Default: "off"* | `shortlived` | Select a Let's Encrypt certificate profile. Also accepts `tlsserver` and `classic`. |
+
+::warning
+Enabling a profile configures Caddy's `cert_issuer`, which pins issuance to **Let's Encrypt only** (the default ZeroSSL fallback is dropped). Short-lived certificates also renew roughly every 2 days, so the container needs reliable egress to the ACME CA. Leave it `off` unless you specifically want this behavior.
+::
+
+**Raw-IP / SNI-less access:** clients connecting by IP address send no SNI, so Caddy needs a [`default_sni`](https://caddyserver.com/docs/caddyfile/options#default-sni){target="_blank"} to know which certificate to serve. There's no dedicated variable for this because the value is your own domain/IP â set it through `CADDY_GLOBAL_OPTIONS`:
+
+```yml
+environment:
+ CADDY_AUTO_HTTPS: "on"
+ CADDY_ACME_PROFILE: "shortlived"
+ # Fallback identity for connections that send no SNI (e.g. by IP).
+ # Reference your own variable if you like: "default_sni {$APP_DOMAIN}"
+ CADDY_GLOBAL_OPTIONS: "default_sni example.com"
+```
+
### Bringing Your Own Certificate
If automatic HTTPS isn't an option, you can provide your own certificate from a vendor like [ssls.com](https://www.ssls.com/){target="_blank"}. Ensure your certificate issuer provides certificates compatible with your web server in [PEM format](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail){target="_blank"}.
diff --git a/docs/content/docs/8.reference/1.environment-variable-specification.md b/docs/content/docs/8.reference/1.environment-variable-specification.md
index 279f97d72..73cd102c4 100644
--- a/docs/content/docs/8.reference/1.environment-variable-specification.md
+++ b/docs/content/docs/8.reference/1.environment-variable-specification.md
@@ -45,6 +45,7 @@ Setting environment variables all depends on what method you're using to run you
`AUTORUN_LARAVEL_SKIP_IF_NOT_FOUND`
*Default: "false"*|When set to `true`, the Laravel Automations script will exit gracefully (without error) if Laravel is not detected in `APP_BASE_DIR`, instead of failing the container. Useful when `AUTORUN_ENABLED=true` is set on a shared image where Laravel may not always be present (e.g. before the first `composer install`).
âšī¸ Requires `AUTORUN_ENABLED = true` to have any effect.| all
`AUTORUN_LARAVEL_STORAGE_LINK`
*Default: "true"*|Automatically run "php artisan storage:link" on container start.
âšī¸ Requires `AUTORUN_ENABLED = true` to run.| all
`AUTORUN_LARAVEL_VIEW_CACHE`
*Default: "true"*|Automatically run "php artisan view:cache" on container start.
âšī¸ Requires `AUTORUN_ENABLED = true` to run.| all
+`CADDY_ACME_PROFILE`
*Default: "off"*|Select a Let's Encrypt ACME certificate profile. Valid options: `off` (default, no profile â keeps the stock Let's Encrypt + ZeroSSL issuers), `shortlived` (~6-day certs; also required for IP-address certificates), `tlsserver`, or `classic`. Setting any profile pins issuance to Let's Encrypt only and renews more frequently, so the container needs reliable egress to the ACME CA. (Official docs)|frankenphp
`CADDY_ADMIN`
*Default: "off"*|Enable Caddy admin interface. (Official docs)|frankenphp
`CADDY_AUTO_HTTPS`
*Default: "off"*|Enable automatic HTTPS. (Official docs)|frankenphp
`CADDY_GLOBAL_OPTIONS`
*Default: ""*|Set global options for the Caddy server. (Official docs)|frankenphp
diff --git a/src/variations/frankenphp/Dockerfile b/src/variations/frankenphp/Dockerfile
index d88b8a9cd..0cd377a6a 100644
--- a/src/variations/frankenphp/Dockerfile
+++ b/src/variations/frankenphp/Dockerfile
@@ -127,6 +127,7 @@ LABEL org.opencontainers.image.title="serversideup/php (frankenphp)" \
org.opencontainers.image.licenses="GPL-3.0-or-later"
ENV APP_BASE_DIR=/var/www/html \
+ CADDY_ACME_PROFILE="off" \
CADDY_ADMIN="off" \
CADDY_AUTO_HTTPS="off" \
CADDY_GLOBAL_OPTIONS="" \
diff --git a/src/variations/frankenphp/etc/frankenphp/Caddyfile b/src/variations/frankenphp/etc/frankenphp/Caddyfile
index cc883e8e1..704cee3dd 100644
--- a/src/variations/frankenphp/etc/frankenphp/Caddyfile
+++ b/src/variations/frankenphp/etc/frankenphp/Caddyfile
@@ -19,8 +19,11 @@
import trusted-proxy/{$TRUSTED_PROXY:cloudflare}.caddyfile
+ # Select a Let's Encrypt ACME certificate profile (default: off)
+ import acme-profile/{$CADDY_ACME_PROFILE:off}.caddyfile
+
# Add additional Caddy configuration files from the caddyfile-global.d directory
- import caddyfile-global.d/*.caddyfile
+ import caddyfile-global.d/*.caddyfile
{$CADDY_GLOBAL_OPTIONS}
}
diff --git a/src/variations/frankenphp/etc/frankenphp/acme-profile/classic.caddyfile b/src/variations/frankenphp/etc/frankenphp/acme-profile/classic.caddyfile
new file mode 100644
index 000000000..34d207326
--- /dev/null
+++ b/src/variations/frankenphp/etc/frankenphp/acme-profile/classic.caddyfile
@@ -0,0 +1,7 @@
+# Request Let's Encrypt's "classic" certificate profile.
+#
+# Note: configuring cert_issuer pins issuance to Let's Encrypt only (this
+# drops the default ZeroSSL fallback).
+cert_issuer acme {
+ profile classic
+}
diff --git a/src/variations/frankenphp/etc/frankenphp/acme-profile/off.caddyfile b/src/variations/frankenphp/etc/frankenphp/acme-profile/off.caddyfile
new file mode 100644
index 000000000..42d840342
--- /dev/null
+++ b/src/variations/frankenphp/etc/frankenphp/acme-profile/off.caddyfile
@@ -0,0 +1,5 @@
+# No ACME certificate profile is configured (default).
+#
+# Caddy keeps its stock issuer behavior, including the automatic
+# Let's Encrypt + ZeroSSL fallback. Set CADDY_ACME_PROFILE to select a
+# specific Let's Encrypt certificate profile instead.
diff --git a/src/variations/frankenphp/etc/frankenphp/acme-profile/shortlived.caddyfile b/src/variations/frankenphp/etc/frankenphp/acme-profile/shortlived.caddyfile
new file mode 100644
index 000000000..ef7b1a93d
--- /dev/null
+++ b/src/variations/frankenphp/etc/frankenphp/acme-profile/shortlived.caddyfile
@@ -0,0 +1,12 @@
+# Request Let's Encrypt's "shortlived" certificate profile (~6-day certs).
+#
+# Note: configuring cert_issuer pins issuance to Let's Encrypt only (this
+# drops the default ZeroSSL fallback). Short-lived certs renew roughly every
+# 2 days, so the container needs reliable egress to the ACME CA.
+#
+# The shortlived profile is also required for IP-address certificates. For
+# raw-IP / SNI-less access, also set a default SNI via CADDY_GLOBAL_OPTIONS,
+# e.g. CADDY_GLOBAL_OPTIONS="default_sni {$APP_DOMAIN}".
+cert_issuer acme {
+ profile shortlived
+}
diff --git a/src/variations/frankenphp/etc/frankenphp/acme-profile/tlsserver.caddyfile b/src/variations/frankenphp/etc/frankenphp/acme-profile/tlsserver.caddyfile
new file mode 100644
index 000000000..73bd5d6e8
--- /dev/null
+++ b/src/variations/frankenphp/etc/frankenphp/acme-profile/tlsserver.caddyfile
@@ -0,0 +1,7 @@
+# Request Let's Encrypt's "tlsserver" certificate profile.
+#
+# Note: configuring cert_issuer pins issuance to Let's Encrypt only (this
+# drops the default ZeroSSL fallback).
+cert_issuer acme {
+ profile tlsserver
+}
From bd12ac83c119304ebc15c41b5f29806625e451c3 Mon Sep 17 00:00:00 2001
From: Jay Rogers
Date: Tue, 4 Aug 2026 18:00:24 -0500
Subject: [PATCH 21/24] Update PHP extension installer version to 2.11.12
---
.../local/bin/docker-php-serversideup-install-php-ext-installer | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/common/usr/local/bin/docker-php-serversideup-install-php-ext-installer b/src/common/usr/local/bin/docker-php-serversideup-install-php-ext-installer
index cad78735d..c2cee43b3 100644
--- a/src/common/usr/local/bin/docker-php-serversideup-install-php-ext-installer
+++ b/src/common/usr/local/bin/docker-php-serversideup-install-php-ext-installer
@@ -11,7 +11,7 @@ script_name="docker-php-serversideup-install-php-ext-installer"
############
# Environment variables
############
-PHP_EXT_INSTALLER_VERSION="2.10.15"
+PHP_EXT_INSTALLER_VERSION="2.11.12"
############
# Main
From 6aa2e3358cfd62bb38347d47f7c24235d322ec3d Mon Sep 17 00:00:00 2001
From: Jay Rogers
Date: Tue, 4 Aug 2026 18:01:47 -0500
Subject: [PATCH 22/24] Update S6 version to 3.2.3.2
---
src/s6/usr/local/bin/docker-php-serversideup-s6-install | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/s6/usr/local/bin/docker-php-serversideup-s6-install b/src/s6/usr/local/bin/docker-php-serversideup-s6-install
index a07f0a1a9..57ea405b2 100644
--- a/src/s6/usr/local/bin/docker-php-serversideup-s6-install
+++ b/src/s6/usr/local/bin/docker-php-serversideup-s6-install
@@ -9,7 +9,7 @@ set -oue
# Be sure to set the S6_SRC_URL, S6_SRC_DEP, and S6_DIR
# environment variables before running this script.
-S6_VERSION=v3.2.2.0
+S6_VERSION=v3.2.3.2
mkdir -p $S6_DIR
export SYS_ARCH=$(uname -m)
case "$SYS_ARCH" in
From 49e286e4dbf2412633d617c93368520d5d8c95b7 Mon Sep 17 00:00:00 2001
From: Jay Rogers
Date: Fri, 7 Aug 2026 07:59:47 -0500
Subject: [PATCH 23/24] Update FrankenPHP version to 1.12.7
---
src/variations/frankenphp/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/variations/frankenphp/Dockerfile b/src/variations/frankenphp/Dockerfile
index 0cd377a6a..9639b660b 100644
--- a/src/variations/frankenphp/Dockerfile
+++ b/src/variations/frankenphp/Dockerfile
@@ -2,7 +2,7 @@
ARG BASE_OS_VERSION='trixie'
ARG PHP_VERSION='8.5'
ARG BASE_IMAGE="php:${PHP_VERSION}-zts-${BASE_OS_VERSION}"
-ARG FRANKENPHP_VERSION='1.12.6'
+ARG FRANKENPHP_VERSION='1.12.7'
ARG GOLANG_VERSION='1.26'
########################
From 32407147708c5edce2a20a6c9d29b4e90322b54f Mon Sep 17 00:00:00 2001
From: agabi10
Date: Tue, 8 Sep 2026 20:42:05 +0200
Subject: [PATCH 24/24] Add PHP_FILE_UPLOADS and PHP_MAX_FILE_UPLOADS to
environment variables (#697)
---
docs/content/docs/2.image-variations/fpm-apache.md | 2 ++
docs/content/docs/2.image-variations/fpm-nginx.md | 2 ++
docs/content/docs/2.image-variations/frankenphp.md | 2 ++
.../docs/8.reference/1.environment-variable-specification.md | 2 ++
.../usr/local/etc/php/conf.d/serversideup-docker-php.ini | 4 ++--
src/variations/cli/Dockerfile | 2 ++
src/variations/fpm-apache/Dockerfile | 2 ++
src/variations/fpm-nginx/Dockerfile | 2 ++
src/variations/fpm/Dockerfile | 2 ++
src/variations/frankenphp/Dockerfile | 2 ++
10 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/docs/content/docs/2.image-variations/fpm-apache.md b/docs/content/docs/2.image-variations/fpm-apache.md
index 194245e6c..58cab7791 100644
--- a/docs/content/docs/2.image-variations/fpm-apache.md
+++ b/docs/content/docs/2.image-variations/fpm-apache.md
@@ -235,6 +235,8 @@ For a complete list of available environment variables, see the [Environment Var
| `PHP_MEMORY_LIMIT` | `256M` | Maximum memory a script can use |
| `PHP_MAX_EXECUTION_TIME` | `99` | Maximum time a script can run (seconds) |
| `PHP_UPLOAD_MAX_FILE_SIZE` | `100M` | Maximum upload file size |
+| `PHP_FILE_UPLOADS` | `On` | Whether HTTP file uploads are allowed |
+| `PHP_MAX_FILE_UPLOADS` | `20` | Maximum number of files per request |
| `PHP_POST_MAX_SIZE` | `100M` | Maximum POST request size |
::tip{to="/docs/reference/environment-variable-specification"}
diff --git a/docs/content/docs/2.image-variations/fpm-nginx.md b/docs/content/docs/2.image-variations/fpm-nginx.md
index 077cb1390..7e635a734 100644
--- a/docs/content/docs/2.image-variations/fpm-nginx.md
+++ b/docs/content/docs/2.image-variations/fpm-nginx.md
@@ -236,6 +236,8 @@ For a complete list of available environment variables, see the [Environment Var
| `PHP_MEMORY_LIMIT` | `256M` | Maximum memory a script can use |
| `PHP_MAX_EXECUTION_TIME` | `99` | Maximum time a script can run (seconds) |
| `PHP_UPLOAD_MAX_FILE_SIZE` | `100M` | Maximum upload file size |
+| `PHP_FILE_UPLOADS` | `On` | Whether HTTP file uploads are allowed |
+| `PHP_MAX_FILE_UPLOADS` | `20` | Maximum number of files per request |
| `PHP_POST_MAX_SIZE` | `100M` | Maximum POST request size |
## Performance Tuning
diff --git a/docs/content/docs/2.image-variations/frankenphp.md b/docs/content/docs/2.image-variations/frankenphp.md
index 6d5e43515..f432b9277 100644
--- a/docs/content/docs/2.image-variations/frankenphp.md
+++ b/docs/content/docs/2.image-variations/frankenphp.md
@@ -366,6 +366,8 @@ For a complete list of available environment variables, see the [Environment Var
| `PHP_MEMORY_LIMIT` | `256M` | Maximum memory a script can use |
| `PHP_MAX_EXECUTION_TIME` | `99` | Maximum time a script can run (seconds) |
| `PHP_UPLOAD_MAX_FILE_SIZE` | `100M` | Maximum upload file size |
+| `PHP_FILE_UPLOADS` | `On` | Whether HTTP file uploads are allowed |
+| `PHP_MAX_FILE_UPLOADS` | `20` | Maximum number of files per request |
| `PHP_POST_MAX_SIZE` | `100M` | Maximum POST request size |
| `PHP_OPCACHE_ENABLE` | `0` | Enable OPcache (`0`/`1`) |
| `PHP_OPCACHE_REVALIDATE_FREQ` | `2` | How often to check for file changes (seconds) |
diff --git a/docs/content/docs/8.reference/1.environment-variable-specification.md b/docs/content/docs/8.reference/1.environment-variable-specification.md
index 73cd102c4..fba7426c0 100644
--- a/docs/content/docs/8.reference/1.environment-variable-specification.md
+++ b/docs/content/docs/8.reference/1.environment-variable-specification.md
@@ -81,6 +81,7 @@ Setting environment variables all depends on what method you're using to run you
`PHP_DISPLAY_STARTUP_ERRORS`
*Default: Off*|Even when display_errors is on, errors that occur during PHP's startup sequence are not displayed. (Official docs)| all
`PHP_ERROR_LOG`
*Default: "/dev/stderr"*|Name of the file where script errors should be logged. . (Official docs)|all
`PHP_ERROR_REPORTING`
*Default: "22527"*|Set PHP error reporting level. Must be a number. Use this tool for help. (Official docs)|all
+`PHP_FILE_UPLOADS`
*Default: "On"*|Whether to allow HTTP file uploads. (Official docs)|all
`PHP_FPM_CHILD_PROCESS_USER`
*Default: "www-data"*| â ī¸ Only used if container is running as root. Set the user of the PHP-FPM child processes. (Official docs)|fpm*
`PHP_FPM_CHILD_PROCESS_GROUP`
*Default: "www-data"*| â ī¸ Only used if container is running as root. Set the group of the PHP-FPM child processes. (Official docs)|fpm*
`PHP_FPM_PM_CONTROL`
*Defaults:
fpm: dynamic
fpm-apache: ondemand
fpm-nginx: ondemand*|Choose how the process manager will control the number of child processes. (Official docs)|fpm*
@@ -93,6 +94,7 @@ Setting environment variables all depends on what method you're using to run you
`PHP_FPM_POOL_NAME`
*Default: "www"*|Set the name of your PHP-FPM pool (helpful when running multiple sites on a single server).|fpm*
`PHP_FPM_PROCESS_CONTROL_TIMEOUT`
*Default: "10s"*|Set the timeout for the process control commands. (Official docs)|fpm*
`PHP_MAX_EXECUTION_TIME`
*Default: "99"*|Set the maximum time in seconds a script is allowed to run before it is terminated by the parser. (Official docs)|all
+`PHP_MAX_FILE_UPLOADS`
*Default: "20"*|The maximum number of files allowed to be uploaded in a single request. (Official docs)|all
`PHP_MAX_INPUT_TIME`
*Default: "-1"*|This sets the maximum time in seconds a script is allowed to parse input data, like POST and GET. Timing begins at the moment PHP is invoked at the server and ends when execution begins. The default setting is -1, which means that max_execution_time is used instead. Set to 0 to allow unlimited time. This directive is hardcoded to -1 for the CLI SAPI by PHP. (Official docs)|all
`PHP_MAX_INPUT_VARS`
*Default: "1000"*|Set the limits for number of input variables (e.g., POST, GET, or COOKIE variables) that PHP will process in a single request. (Official docs)|all
`PHP_MEMORY_LIMIT`
*Default: "256M"*|Set the maximum amount of memory in bytes that a script is allowed to allocate. (Official docs)|all
diff --git a/src/common/usr/local/etc/php/conf.d/serversideup-docker-php.ini b/src/common/usr/local/etc/php/conf.d/serversideup-docker-php.ini
index 0bbeec28c..36c103def 100644
--- a/src/common/usr/local/etc/php/conf.d/serversideup-docker-php.ini
+++ b/src/common/usr/local/etc/php/conf.d/serversideup-docker-php.ini
@@ -849,7 +849,7 @@ enable_dl = Off
; Whether to allow HTTP file uploads.
; https://php.net/file-uploads
-file_uploads = On
+file_uploads = ${PHP_FILE_UPLOADS}
; Temporary directory for HTTP uploaded files (will use system default if not
; specified).
@@ -861,7 +861,7 @@ file_uploads = On
upload_max_filesize = ${PHP_UPLOAD_MAX_FILE_SIZE}
; Maximum number of files that can be uploaded via a single request
-max_file_uploads = 20
+max_file_uploads = ${PHP_MAX_FILE_UPLOADS}
;;;;;;;;;;;;;;;;;;
; Fopen wrappers ;
diff --git a/src/variations/cli/Dockerfile b/src/variations/cli/Dockerfile
index 9e64137f5..faadcfff6 100644
--- a/src/variations/cli/Dockerfile
+++ b/src/variations/cli/Dockerfile
@@ -33,7 +33,9 @@ ENV APP_BASE_DIR=/var/www/html \
PHP_DISPLAY_STARTUP_ERRORS=Off \
PHP_ERROR_LOG="/dev/stderr" \
PHP_ERROR_REPORTING="22527" \
+ PHP_FILE_UPLOADS="On" \
PHP_MAX_EXECUTION_TIME="99" \
+ PHP_MAX_FILE_UPLOADS="20" \
PHP_MAX_INPUT_TIME="-1" \
PHP_MAX_INPUT_VARS="1000" \
PHP_MEMORY_LIMIT="256M" \
diff --git a/src/variations/fpm-apache/Dockerfile b/src/variations/fpm-apache/Dockerfile
index 0fa0d3fc1..7c1c5e364 100644
--- a/src/variations/fpm-apache/Dockerfile
+++ b/src/variations/fpm-apache/Dockerfile
@@ -61,6 +61,7 @@ ENV APACHE_DOCUMENT_ROOT=/var/www/html/public \
PHP_DISPLAY_STARTUP_ERRORS=Off \
PHP_ERROR_LOG="/dev/stderr" \
PHP_ERROR_REPORTING="22527" \
+ PHP_FILE_UPLOADS="On" \
PHP_FPM_PM_CONTROL=ondemand \
PHP_FPM_PM_MAX_CHILDREN="20" \
PHP_FPM_PM_MAX_REQUESTS="0" \
@@ -71,6 +72,7 @@ ENV APACHE_DOCUMENT_ROOT=/var/www/html/public \
PHP_FPM_POOL_NAME="www" \
PHP_FPM_PROCESS_CONTROL_TIMEOUT="10s" \
PHP_MAX_EXECUTION_TIME="99" \
+ PHP_MAX_FILE_UPLOADS="20" \
PHP_MAX_INPUT_TIME="-1" \
PHP_MAX_INPUT_VARS="1000" \
PHP_MEMORY_LIMIT="256M" \
diff --git a/src/variations/fpm-nginx/Dockerfile b/src/variations/fpm-nginx/Dockerfile
index e945a3d57..83a4d944a 100644
--- a/src/variations/fpm-nginx/Dockerfile
+++ b/src/variations/fpm-nginx/Dockerfile
@@ -135,6 +135,7 @@ ENV APP_BASE_DIR=/var/www/html \
PHP_DISPLAY_STARTUP_ERRORS=Off \
PHP_ERROR_LOG="/dev/stderr" \
PHP_ERROR_REPORTING="22527" \
+ PHP_FILE_UPLOADS="On" \
PHP_FPM_PM_CONTROL=ondemand \
PHP_FPM_PM_MAX_CHILDREN="20" \
PHP_FPM_PM_MAX_REQUESTS="0" \
@@ -145,6 +146,7 @@ ENV APP_BASE_DIR=/var/www/html \
PHP_FPM_POOL_NAME="www" \
PHP_FPM_PROCESS_CONTROL_TIMEOUT="10s" \
PHP_MAX_EXECUTION_TIME="99" \
+ PHP_MAX_FILE_UPLOADS="20" \
PHP_MAX_INPUT_TIME="-1" \
PHP_MAX_INPUT_VARS="1000" \
PHP_MEMORY_LIMIT="256M" \
diff --git a/src/variations/fpm/Dockerfile b/src/variations/fpm/Dockerfile
index 33294b908..2d39f76f6 100644
--- a/src/variations/fpm/Dockerfile
+++ b/src/variations/fpm/Dockerfile
@@ -33,6 +33,7 @@ ENV APP_BASE_DIR=/var/www/html \
PHP_DISPLAY_STARTUP_ERRORS=Off \
PHP_ERROR_LOG="/dev/stderr" \
PHP_ERROR_REPORTING="22527" \
+ PHP_FILE_UPLOADS="On" \
PHP_FPM_PM_CONTROL=dynamic \
PHP_FPM_PM_MAX_CHILDREN="20" \
PHP_FPM_PM_MAX_REQUESTS="0" \
@@ -43,6 +44,7 @@ ENV APP_BASE_DIR=/var/www/html \
PHP_FPM_POOL_NAME="www" \
PHP_FPM_PROCESS_CONTROL_TIMEOUT="10s" \
PHP_MAX_EXECUTION_TIME="99" \
+ PHP_MAX_FILE_UPLOADS="20" \
PHP_MAX_INPUT_TIME="-1" \
PHP_MAX_INPUT_VARS="1000" \
PHP_MEMORY_LIMIT="256M" \
diff --git a/src/variations/frankenphp/Dockerfile b/src/variations/frankenphp/Dockerfile
index 9639b660b..c85285712 100644
--- a/src/variations/frankenphp/Dockerfile
+++ b/src/variations/frankenphp/Dockerfile
@@ -152,7 +152,9 @@ LABEL org.opencontainers.image.title="serversideup/php (frankenphp)" \
PHP_DISPLAY_STARTUP_ERRORS=Off \
PHP_ERROR_LOG="/dev/stderr" \
PHP_ERROR_REPORTING="22527" \
+ PHP_FILE_UPLOADS="On" \
PHP_MAX_EXECUTION_TIME="99" \
+ PHP_MAX_FILE_UPLOADS="20" \
PHP_MAX_INPUT_TIME="-1" \
PHP_MAX_INPUT_VARS="1000" \
PHP_MEMORY_LIMIT="256M" \