Symptoms
On the affected Docker releases, the web container obtains its first certificate, then repeatedly fails to start cron. Eventually HTTPS presents an expired certificate. Issue #2301 records these lines: [S1][S2]
web-1 | no crontab for s6
web-1 | seteuid: Operation not permittedRead them from the project directory: [S13]
docker compose logs --tail 200 webChallenge routing can also fail after the scheduler is fixed. [S14]
Cause
The rootless web image runs as UID 1000. Debian cron needs privileges, exits on seteuid: Operation not permitted, and s6 starts it again. Initial issuance succeeds because startup calls acme.sh directly. [S2]
Stable-11146-2 replaces cron with the acme-renewal service and installs acme.sh with --nocron. The service waits 60 seconds, then runs acme.sh --cron --home /storage/acme.sh every 43,200 seconds, or 12 hours. It renews certificates when due. It disables itself if DISABLE_HTTPS=1, ENABLE_LETSENCRYPT is not 1, or the installed executable is missing. [S3][S6]
State locations in stable-11248 are: [S5][S7]
| Purpose | Container path | Host path |
|---|---|---|
| Client, account and renewal metadata | /storage/acme.sh |
${CONFIG}/storage/web/acme.sh |
| Installed chain and key | /storage/acme-certs/meet.example.com/fullchain.pem, /storage/acme-certs/meet.example.com/key.pem |
${CONFIG}/storage/web/acme-certs/meet.example.com/ |
${CONFIG}/tmp/web-crontabs was the obsolete cron mount, removed by PR #2305. ${CONFIG}/tmp/web-load-test remains unrelated to certificate renewal. Startup copies old /config/acme.sh and /config/acme-certs into storage only when their new destinations do not exist. [S2][S5][S7]
Fix
Before changing either installation, run the first command in Verify and record the served certificate’s serial and notAfter. [S10]
-
Docker, affected releases: upgrade the release and its Compose files. Use the stable-11248 release archive, preserve your
.env, passwords and existingCONFIGdirectory, and apply the rootless directory migration if upgrading from an older release. Its writable storage must be accessible to UID 1000. [S2][S4][S5][S8]Set this in
.env, then run the commands from the updated project directory. This recreates services, so schedule a maintenance window. Keep any additional Compose files you normally use in the invocation. [S5][S8][S13]ConfigJITSI_IMAGE_VERSION=stable-11248Terminaldocker compose config --images docker compose pull docker compose up -d --force-recreate docker compose psThe core images must end with
/web:stable-11248,/prosody:stable-11248,/jicofo:stable-11248and/jvb:stable-11248. Custom Compose deployments need the matching storage mount and port mappings, not just a new web image. [S5] -
Docker stable-11248: check renewal prerequisites. For direct HTTPS termination in the web container, confirm these
.envsettings: [S7][S8]ConfigENABLE_LETSENCRYPT=1 DISABLE_HTTPS=0 LETSENCRYPT_DOMAIN=meet.example.com LETSENCRYPT_EMAIL=admin@example.com HTTP_PORT=80 HTTPS_PORT=443After changing these values, recreate web. Restarting alone does not apply environment changes. [S13]
Terminaldocker compose up -d --no-deps --force-recreate webPublic TCP 80 must reach the standalone HTTP challenge. The corrected Compose mapping sends host port 80 to container port 8000, and PR #2300 adds
--httpport 8000. TLS expiry does not prevent HTTP-01 validation. If an external proxy owns TLS, renew through its certificate manager. [S3][S5][S7][S8][S15] -
Docker stable-11248: run a due renewal check first. Use
/command/with-contenvto load the service environment, including PATH for its Nginx hooks. Check due renewals and list records: [S6][S13]Terminaldocker compose exec -T web /command/with-contenv /storage/acme.sh/acme.sh --cron --home /storage/acme.sh docker compose exec -T web /command/with-contenv /storage/acme.sh/acme.sh --list --home /storage/acme.sh -
Docker stable-11248: recover an expired certificate or force one controlled renewal. After fixing connectivity, select the record backing the served certificate. Use the ECC command below for an
ec-key length. For an RSA certificate, omit--ecc. Renewal uses stored challenge settings and install paths. Its hooks stop and start Nginx, so use a maintenance window and avoid concurrent renewal attempts. [S7][S9]Terminaldocker compose exec -T web /command/with-contenv /storage/acme.sh/acme.sh --renew -d meet.example.com --ecc --force --home /storage/acme.shAfter successful renewal, restart web to ensure it loads the installed certificate, then run Verify. Preserve the ACME account and certificate directories. Repeated forced requests are not a substitute for fixing validation and can encounter CA rate limits. [S7][S9][S13][S15]
Terminaldocker compose restart web -
Debian/Ubuntu packages: identify the installed certificate client. Docker tags and its cron regression do not apply to the package helper. At
jitsi-meet_11248, it uses acme.sh under/opt/acmesh/.acme.sh, installs/etc/jitsi/meet/meet.example.com.crtand the matching.key, and saves web-server and coturn reload commands. Run its due-renewal check: [S11]Terminalsudo /opt/acmesh/.acme.sh/acme.sh --cron --home /opt/acmesh/.acme.shTo recover that helper’s issuance and installation configuration, use: [S11]
Terminalsudo /usr/share/jitsi-meet/scripts/install-letsencrypt-cert.sh admin@example.com meet.example.comThis requests a certificate and configures reload hooks. Older installations actually managed by Certbot should instead test their saved renewal configuration, then renew due certificates: [S11][S12]
Terminalsudo certbot renew --dry-run sudo certbot renew
Verify
For Docker stable-11248 and package installs, inspect the endpoint from a machine with OpenSSL 3.0: [S10]
openssl s_client -connect meet.example.com:443 -servername meet.example.com </dev/null 2>/dev/null | openssl x509 -noout -issuer -dates -serial
openssl s_client -connect meet.example.com:443 -servername meet.example.com </dev/null 2>/dev/null | openssl x509 -noout -checkend 0
openssl s_client -connect meet.example.com:443 -servername meet.example.com -verify_hostname meet.example.com -verify_return_error </dev/nullThe expiry check should print Certificate will not expire and exit zero. The trust and hostname check should show Verify return code: 0 (ok). Compare the new serial and notAfter with the pre-renewal certificate. These checks prove current validity; one manual renewal cannot prove future scheduling. [S10]
If it still fails
On Docker stable-11248, read web logs again. acme.sh is not installed in /storage/acme.sh, skipping renewals identifies a disabled renewal service. Check the writable storage mount and HTTPS settings. [S6][S7]
Issue #2321 reports a different failure on stable-11146-2: persisted metadata retained /var/run/s6/services/nginx instead of /run/service/nginx, plus the old validation port. The reporter rebuilt the saved ACME state and restored renewal. This is a community recovery report, not proof that PR #2305 failed. Preserve backups before rebuilding account state; the exact safe migration requires checking your stored certificate records. [S14]
For DNS, blocked TCP 80 or failed initial issuance, use Let’s Encrypt failed. Apply the version-specific package-client distinction above. [S16]
FAQ
Which release fixes rootless cron renewal?
Stable-11146-2 includes PR #2305. Stable-11248 is the latest release checked on 2026-10-05 and retains the service. [S3][S4][S6]
Should I run the web container as root?
Use the corrected rootless service. It calls acme.sh directly and no longer needs Debian cron. [S2][S6]
Is certificate state stored in CONFIG/tmp?
No. Current state is under ${CONFIG}/storage/web; the removed temporary mount held crontabs. [S2][S5]
Can I renew after the certificate has expired?
Yes, HTTP-01 uses port 80. Fix validation, renew with the matching client, and check the certificate served on port 443. [S9][S10][S15]
Sources
[S1] Issue #2301, 2026-08-08, community report, closed 2026-08-17.
[S2] PR #2305, 2026-08-17, maintainer explanation and source code.
[S3] stable-11146-2, 2026-08-17, release note, includes #2300 and #2305.
[S4] Latest release, checked 2026-10-05, release note, stable-11248 published 2026-09-14.
[S5] Compose, stable-11248, checked 2026-10-05, source code.
[S6] Renewal service, stable-11248 and s6 environment, v3.2.3.0, checked 2026-10-05, source code and official doc.
[S7] Web startup and TLS paths, checked 2026-10-05, source code.
[S8] Docker handbook, checked 2026-10-05, official doc.
[S9] acme.sh 3.0.7, Docker client pin and renewal instructions, checked 2026-10-05, source code and official doc.
[S10] OpenSSL x509, s_client, x509 output and TLS output, checked 2026-10-05, official docs and source code.
[S11] Package helper, jitsi-meet_11248, checked 2026-10-05, source code.
[S12] Certbot renewal, checked 2026-10-05, official doc.
[S13] Compose commands, exec, up and restart, checked 2026-10-05, official docs.
[S14] Issue #2321 and reporter’s follow-up, checked 2026-10-05, community report.
[S15] HTTP-01 and rate limits, checked 2026-10-05, official docs.
[S16] Let’s Encrypt failed, updated 2026-10-04, independent community guide.
Open questions
No running Jitsi server was used to test forced renewal, reload timing or expired-site recovery. Confirm those in a maintenance window. No universal migration for the stale metadata in #2321 was verified. Older package certificate-client transitions were not traced release by release.