Support separate auth domain (e.g. auth.cameleer.io) for Logto while
keeping the SaaS app on PUBLIC_HOST (e.g. app.cameleer.io). AUTH_HOST
defaults to PUBLIC_HOST for backward-compatible single-domain setups.
- Logto routing: Host(AUTH_HOST) replaces PathPrefix('/') catch-all
- Root redirect moved from traefik-dynamic.yml to Docker labels with
Host(PUBLIC_HOST) scope so it doesn't intercept auth domain
- Self-signed cert generates SANs for both domains
- Bootstrap Host header uses AUTH_HOST for Logto endpoint validation
- Spring issuer-uri and oidcissueruri use new authhost property
- Both installers (sh + ps1) prompt for AUTH_HOST in expert mode
Local dev: AUTH_HOST=auth.localhost (resolves to 127.0.0.1, no hosts file)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
69 lines
2.6 KiB
Bash
69 lines
2.6 KiB
Bash
#!/bin/sh
|
|
set -e
|
|
|
|
CERTS_DIR="/certs"
|
|
|
|
# Skip if certs already exist (idempotent)
|
|
if [ ! -f "$CERTS_DIR/cert.pem" ]; then
|
|
mkdir -p "$CERTS_DIR"
|
|
|
|
if [ -n "$CERT_FILE" ] && [ -n "$KEY_FILE" ]; then
|
|
# User-supplied certificate
|
|
echo "[certs] Installing user-supplied certificate..."
|
|
cp "$CERT_FILE" "$CERTS_DIR/cert.pem"
|
|
cp "$KEY_FILE" "$CERTS_DIR/key.pem"
|
|
if [ -n "$CA_FILE" ]; then
|
|
cp "$CA_FILE" "$CERTS_DIR/ca.pem"
|
|
fi
|
|
# Validate key matches cert
|
|
CERT_MOD=$(openssl x509 -noout -modulus -in "$CERTS_DIR/cert.pem" 2>/dev/null | md5sum)
|
|
KEY_MOD=$(openssl rsa -noout -modulus -in "$CERTS_DIR/key.pem" 2>/dev/null | md5sum)
|
|
if [ "$CERT_MOD" != "$KEY_MOD" ]; then
|
|
echo "[certs] ERROR: Certificate and key do not match!"
|
|
rm -f "$CERTS_DIR/cert.pem" "$CERTS_DIR/key.pem" "$CERTS_DIR/ca.pem"
|
|
exit 1
|
|
fi
|
|
SELF_SIGNED=false
|
|
echo "[certs] Installed user-supplied certificate."
|
|
else
|
|
# Generate self-signed certificate
|
|
HOST="${PUBLIC_HOST:-localhost}"
|
|
AUTH="${AUTH_HOST:-$HOST}"
|
|
echo "[certs] Generating self-signed certificate for $HOST..."
|
|
# Build SAN list; deduplicate when AUTH_HOST equals PUBLIC_HOST
|
|
if [ "$AUTH" = "$HOST" ]; then
|
|
SAN="DNS:$HOST,DNS:*.$HOST"
|
|
else
|
|
SAN="DNS:$HOST,DNS:*.$HOST,DNS:$AUTH,DNS:*.$AUTH"
|
|
echo "[certs] (+ auth domain: $AUTH)"
|
|
fi
|
|
openssl req -x509 -newkey rsa:4096 \
|
|
-keyout "$CERTS_DIR/key.pem" -out "$CERTS_DIR/cert.pem" \
|
|
-days 365 -nodes \
|
|
-subj "/CN=$HOST" \
|
|
-addext "subjectAltName=$SAN"
|
|
SELF_SIGNED=true
|
|
echo "[certs] Generated self-signed certificate for $HOST."
|
|
fi
|
|
|
|
# Write metadata for SaaS app to seed DB
|
|
SUBJECT=$(openssl x509 -noout -subject -in "$CERTS_DIR/cert.pem" 2>/dev/null | sed 's/subject=//')
|
|
FINGERPRINT=$(openssl x509 -noout -fingerprint -sha256 -in "$CERTS_DIR/cert.pem" 2>/dev/null | sed 's/.*=//')
|
|
NOT_BEFORE=$(openssl x509 -noout -startdate -in "$CERTS_DIR/cert.pem" 2>/dev/null | sed 's/notBefore=//')
|
|
NOT_AFTER=$(openssl x509 -noout -enddate -in "$CERTS_DIR/cert.pem" 2>/dev/null | sed 's/notAfter=//')
|
|
HAS_CA=false
|
|
[ -f "$CERTS_DIR/ca.pem" ] && HAS_CA=true
|
|
cat > "$CERTS_DIR/meta.json" <<METAEOF
|
|
{"subject":"$SUBJECT","fingerprint":"$FINGERPRINT","selfSigned":$SELF_SIGNED,"hasCa":$HAS_CA,"notBefore":"$NOT_BEFORE","notAfter":"$NOT_AFTER"}
|
|
METAEOF
|
|
|
|
mkdir -p "$CERTS_DIR/staged" "$CERTS_DIR/prev"
|
|
chmod 775 "$CERTS_DIR" "$CERTS_DIR/staged" "$CERTS_DIR/prev"
|
|
chmod 660 "$CERTS_DIR"/*.pem 2>/dev/null || true
|
|
else
|
|
echo "[certs] Certificates already exist, skipping generation."
|
|
fi
|
|
|
|
# Start Traefik
|
|
exec traefik "$@"
|