Add shared nginx-proxy role; deploy Hermes in Docker; rename Paperclip
nginx-proxy (new role): - Shared nginx + certbot under /opt/nginx, replacing the copies that lived inside the Paperclip compose project - Apps publish via tasks_from: add_vhost (cert marker -> issue cert -> write vhost -> nginx -t -> reload); a vhost that fails nginx -t is rolled back - Certs issued one per domain via Cloudflare DNS challenge; domains registered as marker files in cert-domains/; optional LE staging - Stock nginx.conf plus conf.d (directory mounts, not single-file mounts); catch-all server drops unknown Host/SNI - Containers renamed to nginx and certbot hermes_docker (new role): - Official Hermes image, host networking, gateway and dashboard bound to loopback and published through nginx-proxy - Dashboard login via basic-auth provider, secrets from the vault - Main model set from hermes_model (fantasmic endpoint, key from vault); config.yaml overrides are merged from a 0600 staged file that is removed afterwards, so the key never appears in a command line - Data dir owner-only (HERMES_HOME_MODE=0700) paperclip-docker: - Remove nginx, certbot and docker-compose download tasks; deploy with community.docker.docker_compose_v2 (idempotent, remove_orphans) - Stop passing the Cloudflare token and certbot email to the Paperclip container via env_file - Bind Postgres to 127.0.0.1 (host networking exposed it on all interfaces); stop chowning pgdata, which the postgres image owns - Handler recreates the paperclip service so .env changes apply - Domain m-v.wdw-labs.cloud -> cranium-command.wdw-labs.cloud Playbooks: - Add day1_deploy_nginx_proxy.yml and day1_deploy_hermes_docker.yml - deploy_paperclip_stack.yml: run nginx-proxy before paperclip-docker, CLI-based container checks (no Docker SDK dependency) - Remove deploy-hermes.yml Host vars: add nginx_proxy_certbot_email and nginx_proxy_certbot_staging (staging stays on until the switch to real certs).
This commit is contained in:
1 parent
5b48536c32
commit
881e2e24a8
37 files changed
+1683
-755
No files matched your search
@@ -0,0 +1,92 @@
|
||||
#!/bin/sh
|
||||
# Issues certificates (one per domain) via the Cloudflare DNS challenge.
|
||||
#
|
||||
# certbot-init.sh -> every domain with a marker file in $DOMAINS_DIR
|
||||
# certbot-init.sh a.example.com -> only the domains given as arguments
|
||||
#
|
||||
# Idempotent: domains that already have a certificate are skipped.
|
||||
# Renewal is NOT handled here; `certbot renew` covers every existing lineage.
|
||||
set -eu
|
||||
|
||||
DOMAINS_DIR="${DOMAINS_DIR:-/etc/cert-domains.d}"
|
||||
EMAIL="${CERTBOT_EMAIL:-}"
|
||||
TOKEN="${CLOUDFLARE_API_TOKEN:-}"
|
||||
|
||||
STAGING_ARG=""
|
||||
if [ "${CERTBOT_STAGING:-0}" = "1" ]; then
|
||||
STAGING_ARG="--server https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
echo "NOTE: using the Let's Encrypt STAGING server (certificates will not be trusted)"
|
||||
fi
|
||||
|
||||
if [ "$#" -gt 0 ]; then
|
||||
DOMAINS="$*"
|
||||
elif [ -d "$DOMAINS_DIR" ]; then
|
||||
DOMAINS=$(ls -1 "$DOMAINS_DIR" | grep -E '^[A-Za-z0-9]([A-Za-z0-9.-]*[A-Za-z0-9])?\.[A-Za-z]{2,}$' || true)
|
||||
else
|
||||
DOMAINS=""
|
||||
fi
|
||||
DOMAINS=$(printf '%s\n' "$DOMAINS" | tr ', \t' '\n\n\n' | grep -v '^$' | sort -u || true)
|
||||
|
||||
if [ -z "$DOMAINS" ]; then
|
||||
echo "No domains registered in $DOMAINS_DIR; nothing to do"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$EMAIL" ]; then
|
||||
echo "ERROR: CERTBOT_EMAIL not set"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$TOKEN" ]; then
|
||||
echo "ERROR: CLOUDFLARE_API_TOKEN not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Temporary credentials file, shared by all requests and always cleaned up
|
||||
CREDS_FILE=$(mktemp /tmp/cloudflare.XXXXXX)
|
||||
trap 'rm -f "$CREDS_FILE"' EXIT
|
||||
chmod 600 "$CREDS_FILE"
|
||||
printf 'dns_cloudflare_api_token = %s\n' "$TOKEN" > "$CREDS_FILE"
|
||||
|
||||
FAILED=""
|
||||
ISSUED=0
|
||||
SKIPPED=0
|
||||
|
||||
for DOMAIN in $DOMAINS; do
|
||||
CERT_PATH="/etc/letsencrypt/live/${DOMAIN}/fullchain.pem"
|
||||
|
||||
if [ -f "$CERT_PATH" ]; then
|
||||
echo "Certificate for $DOMAIN already exists at $CERT_PATH"
|
||||
SKIPPED=$((SKIPPED + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "Requesting certificate for $DOMAIN via Cloudflare DNS challenge..."
|
||||
|
||||
# --cert-name pins the lineage directory to the domain name so the
|
||||
# live/<domain>/ path nginx expects never gets a -0001 suffix.
|
||||
# STAGING_ARG is intentionally unquoted (it expands to two words).
|
||||
# shellcheck disable=SC2086
|
||||
if certbot certonly \
|
||||
--dns-cloudflare \
|
||||
--dns-cloudflare-credentials "$CREDS_FILE" \
|
||||
--agree-tos \
|
||||
--no-eff-email \
|
||||
--email "$EMAIL" \
|
||||
--non-interactive \
|
||||
--cert-name "$DOMAIN" \
|
||||
$STAGING_ARG \
|
||||
-d "$DOMAIN" && [ -f "$CERT_PATH" ]; then
|
||||
echo "Certificate obtained and verified for $DOMAIN at $CERT_PATH"
|
||||
ISSUED=$((ISSUED + 1))
|
||||
else
|
||||
echo "ERROR: Failed to obtain certificate for $DOMAIN"
|
||||
FAILED="$FAILED $DOMAIN"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Summary: $ISSUED issued, $SKIPPED already present"
|
||||
|
||||
if [ -n "$FAILED" ]; then
|
||||
echo "ERROR: certificate request failed for:$FAILED"
|
||||
exit 1
|
||||
fi
|
||||
Reference in new issue
Block a user