Skip to content

Commit c26ce9e

Browse files
committed
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.
1 parent 9298c36 commit c26ce9e

9 files changed

Lines changed: 64 additions & 1 deletion

File tree

docs/content/docs/2.image-variations/frankenphp.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ services:
304304
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`.
305305
::
306306

307+
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.
308+
307309
### SSL Modes for Development
308310
For local development, use the `SSL_MODE` environment variable:
309311

@@ -339,6 +341,7 @@ The FrankenPHP variation supports extensive customization through environment va
339341
| `FRANKENPHP_CONFIG` | `""` | FrankenPHP-specific configuration (e.g., worker mode) |
340342
| `CADDY_SERVER_ROOT` | `/var/www/html/public` | Document root for the application |
341343
| `CADDY_AUTO_HTTPS` | `off` | Enable automatic HTTPS (`on`/`off`) |
344+
| `CADDY_ACME_PROFILE` | `off` | Let's Encrypt certificate profile: `off`, `shortlived`, `tlsserver`, or `classic` |
342345
| `CADDY_HTTP_PORT` | `8080` | HTTP port |
343346
| `CADDY_HTTPS_PORT` | `8443` | HTTPS port |
344347
| `CADDY_ADMIN` | `off` | Caddy admin API endpoint |

docs/content/docs/4.deployment-and-production/4.configuring-ssl.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,30 @@ phpinfo();
150150
You can achieve zero-downtime deployments with FrankenPHP by placing a reverse proxy in front of the container.
151151
::
152152

153+
#### Short-lived & IP-address certificates
154+
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"}.
155+
156+
Enable it with the `CADDY_ACME_PROFILE` environment variable:
157+
158+
| Variable | Expected Value | Description |
159+
|----------|----------------|----------------|
160+
| `CADDY_ACME_PROFILE` <br />*Default: "off"* | `shortlived` | Select a Let's Encrypt certificate profile. Also accepts `tlsserver` and `classic`. |
161+
162+
::warning
163+
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.
164+
::
165+
166+
**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`:
167+
168+
```yml
169+
environment:
170+
CADDY_AUTO_HTTPS: "on"
171+
CADDY_ACME_PROFILE: "shortlived"
172+
# Fallback identity for connections that send no SNI (e.g. by IP).
173+
# Reference your own variable if you like: "default_sni {$APP_DOMAIN}"
174+
CADDY_GLOBAL_OPTIONS: "default_sni example.com"
175+
```
176+
153177
### Bringing Your Own Certificate
154178
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"}.
155179

docs/content/docs/8.reference/1.environment-variable-specification.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Setting environment variables all depends on what method you're using to run you
4545
`AUTORUN_LARAVEL_SKIP_IF_NOT_FOUND`<br />*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`). <br />ℹ️ Requires `AUTORUN_ENABLED = true` to have any effect.| all
4646
`AUTORUN_LARAVEL_STORAGE_LINK`<br />*Default: "true"*|Automatically run "php artisan storage:link" on container start. <br />ℹ️ Requires `AUTORUN_ENABLED = true` to run.| all
4747
`AUTORUN_LARAVEL_VIEW_CACHE`<br />*Default: "true"*|Automatically run "php artisan view:cache" on container start. <br />ℹ️ Requires `AUTORUN_ENABLED = true` to run.| all
48+
`CADDY_ACME_PROFILE`<br />*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. (<a target="_blank" href="https://letsencrypt.org/docs/profiles/">Official docs</a>)|frankenphp
4849
`CADDY_ADMIN`<br />*Default: "off"*|Enable Caddy admin interface. (<a target="_blank" href="https://caddyserver.com/docs/caddyfile/options#admin">Official docs</a>)|frankenphp
4950
`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
5051
`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

src/variations/frankenphp/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ LABEL org.opencontainers.image.title="serversideup/php (frankenphp)" \
127127
org.opencontainers.image.licenses="GPL-3.0-or-later"
128128

129129
ENV APP_BASE_DIR=/var/www/html \
130+
CADDY_ACME_PROFILE="off" \
130131
CADDY_ADMIN="off" \
131132
CADDY_AUTO_HTTPS="off" \
132133
CADDY_GLOBAL_OPTIONS="" \

src/variations/frankenphp/etc/frankenphp/Caddyfile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919

2020
import trusted-proxy/{$TRUSTED_PROXY:cloudflare}.caddyfile
2121

22+
# Select a Let's Encrypt ACME certificate profile (default: off)
23+
import acme-profile/{$CADDY_ACME_PROFILE:off}.caddyfile
24+
2225
# Add additional Caddy configuration files from the caddyfile-global.d directory
23-
import caddyfile-global.d/*.caddyfile
26+
import caddyfile-global.d/*.caddyfile
2427

2528
{$CADDY_GLOBAL_OPTIONS}
2629
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Request Let's Encrypt's "classic" certificate profile.
2+
#
3+
# Note: configuring cert_issuer pins issuance to Let's Encrypt only (this
4+
# drops the default ZeroSSL fallback).
5+
cert_issuer acme {
6+
profile classic
7+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# No ACME certificate profile is configured (default).
2+
#
3+
# Caddy keeps its stock issuer behavior, including the automatic
4+
# Let's Encrypt + ZeroSSL fallback. Set CADDY_ACME_PROFILE to select a
5+
# specific Let's Encrypt certificate profile instead.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Request Let's Encrypt's "shortlived" certificate profile (~6-day certs).
2+
#
3+
# Note: configuring cert_issuer pins issuance to Let's Encrypt only (this
4+
# drops the default ZeroSSL fallback). Short-lived certs renew roughly every
5+
# 2 days, so the container needs reliable egress to the ACME CA.
6+
#
7+
# The shortlived profile is also required for IP-address certificates. For
8+
# raw-IP / SNI-less access, also set a default SNI via CADDY_GLOBAL_OPTIONS,
9+
# e.g. CADDY_GLOBAL_OPTIONS="default_sni {$APP_DOMAIN}".
10+
cert_issuer acme {
11+
profile shortlived
12+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Request Let's Encrypt's "tlsserver" certificate profile.
2+
#
3+
# Note: configuring cert_issuer pins issuance to Let's Encrypt only (this
4+
# drops the default ZeroSSL fallback).
5+
cert_issuer acme {
6+
profile tlsserver
7+
}

0 commit comments

Comments
 (0)