chore(ops): gitignore runtime artifacts — .logs/, .pids/, Temp JSON files
Co-Authored-By: Mira Rehfeld <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/env bash
|
||||
# Configure a Bunny.net pull zone for the APIX registry.
|
||||
#
|
||||
# What this script does:
|
||||
# 1. Creates a pull zone pointing at the origin VPS
|
||||
# 2. Enables query-string vary cache (so /services?capability=nlp and
|
||||
# /services?capability=translation are cached as separate entries)
|
||||
# 3. Sets the edge TTL to follow the origin Cache-Control headers
|
||||
# 4. Adds the custom hostname (api-index.org)
|
||||
# 5. Prints the CDN hostname to use in your DNS CNAME record
|
||||
#
|
||||
# Prerequisites:
|
||||
# - A Bunny.net account with an API key (bunny.net → Account → API)
|
||||
# - The origin VPS is reachable at ORIGIN_URL before running this
|
||||
# - DNS for api-index.org is under your control
|
||||
#
|
||||
# Usage:
|
||||
# BUNNYNET_API_KEY=your-key \
|
||||
# ORIGIN_URL=https://your-vps-ip-or-hostname \
|
||||
# CUSTOM_HOSTNAME=api-index.org \
|
||||
# ./scripts/setup-bunnynet.sh
|
||||
#
|
||||
# Optional — enable real-time Loki log forwarding for live telemetry:
|
||||
# SYSLOG_HOST=your-vps-ip \
|
||||
# SYSLOG_PORT=5514 \
|
||||
# ./scripts/setup-bunnynet.sh
|
||||
#
|
||||
# Optional — install weekly cron job (Mondays 06:00) for CDN analytics report:
|
||||
# INSTALL_CRON=true \
|
||||
# ./scripts/setup-bunnynet.sh
|
||||
#
|
||||
# Deploy scripts/promtail-cdn-logs.yaml on the VPS before setting SYSLOG_HOST.
|
||||
# Bunny.net will start streaming access logs (one syslog line per request,
|
||||
# including CDN cache hits) to Promtail, which pushes to your Loki instance.
|
||||
#
|
||||
# CDN selection rationale:
|
||||
# Bunny.net is European (Slovenia), GDPR-compliant, has PoPs in Shanghai,
|
||||
# Singapore, Tokyo, Hong Kong, and Frankfurt. No founding-member conflict
|
||||
# (Cloudflare and AWS are both founding member candidates and must not
|
||||
# operate infrastructure over the registry).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
BUNNYNET_API_KEY="${BUNNYNET_API_KEY:?BUNNYNET_API_KEY is required}"
|
||||
ORIGIN_URL="${ORIGIN_URL:?ORIGIN_URL is required (e.g. https://1.2.3.4)}"
|
||||
CUSTOM_HOSTNAME="${CUSTOM_HOSTNAME:-api-index.org}"
|
||||
PULL_ZONE_NAME="${PULL_ZONE_NAME:-apix-registry}"
|
||||
BUNNYNET_API="https://api.bunny.net"
|
||||
|
||||
# Optional — set SYSLOG_HOST to enable real-time log forwarding to Promtail/Loki.
|
||||
# Bunny.net streams one syslog line per request (all requests, not just misses).
|
||||
# Start Promtail with scripts/promtail-cdn-logs.yaml on the VPS first.
|
||||
SYSLOG_HOST="${SYSLOG_HOST:-}"
|
||||
SYSLOG_PORT="${SYSLOG_PORT:-5514}"
|
||||
INSTALL_CRON="${INSTALL_CRON:-false}"
|
||||
|
||||
echo "==> Creating Bunny.net pull zone '${PULL_ZONE_NAME}' → ${ORIGIN_URL} ..."
|
||||
|
||||
CREATE_RESPONSE=$(curl -sf -X POST "${BUNNYNET_API}/pullzone" \
|
||||
-H "AccessKey: ${BUNNYNET_API_KEY}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"Name": "'"${PULL_ZONE_NAME}"'",
|
||||
"OriginUrl": "'"${ORIGIN_URL}"'",
|
||||
"Type": 0,
|
||||
"EnableQueryStringVaryCache": true,
|
||||
"UseBackgroundUpdate": false,
|
||||
"EnableWebPVary": false,
|
||||
"EnableCountryCodeVary": false,
|
||||
"EnableMobileVary": false,
|
||||
"EnableHostnameVary": false,
|
||||
"IgnoreQueryStrings": false,
|
||||
"CacheControlMaxAgeOverride": -1,
|
||||
"CacheControlBrowserMaxAgeOverride": -1,
|
||||
"EnableLogging": true,
|
||||
"LoggingIPAnonymizationEnabled": true
|
||||
}')
|
||||
|
||||
# -1 on both MaxAgeOverride fields means "respect the origin Cache-Control header"
|
||||
# The application sets: GET / → max-age=60, GET /services|/devices → max-age=30
|
||||
|
||||
PULL_ZONE_ID=$(echo "${CREATE_RESPONSE}" | python3 -c "import sys,json; print(json.load(sys.stdin)['Id'])")
|
||||
CDN_HOSTNAME=$(echo "${CREATE_RESPONSE}" | python3 -c "import sys,json; print(json.load(sys.stdin)['Hostnames'][0]['Value'])")
|
||||
|
||||
echo " Pull zone ID : ${PULL_ZONE_ID}"
|
||||
echo " CDN hostname : ${CDN_HOSTNAME}"
|
||||
|
||||
echo ""
|
||||
echo "==> Adding custom hostname '${CUSTOM_HOSTNAME}' to pull zone ..."
|
||||
|
||||
curl -sf -X POST "${BUNNYNET_API}/pullzone/${PULL_ZONE_ID}/addHostname" \
|
||||
-H "AccessKey: ${BUNNYNET_API_KEY}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"Hostname": "'"${CUSTOM_HOSTNAME}"'"}' > /dev/null
|
||||
|
||||
echo " Done."
|
||||
|
||||
echo ""
|
||||
echo "==> Adding edge rule: bypass cache for internal paths (/q/*) ..."
|
||||
|
||||
curl -sf -X POST "${BUNNYNET_API}/pullzone/${PULL_ZONE_ID}/edgerules/addOrUpdate" \
|
||||
-H "AccessKey: ${BUNNYNET_API_KEY}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"Enabled": true,
|
||||
"Description": "Bypass cache for Quarkus health and metrics endpoints",
|
||||
"ActionType": 15,
|
||||
"Triggers": [{
|
||||
"Type": 0,
|
||||
"PatternMatches": ["/q/"],
|
||||
"PatternMatchingType": 12
|
||||
}],
|
||||
"ActionParameter1": "",
|
||||
"ActionParameter2": ""
|
||||
}' > /dev/null
|
||||
|
||||
echo " Done."
|
||||
|
||||
if [ -n "${SYSLOG_HOST}" ]; then
|
||||
echo ""
|
||||
echo "==> Enabling real-time log forwarding → ${SYSLOG_HOST}:${SYSLOG_PORT} (TCP Syslog) ..."
|
||||
|
||||
curl -sf -X POST "${BUNNYNET_API}/pullzone/${PULL_ZONE_ID}" \
|
||||
-H "AccessKey: ${BUNNYNET_API_KEY}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"LogForwardingEnabled": true,
|
||||
"LogForwardingHostname": "'"${SYSLOG_HOST}"'",
|
||||
"LogForwardingPort": '"${SYSLOG_PORT}"',
|
||||
"LogForwardingProtocol": 1,
|
||||
"LogForwardingToken": ""
|
||||
}' > /dev/null
|
||||
|
||||
echo " Done."
|
||||
echo " Bunny.net will forward every request (hits + misses) as a syslog line."
|
||||
echo " Promtail → Loki → Grafana will show live capability traffic within seconds."
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "==> Purging initial cache to ensure clean state ..."
|
||||
|
||||
curl -sf -X POST "${BUNNYNET_API}/pullzone/${PULL_ZONE_ID}/purgeCache" \
|
||||
-H "AccessKey: ${BUNNYNET_API_KEY}" > /dev/null
|
||||
|
||||
echo " Done."
|
||||
|
||||
echo ""
|
||||
echo "======================================================================"
|
||||
echo " Setup complete. Next steps:"
|
||||
echo ""
|
||||
echo " 1. Add a DNS CNAME record:"
|
||||
echo " ${CUSTOM_HOSTNAME} CNAME ${CDN_HOSTNAME}"
|
||||
echo ""
|
||||
echo " 2. Wait for DNS propagation (~5 minutes for most registrars)"
|
||||
echo ""
|
||||
echo " 3. Bunny.net will provision a free TLS certificate automatically"
|
||||
echo " once the CNAME is live. No manual cert management needed."
|
||||
echo ""
|
||||
echo " 4. Verify the CDN is caching correctly:"
|
||||
echo " curl -sI https://${CUSTOM_HOSTNAME}/ | grep -i cache-control"
|
||||
echo " Expected: Cache-Control: public, max-age=60"
|
||||
echo ""
|
||||
echo " 5. Test from Asia (requires a remote machine or VPN):"
|
||||
echo " curl -w '%{time_total}s\n' -o /dev/null -s https://${CUSTOM_HOSTNAME}/"
|
||||
echo " First request: ~200ms (cache miss → origin). Subsequent: <20ms (edge)."
|
||||
echo ""
|
||||
echo " CDN hostname : ${CDN_HOSTNAME}"
|
||||
echo " Pull zone ID : ${PULL_ZONE_ID}"
|
||||
echo ""
|
||||
echo " Log access (Bunny.net access logs, gzip, one file per day):"
|
||||
echo " curl -H 'AccessKey: \$BUNNYNET_API_KEY' \\"
|
||||
echo " https://logging.bunnycdn.com/YYYY/MM/DD/${PULL_ZONE_ID}/ -o logs.gz"
|
||||
echo ""
|
||||
echo " Query frequency report (last 7 days):"
|
||||
echo " BUNNYNET_API_KEY=\$BUNNYNET_API_KEY PULL_ZONE_ID=${PULL_ZONE_ID} \\"
|
||||
echo " ./scripts/query-report.sh"
|
||||
echo ""
|
||||
echo " Logs are IP-anonymised (last octet zeroed) for GDPR compliance."
|
||||
echo ""
|
||||
if [ -n "${SYSLOG_HOST}" ]; then
|
||||
echo " Live Loki forwarding : ENABLED → ${SYSLOG_HOST}:${SYSLOG_PORT}"
|
||||
echo " Every request (CDN hit and miss) streams as a syslog line."
|
||||
echo " Grafana dashboard shows capability traffic in real-time."
|
||||
echo " Promtail config: scripts/promtail-cdn-logs.yaml"
|
||||
else
|
||||
echo " Live Loki forwarding : DISABLED (re-run with SYSLOG_HOST=<vps-ip> to enable)"
|
||||
echo " Without this, only cache misses appear in origin Prometheus metrics."
|
||||
echo " For the OpenClaw demo: enable this before the session starts."
|
||||
fi
|
||||
echo "======================================================================"
|
||||
|
||||
# Persist pull zone ID for query-report.sh convenience
|
||||
echo "${PULL_ZONE_ID}" > .bunnynet-pull-zone-id
|
||||
echo ""
|
||||
echo "Pull zone ID saved to .bunnynet-pull-zone-id (add to .gitignore)."
|
||||
|
||||
if [ "${INSTALL_CRON}" = "true" ]; then
|
||||
echo ""
|
||||
echo "==> Installing weekly cron job for CDN analytics report ..."
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPORT_SCRIPT="${SCRIPT_DIR}/query-report.sh"
|
||||
LOG_DIR="${SCRIPT_DIR}/../logs"
|
||||
mkdir -p "${LOG_DIR}"
|
||||
|
||||
CRON_LINE="0 6 * * 1 BUNNYNET_API_KEY=${BUNNYNET_API_KEY} PULL_ZONE_ID=${PULL_ZONE_ID} ${REPORT_SCRIPT} >> ${LOG_DIR}/cdn-report.log 2>&1"
|
||||
|
||||
# Install without duplicating — removes any existing query-report.sh entry first
|
||||
( crontab -l 2>/dev/null | grep -v "query-report\.sh"; echo "${CRON_LINE}" ) | crontab -
|
||||
|
||||
echo " Done."
|
||||
echo " Schedule : every Monday at 06:00"
|
||||
echo " Log : ${LOG_DIR}/cdn-report.log"
|
||||
echo ""
|
||||
echo " Verify with: crontab -l | grep query-report"
|
||||
fi
|
||||
Reference in New Issue
Block a user