Skip to content

Instantly share code, notes, and snippets.

@theodson
Created August 14, 2026 01:37
Show Gist options
  • Select an option

  • Save theodson/9a7cecb9472c62ec86cd148459e2350e to your computer and use it in GitHub Desktop.

Select an option

Save theodson/9a7cecb9472c62ec86cd148459e2350e to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
#
# Rebuild the CA bundle Herd's PHP uses, appending locally-trusted development
# root CAs (OrbStack, mkcert) that ship in the macOS login keychain but are
# absent from the Mozilla bundle Herd manages.
#
# Why: PHP/curl verifies against a static cacert.pem and does NOT consult the
# macOS keychain. Browsers and system curl do, which is why https://*.orb.local
# works everywhere except PHP, where it fails with:
# cURL error 60: SSL certificate ... self-signed certificate in certificate chain (19)
#
# Re-run this after Herd updates cacert.pem, or after OrbStack regenerates its
# root CA (e.g. a reinstall).
#
set -euo pipefail
HERD_PHP_CONFIG="${HOME}/Library/Application Support/Herd/config/php"
UPSTREAM="${HERD_PHP_CONFIG}/cacert.pem"
OUTPUT="${HERD_PHP_CONFIG}/cacert-with-local-cas.pem"
# Development root CAs to pull from the login keychain, by common-name match.
LOCAL_CAS=(
"OrbStack Development Root CA"
"mkcert"
)
if [[ ! -f "${UPSTREAM}" ]]; then
echo "error: Herd CA bundle not found at ${UPSTREAM}" >&2
exit 1
fi
TMP="$(mktemp)"
trap 'rm -f "${TMP}"' EXIT
cat "${UPSTREAM}" > "${TMP}"
for ca in "${LOCAL_CAS[@]}"; do
if certs="$(security find-certificate -a -c "${ca}" -p "${HOME}/Library/Keychains/login.keychain-db" 2>/dev/null)" \
&& [[ -n "${certs}" ]]; then
{
printf '\n# ---- local development CA: %s ----\n' "${ca}"
printf '%s\n' "${certs}"
} >> "${TMP}"
echo "added: ${ca}"
else
echo "skipped (not in login keychain): ${ca}"
fi
done
mv "${TMP}" "${OUTPUT}"
trap - EXIT
echo
echo "wrote ${OUTPUT} ($(grep -c 'BEGIN CERTIFICATE' "${OUTPUT}") certificates)"
echo "Herd's php.ini files should point curl.cainfo/openssl.cafile at this file."
echo "Run 'herd restart' for PHP-FPM to pick up changes."

Comments are disabled for this gist.