This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/docker-entrypoint-fe.sh
2026-03-03 13:12:13 +00:00

185 lines
5.4 KiB
Bash

#!/bin/sh
# ============================================
# Chat Switchboard - Frontend Entrypoint
# ============================================
# nginx serves static assets and proxies page
# routes to the Go backend for template rendering.
# API/WS routes are handled by Ingress directly.
#
# Environment (required):
# BACKEND_URL - Backend service URL
# (e.g. "http://switchboard-be:8080")
#
# Environment (optional):
# BASE_PATH - URL prefix (e.g. "/dev", "" for root)
# ENVIRONMENT - Environment name for logging
# ============================================
set -e
BASE_PATH="${BASE_PATH:-}"
BACKEND_URL="${BACKEND_URL:?BACKEND_URL is required (e.g. http://switchboard-be:8080)}"
ENVIRONMENT="${ENVIRONMENT:-production}"
# Read version from VERSION file (baked in at build time)
APP_VERSION="dev"
if [ -f /VERSION ]; then
APP_VERSION=$(cat /VERSION | tr -d '[:space:]')
fi
# Compute build hash from JS file contents (unique per deploy)
BUILD_HASH=$(find /usr/share/nginx/html/js -name '*.js' -exec md5sum {} + 2>/dev/null | sort | md5sum | cut -c1-8)
if [ -z "${BUILD_HASH}" ]; then
BUILD_HASH=$(date +%s | md5sum | cut -c1-8)
fi
# ── Inject into index.html (redirect page) ──
sed -i \
-e "s|%%BASE_PATH%%|${BASE_PATH}|g" \
-e "s|%%APP_VERSION%%|${APP_VERSION}|g" \
/usr/share/nginx/html/index.html
# Inject version and build hash into service worker
sed -i \
-e "s|%%APP_VERSION%%|${APP_VERSION}|g" \
-e "s|%%BUILD_HASH%%|${BUILD_HASH}|g" \
/usr/share/nginx/html/sw.js
echo "✅ Frontend: BASE_PATH=${BASE_PATH:-/} VERSION=${APP_VERSION} BUILD=${BUILD_HASH} BACKEND=${BACKEND_URL}"
# ── Page route proxy blocks ─────────────────
page_proxy_block() {
local path="$1"
cat <<PROXY
location ${path} {
proxy_pass ${BACKEND_URL};
proxy_http_version 1.1;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
}
PROXY
}
PAGE_ROUTES=$(cat <<ROUTES
# ── Page routes → backend ────────────────
$(page_proxy_block "= ${BASE_PATH}/")
$(page_proxy_block "= ${BASE_PATH}/login")
location ~ ^${BASE_PATH}/chat/[^/]+\$ {
proxy_pass ${BACKEND_URL};
proxy_http_version 1.1;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
}
$(page_proxy_block "${BASE_PATH}/admin")
$(page_proxy_block "${BASE_PATH}/editor")
$(page_proxy_block "${BASE_PATH}/notes")
$(page_proxy_block "${BASE_PATH}/settings")
ROUTES
)
# ── Generate nginx config ───────────────────
if [ -z "${BASE_PATH}" ]; then
cat > /etc/nginx/conf.d/default.conf <<NGINX
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml application/javascript;
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location = /sw.js {
expires off;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
location /branding/ {
alias /branding/;
expires 1h;
add_header Cache-Control "public";
try_files \$uri =404;
}
${PAGE_ROUTES}
location / {
try_files \$uri \$uri/ /index.html;
}
location = /healthz {
return 200 'ok';
add_header Content-Type text/plain;
}
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}
NGINX
else
cat > /etc/nginx/conf.d/default.conf <<NGINX
server {
listen 80;
server_name _;
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml application/javascript;
${PAGE_ROUTES}
location ${BASE_PATH}/ {
alias /usr/share/nginx/html/;
try_files \$uri \$uri/ ${BASE_PATH}/index.html;
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)\$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location = ${BASE_PATH}/sw.js {
alias /usr/share/nginx/html/sw.js;
expires off;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
}
location ${BASE_PATH}/branding/ {
alias /branding/;
expires 1h;
add_header Cache-Control "public";
try_files \$uri =404;
}
location = ${BASE_PATH} {
return 301 ${BASE_PATH}/;
}
location = /healthz {
return 200 'ok';
add_header Content-Type text/plain;
}
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}
NGINX
fi
exec nginx -g 'daemon off;'