Skip to content

Deploy Natali Proxy Worker #12

Deploy Natali Proxy Worker

Deploy Natali Proxy Worker #12

Workflow file for this run

name: Deploy Natali Proxy Worker
on:
workflow_dispatch:
permissions:
contents: read
jobs:
deploy-proxy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy Natali Proxy Worker
env:
CF_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: |
set -x
ZONE_ID="5b3f8237bfa2518bff375eb8163623a5"
WORKER_NAME="natalie-proxy"
cat > /tmp/worker.js << 'WORKEREOF'
const RAW_BASE = 'https://raw.githubusercontent.com/spivanatalie64/spivanatalie64.github.io/gh-pages';
const GH_BASE = 'https://spivanatalie64.github.io';
// Map file extensions to content types
const MIME_TYPES = {
'.html': 'text/html; charset=utf-8',
'.css': 'text/css; charset=utf-8',
'.js': 'application/javascript; charset=utf-8',
'.json': 'application/json; charset=utf-8',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.ico': 'image/x-icon',
'.webp': 'image/webp',
'.pdf': 'application/pdf',
'.woff': 'font/woff',
'.woff2': 'font/woff2',
'.ttf': 'font/ttf',
};
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
try {
const url = new URL(request.url);
let path = url.pathname;
// For root or any non-file path, serve index.html (SPA)
const isAsset = path.match(/\.\w+$/);
if (!isAsset) {
// Remove trailing slash
if (path.endsWith('/') && path.length > 1) {
path = path.slice(0, -1);
}
// SPA fallback - serve index.html for all non-asset routes
const indexUrl = RAW_BASE + '/index.html';
const response = await fetch(indexUrl);
if (response.ok) {
const newHeaders = new Headers(response.headers);
newHeaders.set('Content-Type', 'text/html; charset=utf-8');
newHeaders.set('X-Proxied-By', 'natalie-worker');
newHeaders.set('Cache-Control', 'public, max-age=0, s-maxage=300');
return new Response(response.body, {
status: 200,
statusText: 'OK',
headers: newHeaders,
});
}
return new Response('Not Found', { status: 404 });
}
// For assets, fetch from raw.githubusercontent.com
const assetUrl = RAW_BASE + path;
const response = await fetch(assetUrl);
if (response.ok) {
const ext = path.match(/\.(\w+)$/)[0];
const contentType = MIME_TYPES[ext] || response.headers.get('Content-Type') || 'application/octet-stream';
const newHeaders = new Headers(response.headers);
newHeaders.set('Content-Type', contentType);
newHeaders.set('X-Proxied-By', 'natalie-worker');
newHeaders.set('Cache-Control', 'public, max-age=86400, s-maxage=604800');
return new Response(response.body, {
status: 200,
statusText: 'OK',
headers: newHeaders,
});
}
// Fallback: try GH Pages (might redirect, but worth a shot)
const ghResponse = await fetch(GH_BASE + path, {
headers: { 'Host': 'natalie.acreonetionos.org' },
redirect: 'manual',
});
if (ghResponse.status === 200) {
const newHeaders = new Headers(ghResponse.headers);
newHeaders.set('X-Proxied-By', 'natalie-worker');
return new Response(ghResponse.body, {
status: 200,
statusText: 'OK',
headers: newHeaders,
});
}
// Last resort: serve index.html for SPA
const indexResponse = await fetch(RAW_BASE + '/index.html');
if (indexResponse.ok) {
const newHeaders = new Headers(indexResponse.headers);
newHeaders.set('Content-Type', 'text/html; charset=utf-8');
newHeaders.set('X-Proxied-By', 'natalie-worker');
return new Response(indexResponse.body, {
status: 200,
statusText: 'OK',
headers: newHeaders,
});
}
return new Response('Not Found', { status: 404 });
} catch (err) {
return new Response('Worker Error: ' + err.message, {
status: 500,
headers: { 'Content-Type': 'text/plain' },
});
}
}
WORKEREOF
cat > /tmp/metadata.json << 'METADATAEOF'
{
"body_part": "script",
"bindings": [],
"compatibility_date": "2026-06-20",
"compatibility_flags": []
}
METADATAEOF
curl -s -X PUT \
"https://api.cloudflare.com/client/v4/accounts/6a46b418508c26278ae2d3373f41da81/workers/scripts/$WORKER_NAME" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-F "metadata=@/tmp/metadata.json;type=application/json" \
-F "script=@/tmp/worker.js;type=application/javascript" | jq .
EXISTING_ROUTES=$(curl -s -H "Authorization: Bearer $CF_API_TOKEN" \
"https://api.cloudflare.com/client/v4/zones/$ZONE_ID/workers/routes")
NATALIE_ROUTE_ID=$(echo "$EXISTING_ROUTES" | jq -r '.result[] | select(.pattern == "natalie.acreetionos.org/*") | .id')
curl -s -X PUT \
"https://api.cloudflare.com/client/v4/zones/$ZONE_ID/workers/routes/$NATALIE_ROUTE_ID" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"pattern\": \"natalie.acreetionos.org/*\",
\"script\": \"$WORKER_NAME\"
}" | jq .
echo "=== Done ==="