#!/bin/bash # CV build, website generation and the Caddy stack snippets. # # Sourced by setup_personal_website.sh; split out to keep it under the 250-line cap. # Sourced rather than run, so it inherits the caller's strict mode and # the helper functions and variables defined above the source line. # --- Phase 5: build the website -------------------------------------------- build_website() { log_info "Installing website dependencies and building…" ( cd "$WEBSITE_SRC" || die "Cannot enter ${WEBSITE_SRC}." pnpm install --frozen-lockfile pnpm run build ) [[ -f "${WEBSITE_SRC}/dist/index.html" ]] || die "Build did not produce ${WEBSITE_SRC}/dist/index.html." log_ok "Website built to ${WEBSITE_SRC}/dist." } # --- Phase 6: write the website's static-serve stack ------------------------ write_website_stack() { ensure_dir "$WEBSITE_DATA_DIR" cat >"$WEBSITE_COMPOSE" <"$WEBSITE_INNER_CADDY" <"$WEBSITE_SNIPPET" </dev/null 2>&1; then docker exec "$CADDY_CONTAINER" caddy reload --config /etc/caddy/Caddyfile log_ok "Reloaded ${CADDY_CONTAINER}." else die "Caddy config invalid — aborting reload. Check ${SITES_DIR}/*.caddy." fi } # --- Phase 10: firewall ----------------------------------------------------- ensure_firewall() { log_info "Ensuring ports 80/443 are open (idempotent)…" sudo bash "$WG_SCRIPT" allow-web } # --- Phase 11: report ------------------------------------------------------- print_report() { cat < https://${GITEA_DOMAIN}//.git Acceptance test (do this on your phone): Turn Wi-Fi OFF (use cellular) and open https://${WEBSITE_DOMAIN}/ — it should load over HTTPS with the hero, live GitHub projects, and CV, and be usable at phone width. ============================================================================ EOF } setup_cmd() { print_setup_header "Personal website setup" preflight migrate_caddy_snippets relocate_gitea build_cv_json build_website write_website_stack write_website_snippet start_website reload_caddy ensure_firewall print_report log_ok "Personal website setup complete." } # --- status: self-diagnose -------------------------------------------------- status_line() { if [[ $1 -eq 0 ]]; then log_ok "$2" else log_warn "$2" fi } check_http() { # Prints 0 to stdout if the URL returns 200, else 1. local url="$1" code code="$(curl -sk -o /dev/null -w '%{http_code}' --max-time 10 "$url" 2>/dev/null || echo 000)" [[ $code == "200" ]] && echo 0 || echo 1 } status_cmd() { print_setup_header "Personal website status" if has_cmd node; then status_line 0 "node present" else status_line 1 "node missing" fi if has_cmd pnpm; then status_line 0 "pnpm present" else status_line 1 "pnpm missing" fi if [[ -f "${WEBSITE_SRC}/dist/index.html" ]]; then status_line 0 "build present (dist/index.html)" else status_line 1 "build missing — run setup" fi if docker ps --format '{{.Names}}' | grep -qx personal-website; then status_line 0 "personal-website container running" else status_line 1 "personal-website container not running" fi status_line "$(check_http "http://127.0.0.1:${WEBSITE_PORT}/")" \ "local static server (127.0.0.1:${WEBSITE_PORT})" if [[ -f $WEBSITE_SNIPPET ]]; then status_line 0 "Caddy website snippet present" else status_line 1 "Caddy website snippet missing" fi if grep -qE '^[[:space:]]*import[[:space:]]+/etc/caddy/sites' "$CADDYFILE" 2>/dev/null; then status_line 0 "root Caddyfile uses snippet imports" else status_line 1 "root Caddyfile not migrated to imports" fi if getent hosts "$WEBSITE_DOMAIN" >/dev/null; then status_line 0 "${WEBSITE_DOMAIN} resolves" else status_line 1 "${WEBSITE_DOMAIN} does not resolve" fi if getent hosts "$GITEA_DOMAIN" >/dev/null; then status_line 0 "${GITEA_DOMAIN} resolves" else status_line 1 "${GITEA_DOMAIN} does not resolve" fi status_line "$(check_http "https://${WEBSITE_DOMAIN}/")" \ "external https://${WEBSITE_DOMAIN}/" status_line "$(check_http "https://${GITEA_DOMAIN}/")" \ "external https://${GITEA_DOMAIN}/" }