Posted on
Artificial Intelligence

Artificial Intelligence CDN Optimisation

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

AI-Driven CDN Optimisation with Bash: Predict, Pre‑warm, and Profit

Ever watched a blog post go viral and your origin creak while your CDN cache is still cold? Or seen TTFB spike because your TTLs aren’t tuned for real traffic patterns? AI can help you predict what users will want next—and your Bash toolbox can put those predictions to work.

This post shows you how to glue together logs, a lightweight AI prompt, and a few trusty CLI tools to:

  • Forecast hot assets from recent traffic

  • Pre-warm the CDN before the crowd shows up

  • Auto-tune cache TTLs based on predicted demand

  • Automate it all with cron

All from a Linux shell.

Why this is worth your time

  • CDN caches are only as good as what’s in them and how long they stay. Manual tuning can’t keep up with flash crowds or product drops.

  • AI (even a small LLM prompt) can spot likely next-clicks and hot segments from raw logs—without standing up a full ML pipeline.

  • Pre-warming and adaptive TTLs reduce TTFB and increase offload, saving origin resources and often cutting costs.

You don’t need to rewrite your stack—just add a thin AI-driven loop onto your existing CDN and NGINX/Apache logs.


Prerequisites (install once)

We’ll use curl, jq, and cron. Install them with your package manager:

Debian/Ubuntu (apt):

sudo apt update
sudo apt install -y curl jq cron
sudo systemctl enable --now cron

Fedora/RHEL/CentOS (dnf):

sudo dnf install -y curl jq cronie
sudo systemctl enable --now crond

openSUSE (zypper):

sudo zypper refresh
sudo zypper install -y curl jq cron
sudo systemctl enable --now cron

Optional: if you run NGINX and want to auto-reload TTL maps:

  • Debian/Ubuntu:
sudo apt install -y nginx
  • Fedora/RHEL/CentOS:
sudo dnf install -y nginx
  • openSUSE:
sudo zypper install -y nginx

Optional (local inference instead of a cloud LLM): Ollama

curl -fsSL https://ollama.com/install.sh | sh
# example model
ollama pull llama3.1:8b

Note: If you use a cloud LLM, set environment variables (export them in your shell or a .env file used by cron):

export AI_BASE_URL="https://api.openai.com/v1"   # Any OpenAI-compatible endpoint works
export AI_MODEL="gpt-4o-mini"                    # Or your chosen model
export AI_API_KEY="sk-..."                       # Your API key

Architecture at a glance

  • Collect a sliding window of access logs.

  • Ask an LLM to return a compact JSON list of “hot” URLs and recommended TTLs.

  • Pre-warm those URLs via HEAD/GET through your CDN hostname.

  • Optionally write an NGINX TTL map and reload.

  • Run every 10 minutes via cron.


Step 1 — Sample your CDN/NGINX logs

This snippet extracts the most-hit paths from your recent log lines (Nginx combined format assumed), strips obvious noise, and builds a JSON payload for AI input.

#!/usr/bin/env bash
set -euo pipefail

LOG_FILE="${LOG_FILE:-/var/log/nginx/access.log}"
SAMPLE_LINES="${SAMPLE_LINES:-50000}"
WORK_DIR="${WORK_DIR:-/tmp/ai-cdn}"
mkdir -p "$WORK_DIR"

# Pull last N lines and extract request paths from NGINX combined log format
tail -n "$SAMPLE_LINES" "$LOG_FILE" \
  | awk -F\" '($2 ~ /^GET|^HEAD/){split($2,a," "); print a[2]}' \
  | grep -E '^/[A-Za-z0-9._~:/?#@!$&'"'"'()*+,;=%-]+' \
  | grep -v -E '\?(utm_|fbclid|gclid|_ga=)' \
  | grep -v -E '(\.php|\.cgi|/admin|/login|/wp-admin|/cart|/checkout)' \
  | awk 'length($0) < 200' \
  | sort \
  | uniq -c \
  | sort -nr \
  | head -n 500 \
  | awk '{count=$1; $1=""; path=substr($0,2); printf("{\"path\":\"%s\",\"hits\":%s}\n", path, count)}' \
  > "$WORK_DIR/paths.ndjson"

jq -s '.' "$WORK_DIR/paths.ndjson" > "$WORK_DIR/paths.json"
echo "Built sample at $WORK_DIR/paths.json"

Tip:

  • Adjust filters to match your app (e.g., keep image/video extensions; exclude admin/auth).

  • If you use Apache, update the awk extraction appropriately.


Step 2 — Ask AI to predict “what’s hot next”

We’ll ask an OpenAI-compatible endpoint to return a compact JSON object with:

  • hot: a de-duped, ordered array of URLs to pre-warm

  • ttl_seconds: TTL recommendations per path

Cloud LLM example (OpenAI-compatible API):

#!/usr/bin/env bash
set -euo pipefail

WORK_DIR="${WORK_DIR:-/tmp/ai-cdn}"
AI_BASE_URL="${AI_BASE_URL:-https://api.openai.com/v1}"
AI_MODEL="${AI_MODEL:-gpt-4o-mini}"
AI_API_KEY="${AI_API_KEY:?AI_API_KEY not set}"
AI_MAX_URLS="${AI_MAX_URLS:-100}"

PROMPT_SYS='You are a CDN operations assistant. From recent request paths and hit counts, predict the next hot URLs for the next 30–60 minutes and suggest TTLs. Output ONLY compact JSON:
{"hot":["/a","/b"],"ttl_seconds":{"/a":3600,"/b":1800}}
Rules:

- Max '"$AI_MAX_URLS"' entries in "hot".

- Include only cacheable, GET-able assets (no admin/auth/private).

- Prefer static assets and popular product/category pages.

- TTLs: 10m–2h. Shorter for frequently changing pages, longer for static assets.

- No extra text.'

DATA_JSON=$(cat "$WORK_DIR/paths.json" | jq -c .)
HOUR_UTC=$(date -u +%H)

REQ=$(jq -n \
  --arg model "$AI_MODEL" \
  --arg sys "$PROMPT_SYS" \
  --arg data "$DATA_JSON" \
  --arg hour "$HOUR_UTC" \
  '{
    model: $model,
    temperature: 0.2,
    messages: [
      {role:"system", content:$sys},
      {role:"user", content: ("Recent paths (JSON array): " + $data + "\nCurrent UTC hour: " + $hour)}
    ]
  }')

curl -sS \
  -H "Authorization: Bearer $AI_API_KEY" \
  -H "Content-Type: application/json" \
  -d "$REQ" \
  "$AI_BASE_URL/chat/completions" \
  | jq -r '.choices[0].message.content' \
  > "$WORK_DIR/ai_raw.txt"

# Ensure valid JSON; fall back to top hitters if AI returns junk
if ! jq -e . >/dev/null 2>&1 < "$WORK_DIR/ai_raw.txt"; then
  echo "AI returned non-JSON; falling back to top 50."
  jq -r '.[0:50] | map(.path) | {hot:., ttl_seconds:{}}' "$WORK_DIR/paths.json" > "$WORK_DIR/ai.json"
else
  cat "$WORK_DIR/ai_raw.txt" > "$WORK_DIR/ai.json"
fi

jq -r '.hot[]' "$WORK_DIR/ai.json" > "$WORK_DIR/hot_paths.txt"
echo "AI predicted $(wc -l < "$WORK_DIR/hot_paths.txt") hot paths"

Local LLM with Ollama (optional):

# Assuming ollama serve is running and a model is pulled
PROMPT=$(cat <<'EOF'
SYSTEM:
You are a CDN operations assistant...
[Same JSON-only rules as above]
USER:
Recent paths (JSON array): __DATA__
Current UTC hour: __HOUR__
EOF
)

DATA_JSON=$(cat "$WORK_DIR/paths.json" | jq -c .)
HOUR_UTC=$(date -u +%H)
PROMPT_FILLED="${PROMPT/__DATA__/$DATA_JSON}"
PROMPT_FILLED="${PROMPT_FILLED/__HOUR__/$HOUR_UTC}"

curl -s http://localhost:11434/api/generate \
  -d "$(jq -n --arg m "llama3.1:8b" --arg p "$PROMPT_FILLED" '{model:$m,prompt:$p,stream:false}')" \
  | jq -r '.response' > "$WORK_DIR/ai.json"

jq -r '.hot[]' "$WORK_DIR/ai.json" > "$WORK_DIR/hot_paths.txt"

Privacy note: If using a cloud LLM, ensure you don’t send PII, tokens, or secrets. The filters above strip common noise, but review for your app.


Step 3 — Pre-warm your CDN

Hit the predicted hot URLs through your CDN hostname (not origin) with fast, parallel HEAD requests. This fills edge caches ahead of demand.

#!/usr/bin/env bash
set -euo pipefail

WORK_DIR="${WORK_DIR:-/tmp/ai-cdn}"
CDN_HOST="${CDN_HOST:?Set CDN_HOST to your CDN zone, e.g. cdn.example.com}"
CONCURRENCY="${CONCURRENCY:-16}"

# Use HEAD to avoid heavy origin load; switch to GET for CDNs that need object body to cache
xargs -I{} -P "$CONCURRENCY" \
  curl -sSI "https://$CDN_HOST{}" \
    -H 'User-Agent: ai-cdn-prewarmer/1.0' \
    -H 'Cache-Control: no-transform' \
    -o /dev/null \
    -w '%{http_code} %{url_effective}\n' \
  < "$WORK_DIR/hot_paths.txt" \
  | tee "$WORK_DIR/prewarm_report.txt"

Tips:

  • Handle variants (webp/avif, mobile) if your site uses content negotiation.

  • Pre-warm regional POPs by running the job from different regions or via proxies if needed.


Step 4 — Adaptive TTL maps (NGINX example)

If you terminate at NGINX and use proxy_cache, you can feed AI-suggested TTLs into a map include and reload.

First, create an include file and a simple map (once):

sudo tee /etc/nginx/conf.d/cache-ttl-map.conf >/dev/null <<'NGINX'
map $request_uri $ai_cache_ttl {
    default 10m;
    include /etc/nginx/conf.d/hot-uris.ttl;
}
# Example usage in your location/server:
# proxy_cache_valid 200 $ai_cache_ttl;
NGINX
sudo touch /etc/nginx/conf.d/hot-uris.ttl
sudo nginx -t && sudo systemctl reload nginx

Now, write TTLs from AI output and reload:

#!/usr/bin/env bash
set -euo pipefail

WORK_DIR="${WORK_DIR:-/tmp/ai-cdn}"
TTL_FILE="/etc/nginx/conf.d/hot-uris.ttl"

if [[ -f "$WORK_DIR/ai.json" ]] && command -v nginx >/dev/null 2>&1; then
  # Convert {"ttl_seconds":{"/a":3600,...}} to NGINX map lines: /a 3600s;
  if jq -e '.ttl_seconds' "$WORK_DIR/ai.json" >/dev/null 2>&1; then
    sudo bash -c "jq -r '.ttl_seconds | to_entries[] | \"\(.key) \(.value)s;\"' '$WORK_DIR/ai.json' > '$TTL_FILE'"
    sudo nginx -t && sudo systemctl reload nginx
    echo "Updated TTL map and reloaded NGINX."
  else
    echo "No ttl_seconds provided; skipping TTL update."
  fi
else
  echo "NGINX not found or ai.json missing; skipping TTL update."
fi

If you’re not on NGINX, adapt the same idea to your edge platform (e.g., VCL for Varnish, edge rules for your CDN provider).


Step 5 — Automate with cron

Run the full loop every 10 minutes. Place a wrapper at /usr/local/bin/ai-cdn-optimize.sh:

#!/usr/bin/env bash
set -euo pipefail

export LOG_FILE="/var/log/nginx/access.log"
export WORK_DIR="/tmp/ai-cdn"
export AI_BASE_URL="${AI_BASE_URL:-https://api.openai.com/v1}"
export AI_MODEL="${AI_MODEL:-gpt-4o-mini}"
export AI_API_KEY="${AI_API_KEY:?AI_API_KEY not set}"
export AI_MAX_URLS="${AI_MAX_URLS:-100}"
export CDN_HOST="${CDN_HOST:?Set CDN_HOST e.g. cdn.example.com}"
export CONCURRENCY="${CONCURRENCY:-16}"

# 1) sample logs
/path/to/step1.sh
# 2) ask AI
/path/to/step2.sh
# 3) pre-warm
/path/to/step3.sh
# 4) TTL update (optional)
/path/to/step4.sh

Create a cron job:

sudo tee /etc/cron.d/ai-cdn-optimize >/dev/null <<'CRON'
*/10 * * * * root /usr/local/bin/ai-cdn-optimize.sh >> /var/log/ai-cdn-optimize.log 2>&1
CRON

Service enablement recap:

  • Debian/Ubuntu: systemctl enable --now cron

  • Fedora/RHEL/CentOS: systemctl enable --now crond

  • openSUSE: systemctl enable --now cron


Real-world notes and guardrails

  • Keep it safe: Do not pre-warm authenticated or user-specific URLs. Filter aggressively.

  • Respect robots, rate limits, and provider billing. Throttle pre-warm concurrency if needed.

  • Measure: Track TTFB, cache hit ratio, origin CPU/egress before and after. Aim for higher offload and lower p95 TTFB.

  • Cost/latency trade-offs: Long TTLs are great for static assets, shorter for fast-changing pages. Let the AI propose, but you decide the bounds.

  • Rollback: Keep a default TTL map and revert if AI output looks wrong.


Conclusion and next steps

You don’t need a data science team to get AI benefits at the edge. A few Bash scripts + your logs + a small LLM prompt can:

  • Predict and pre-warm hot content

  • Auto-tune TTLs based on demand

  • Reduce TTFB and origin load during spikes

Your next step: 1) Install prerequisites (curl, jq, cron) using apt/dnf/zypper. 2) Wire up the scripts against your logs and CDN hostname. 3) Test on a staging CDN zone, then schedule via cron. 4) Measure results and iterate on filters/prompt.

Have questions or want a production-hardened version for your stack? Drop a comment with your distro/CDN and we’ll tailor a script.