# Alex Mercer - Full Site Documentation Archive > Complete concatenated archive of example.com for LLM ingestion, agent analysis, and retrieval. > Canonical URL: https://www.example.com --- # About Alex Mercer - Role: Principal Cloud & Platform Architect - Location: San Francisco, CA - URL: https://www.example.com/about/ ## Summary I’m a Principal Cloud & Platform Architect with over a decade of experience designing resilient distributed systems, multi-region edge delivery networks, and declarative infrastructure-as-code workflows. My engineering philosophy centers on simplicity, observability, and removing moving parts at runtime. Whether architecting global storage replication with AWS S3 Multi-Region Access Points or building zero-SSR static web applications, I prefer systems whose failure modes are predictable and whose deployments are fully reproducible from version control. Outside the terminal, I spend my time photographing minimalist architecture, coastal geometry, and alpine landscapes. ## Career History ### Principal Cloud & Platform Architect — Aether Cloud Systems - Period: March 2024 – Present - Location: San Francisco, CA - Skills: AWS, Terraform, Infrastructure, CI/CD, Architecture - Architected active-active multi-region AWS edge platforms utilizing S3 Multi-Region Access Points (MRAP), CloudFront SigV4a Origin Access Control, and Global Accelerator. - Standardized organization-wide Terraform modules and GitLab CI/CD pipelines with native S3 state locking, cutting deployment lead times by 68%. - Led reliability engineering reviews, SLO error-budget governance, and automated chaos testing across 14 global points of presence. ### Staff Site Reliability Engineer — Veridian Edge Networks - Period: June 2020 – February 2024 (3 yrs 9 mos) - Location: Seattle, WA - Progression: Senior SRE → Staff Site Reliability Engineer - Skills: AWS, Terraform, CI/CD, AstroJS, Tailwind CSS - Designed high-throughput observability pipelines and zero-downtime release automation supporting 40,000+ requests per second at the edge. - Engineered automated TLS/ACM certificate lifecycle tooling, DNSSEC validation, and strict IAM least-privilege boundaries across production AWS accounts. - Authored internal developer documentation and static architecture portals built with Astro and Tailwind CSS. ### Senior Systems & Virtualization Engineer — Helios Datacenter Solutions - Period: January 2017 – May 2020 (3 yrs 5 mos) - Location: Austin, TX - Skills: Infrastructure, Architecture - Managed hybrid bare-metal Linux clusters, Proxmox VE hypervisors, and ZFS storage pools with PCIe HBA passthrough for low-latency workloads. - Automated bare-metal provisioning, BGP Anycast routing policies, and hardware health telemetry across three regional facilities. ## Peer Recommendations ### Peer Recommendation (JL) “Working alongside Alex over the past three years transformed how our platform group approaches multi-region resilience and infrastructure automation. Alex has a rare ability to take deeply complex distributed systems problems and distil them into clean, maintainable Terraform and CI/CD workflows. Whenever a critical architectural decision or cross-region latency bottleneck surfaced, Alex combined rigorous first-principles diagnostics with pragmatic execution—delivering production-grade solutions without unnecessary complexity. Beyond technical depth, Alex is a generous mentor who elevates the engineering bar for everyone on the team.” ### Peer Recommendation (SR) “Alex is the kind of principal engineer every infrastructure organization hopes to find. From SigV4a multi-region storage routing to zero-SSR static edge delivery, every system Alex designs is fast, observable, and rock-solid.” ### Peer Recommendation (MK) “Clear communicator, methodical debugger, and relentless automator. Alex turned our manual cloud provisioning into a reproducible, self-documenting GitLab CI/CD pipeline in a matter of weeks.” ### Peer Recommendation (DT) “An exceptional systems architect who pairs deep Linux and networking fundamentals with modern cloud-native patterns.” ### Peer Recommendation (EC) “Alex brings clarity, calm, and deep technical mastery to every architecture review and production incident.” ### Peer Recommendation (RN) “Collaborating with Alex on our global edge migration was a highlight of my career. The documentation, diagrams, and Terraform modules Alex authored remain the gold standard across our engineering org.” ### Peer Recommendation (HP) “Thoughtful, proactive, and detail-oriented—Alex consistently bridges the gap between low-level infrastructure reliability and polished developer experience.” --- # Articles Archive --- # Part 1 — Customizing This Astro Theme: Identity, Feature Toggles, and Content - URL: https://www.example.com/blog/2026-11-03-part-1-customizing-this-astro-theme/ - Published Date: Nov 03, 2026 - Updated Date: Nov 06, 2026 - Tags: AstroJS, Architecture, Tailwind CSS, Design, Engineering - Description: A practical guide to cloning, running, and customizing this modular Astro 7.4 + Tailwind CSS v4 site—toggling features, choosing your homepage, and adding content without editing a single .astro template. > [!NOTE] > This is **Part 1** of a three-part guide on setting up and deploying **The Navigator** ([**GitHub (`edstuurman/the-navigator`)**](https://github.com/edstuurman/the-navigator) · [**GitLab (`src9061948/the-navigator`)**](https://gitlab.com/src9061948/the-navigator) · [**Live Interactive Demo**](https://the-navigator-sage.vercel.app/)): > - **Part 1 (You are here)**: Local setup, identity, feature toggles, configurable homepage, and content authoring. > - [**Part 2 (Optional) — Provisioning the Multi-Region AWS Stack with Terraform**](/blog/2026-11-03-part-2-provisioning-aws-mrap-cloudfront-terraform-gitlab-ci/): Setting up AWS S3, CloudFront, SSL certificates, and Route 53 DNS via GitLab CI, GitHub Actions, or Local CLI. > - [**Part 3 — Automated CI/CD Pipelines & Deploying to Any Static Host**](/blog/2026-11-03-part-3-ci-cd-pipelines-dry-run-mode-and-static-hosting/): Zero-config deployment to Vercel, Netlify, or Cloudflare Pages, plus GitHub Actions & GitLab CI pipelines. **The Navigator** is built around a simple rule: **you can customize 100% of your identity, layout, bio, blog posts, career timeline, and photo gallery—and turn entire sections (`blog`, `photography`, `log`, `now`, `about`, `tags`, `contact`, `contactForm`, `rss`, `llms`) on or off or choose which page serves as your `/` homepage—without ever opening an `.astro` template file.** Here is how the configuration, content folders, and data files fit together—and the step-by-step guide to making the site your own. --- ## How the Project Is Organized Instead of mixing personal content with layout code, `src/` is split into three simple layers that build your static site: ```mermaid flowchart TD subgraph Configs["1. Configuration Files (src/*.config.ts)"] SC["src/site.config.ts
(Your Name, Domain, Bio, Avatar, Social Links)"] TC["src/theme.config.ts
(Feature Toggles, Default Homepage, Logo, Nav, Integrations)"] end subgraph Content["2. Markdown Pages & Posts (src/content/)"] PG["src/content/pages/*.md
(Page Titles & Intro Copy: home, about, now, contact...)"] BL["src/content/blog/*.md
(Blog Articles)"] LG["src/content/log/*.md + CHANGELOG.md
(Short Status Notes & Release History)"] PH["src/content/photography/*.md
(Photo Titles, Stories & Dates)"] end subgraph Data["3. Structured Data (src/data/)"] EX["experiences.ts
(Career Timeline)"] RC["recommendations.ts
(Peer Recommendations)"] TT["techTerms.ts
(Technical Term Tooltips)"] end subgraph Outputs["4. Static Site Output (dist/)"] HTML["Static HTML Pages & Photo Lightbox"] OG["1200x630 Social Preview Cards (/og/*.jpg)"] FEEDS["Sitemap, RSS/Atom & AI Feeds (/llms.txt)"] end Configs --> Outputs Content --> Outputs Data --> Outputs ``` - **`src/*.config.ts`** controls **who owns the site** (`site.config.ts`) and **which features and integrations are enabled** (`theme.config.ts`). - **`src/content/`** holds your **Markdown pages and posts** (`pages`, `blog`, `log`, `photography`), supporting diagrams, YouTube embeds, callout boxes, and automatic term tooltips. - **`src/data/`** holds **structured lists** (`experiences.ts` for your career timeline, `recommendations.ts` for peer quotes, and `techTerms.ts` for hover definitions). --- ## Step 1: Local Prerequisites & Quickstart Before cloning and running the theme locally, make sure you have: - **Node.js `>= 20`** and `npm` - **Playwright Chromium** *(used at build time to render Markdown Mermaid diagrams into crisp inline SVGs)* - *(Optional)* **A [Formspree](https://formspree.io/) account (free)** — only needed if you want the embedded message form on `/contact/`, `/about/`, and blog posts. Set `features.contactForm: false` or leave the endpoint blank to use simple email and social links instead. - *(Optional)* **An [Umami](https://umami.is/) account or self-hosted instance** — if you want privacy-friendly analytics (`integrations.umami` in `src/theme.config.ts`). - *(Optional)* **A GitLab or GitHub account (free)** — for repository hosting and automated CI/CD builds. Clone the starter repository from **GitHub** or **GitLab** and start the development server: ```bash # 1. Clone from GitHub (or GitLab: https://gitlab.com/src9061948/the-navigator.git) git clone https://github.com/edstuurman/the-navigator.git cd the-navigator npm ci # 2. Install headless Chromium for build-time diagram rendering npx playwright install chromium # 3. Start the local dev server at http://localhost:4321 npm run dev ``` To run a full production build and preview the generated `./dist/` folder locally: ```bash npm run build npm run preview ``` > [!TIP] > **Fast Warm Builds**: Optimized images and social preview cards are cached in `.cache/`. While the very first build takes ~45–60 seconds to process all sample photos and preview cards, subsequent builds finish in **~1.5 to 2 seconds**. --- ## Step 2: Configure Your Identity (`src/site.config.ts`) Start by opening `src/site.config.ts`. This file holds your site URL, name, bio, portrait, and social links: ```ts export const siteConfig: SiteIdentityConfig = { site: { url: 'https://www.example.com', domain: 'example.com', title: 'Alex Mercer', description: 'Alex Mercer — Principal Cloud & Platform Architect. Distributed edge systems, multi-region AWS infrastructure, Terraform automation, and architectural photography.', locale: 'en_US', language: 'en-us', timeZone: 'America/Los_Angeles', defaultKeywords: [ 'Alex Mercer', 'example.com', 'Platform Architect', 'Site Reliability Engineering', 'Terraform', 'AWS', 'CloudFront', 'Astro', 'Tailwind CSS', ], }, author: { name: 'Alex Mercer', alternateName: 'Alexander Mercer', avatar: 'author.jpg', // Small circular chip on blog & log cards (src/images/author.jpg) aboutImage: 'author.jpg', // Large portrait on /about/ (can be a separate photo in src/images/) tagline: 'Cloud & Platform Architecture', jobTitle: 'Principal Cloud & Platform Architect', bio: 'Principal Cloud & Platform Architect specializing in multi-region edge infrastructure, declarative Terraform automation, high-throughput distributed systems, and architectural photography.', location: 'San Francisco, CA', email: 'alex@example.com', knowsAbout: [ 'Cloud Architecture', 'AWS Multi-Region Infrastructure', 'Terraform', 'Site Reliability Engineering', 'Linux Systems', 'Edge Networking', 'Static Web Architecture', ], }, socials: { github: 'https://github.com', gitlab: 'https://gitlab.com', linkedin: 'https://www.linkedin.com', instagram: 'https://www.instagram.com', // Optional: twitter, bluesky, mastodon (omit or leave empty to hide) }, }; ``` Updating `src/site.config.ts` automatically updates your name, domain, portrait (`src/images/author.jpg`), social links, RSS/Atom feeds, sitemap, and search engine metadata across every page. --- ## Step 3: Toggle Features & Choose Your Homepage (`src/theme.config.ts`) Next, open `src/theme.config.ts` to choose which sections of the theme you want to use, which page acts as your front page, and how the interface looks: ```ts export const themeMechanics: ThemeMechanicsConfig = { logo: { text: 'ALEX MERCER', ariaLabel: siteConfig.site.title, letterSpacing: '0.22em', fontSize: 14, showCompass: true, compassAngle: 42, }, integrations: { formspree: { endpoint: 'https://formspree.io/f/your-form-id', // Optional: leave empty or set contactForm: false to hide }, umami: { enabled: false, scriptUrl: 'https://cloud.umami.is/script.js', websiteId: '', }, }, navigation: { items: [ { label: 'Home', href: '/', enabled: true }, { label: 'About', href: '/about/', enabled: true }, { label: 'Now', href: '/now/', enabled: true }, { label: 'Blog', href: '/blog/', enabled: true, activePrefixes: ['/tags'] }, { label: 'Photography', href: '/photography/', enabled: true }, { label: 'Log', href: '/log/', enabled: true }, { label: 'Contact', href: '/contact/', enabled: true }, ], }, features: { defaultHomePage: 'home', // 'home' | 'blog' | 'about' | 'now' | 'photography' | 'log' | 'tags' | 'contact' home: true, about: true, now: true, blog: true, photography: true, log: true, tags: true, contact: true, contactForm: true, rss: true, llms: true, }, pagination: { olderBlogsCount: 20, logCount: 20, galleryCount: 50, homepageCarouselCount: 7, }, openGraph: { brandLabel: 'ALEX MERCER', locationPinLabel: siteConfig.author.location, }, tooltips: { enabled: true, autoLink: 'first', // 'first' | 'all' | 'off' }, footer: { siteColumnTitle: 'Example.com', showPoweredBy: true, poweredByLinks: [ { label: 'AWS S3', href: 'https://aws.amazon.com/s3/', icon: 's3' }, { label: 'AWS MRAP', href: 'https://aws.amazon.com/s3/features/multi-region-access-points/', icon: 'mrap' }, { label: 'AWS CloudFront', href: 'https://aws.amazon.com/cloudfront/', icon: 'cloudfront' }, { label: 'Colophon', href: '/blog/2026-11-03-part-2-provisioning-aws-mrap-cloudfront-terraform-gitlab-ci/', icon: 'info', highlight: true }, ], showThemeAttribution: false, // Set to `true` to display the optional footer credit }, }; ``` ### What You Can Toggle & Customize Here 1. **Turn Any Section On or Off (`features` & `navigation`)**: - Don't need a photography gallery, a `/now/` page, or an activity log? Set `photography: false` (or `enabled: false` on its item in `navigation.items`). - Turning a feature off removes it completely—skipping its pages at build time and automatically removing its navigation links, homepage carousel, `/log/` filter tab, `/tags/` section, sitemap entries, and RSS/AI feed items. 2. **Choose Your Front Page (`features.defaultHomePage`)**: - By default, `/` renders the multi-stream `home` overview with carousels. - Want your blog index or about page to be the front page of your site? Set `defaultHomePage: 'blog'` (or `'about'`, `'photography'`, `'log'`, `'now'`, `'tags'`, `'contact'`) and that section is rendered directly at `/`. 3. **Optional Contact Form & Feeds (`contactForm`, `rss`, `llms`)**: - **Formspree (`contactForm` & `integrations.formspree.endpoint`)**: Completely optional. Paste a free Formspree URL to enable the message form on [`/contact/`](/contact/), [`/about/#contact`](/about/#contact), and at the bottom of blog posts—or set `contactForm: false` (or leave `endpoint` blank) to hide the form and display your email and social links instead. - **RSS & AI Feeds (`rss`, `llms`)**: Set `rss: false` to disable `/rss.xml` and `/atom.xml`, or `llms: false` to disable `/llms.txt`, `/llms-full.txt`, and `/llms.json`. - **Umami Analytics (`integrations.umami`)**: Optional privacy-friendly analytics (`enabled: true/false`). 4. **Header Logo, Social Preview Cards & Tooltips (`logo`, `openGraph`, `tooltips`, `footer`)**: - **`logo`**: Change the SVG header text, font size, letter spacing, and compass icon. - **`openGraph`**: Set the `brandLabel` and `locationPinLabel` shown on generated 1200×630 social preview cards. - **`tooltips`**: Automatically turns the first mention of technical terms from `src/data/techTerms.ts` in each article into a hover/tap definition card (`autoLink: 'first' | 'all' | 'off'`). - **`footer`**: Customize footer links, toggle the "Powered by" column (`showPoweredBy`), or toggle the theme credit (`showThemeAttribution`). --- ## Step 4: Edit Page Titles & Intro Copy (`src/content/pages/`) Every top-level page (`/`, `/about/`, `/now/`, `/contact/`, `/blog/`, `/log/`, `/photography/`, and `/tags/`) reads its title, description, headings, and intro copy from Markdown files in **`src/content/pages/`**: | File | Route | What You Customize Here | | :--- | :--- | :--- | | `src/content/pages/home.md` | [`/`](/) | Homepage title, hero intro card, optional `setupGuide` quickstart banner, and carousel section titles. | | `src/content/pages/about.md` | [`/about/`](/about/) | Your biography paragraphs (in the Markdown body), spoken `languages` badges, and `faq` accordion items. | | `src/content/pages/now.md` | [`/now/`](/now/) | Your `/now` status cards (Location, Current Focus, Projects, Reading). | | `src/content/pages/contact.md` | [`/contact/`](/contact/) | Contact page intro text, timezone/response-time labels, and form heading. | | `src/content/pages/blog.md` | [`/blog/`](/blog/) | Blog page title, description, and archive heading. | | `src/content/pages/log.md` | [`/log/`](/log/) | Activity log page title, description, and heading. | | `src/content/pages/photography.md` | [`/photography/`](/photography/) | Photo gallery page title and description. | | `src/content/pages/tags.md` | [`/tags/`](/tags/) | Topic index page title, description, and heading. | > [!TIP] > **Hiding the Starter Quickstart Banner on `/` (`setupGuide.enabled: false`)**: In **The Navigator** starter template, `src/content/pages/home.md` includes `setupGuide.enabled: true` to show the 3-step onboarding banner inside the homepage hero card. Set `enabled: false` under `setupGuide:` in `src/content/pages/home.md` whenever you're ready to hide it. --- ## Step 5: Update Your Career Timeline & Dictionaries (`src/data/`) Three files in `src/data/` power the career timeline, peer recommendations, and term tooltips: 1. **`src/data/experiences.ts`**: Powers the [career timeline](/about/#experience) on `/about/` and links each role's `tags` to matching topic pages under [`/tags/`](/tags/). 2. **`src/data/recommendations.ts`**: Powers the peer recommendations grid on [`/about/#recommendations`](/about/#recommendations). 3. **`src/data/techTerms.ts`**: Holds ~60 technical term definitions (`Cloud`, `Networking`, `Storage`, `Security`, `Hardware`, `Virtualization`, `Architecture`, `DevOps`, `AI`) that automatically display hover/tap tooltips in your articles. --- ## Step 6: Adding Blog Posts, Logs & Photos Day-to-day publishing happens in Markdown: ### 1. Blog Articles (`src/content/blog/*.md`) Create a `.md` file in `src/content/blog/`: ```markdown --- title: "Designing Resilient Multi-Region Storage" description: "Practical notes on replication topologies, RPO/RTO trade-offs, and automated failover testing." pubDate: "Nov 03 2026" tags: ["AWS", "Infrastructure", "Architecture"] sectionNav: "h1 to h2" --- ``` - **`sectionNav: "h1 to h2"`**: Automatically builds the floating table-of-contents bar from your article's headings. - **Built-in Markdown Extras**: - **Callout Boxes**: Use `> [!NOTE]`, `> [!TIP]`, `> [!IMPORTANT]`, `> [!WARNING]`, or `> [!CAUTION]`. - **Diagrams**: Standard ` ```mermaid ` code blocks render as inline SVGs with a click-to-zoom lightbox. - **YouTube Videos**: Use a ` ```youtube ` code block (video URL on line 1, title on line 2) for a privacy-friendly click-to-play video card. ### 2. Activity Logs (`src/content/log/*.md` & `CHANGELOG.md`) - **Short Status Notes**: Add Markdown files to `src/content/log/YYYY-MM-DD-slug.md`. - **Release Notes**: Add release headings (`## [YYYY-MM-DD] - Title`) to root `CHANGELOG.md`. They automatically appear in the `/log/` timeline. ### 3. Photography (`src/images/photography/` & `src/content/photography/`) - Drop `.jpg` photos into `src/images/photography/` (e.g., `1.jpg`) with a matching `src/content/photography/1.md` file containing `id`, `filename`, `title`, `pubDate`, `category`, `location`, `tags`, and optional story notes. --- ## Next Up: Choose Your Deployment Path Once `npm run build` succeeds locally, your static site is ready in `./dist/`: 1. **Provision the Multi-Region AWS S3 + CloudFront Stack (Optional)**: Continue to [**Part 2 (Optional) — Provisioning the Multi-Region AWS Stack with Terraform**](/blog/2026-11-03-part-2-provisioning-aws-mrap-cloudfront-terraform-gitlab-ci/). 2. **Deploy to Any Static Host (Vercel, Netlify, Cloudflare Pages) or Explore CI/CD**: Jump to [**Part 3 — Automated CI/CD Pipelines & Deploying to Any Static Host**](/blog/2026-11-03-part-3-ci-cd-pipelines-dry-run-mode-and-static-hosting/). --- # Part 2 (Optional) — Provisioning the Multi-Region AWS Stack with Terraform (GitLab CI, GitHub Actions & Local CLI) - URL: https://www.example.com/blog/2026-11-03-part-2-provisioning-aws-mrap-cloudfront-terraform-gitlab-ci/ - Published Date: Nov 03, 2026 - Updated Date: Nov 05, 2026 - Tags: AWS, Terraform, CI/CD, Infrastructure, Architecture - Description: How to provision globally replicated AWS S3 buckets, a Multi-Region Access Point (MRAP), native CloudFront SigV4a Origin Access Control (OAC), ACM SSL, and Route 53 DNS using Terraform 1.10+ via GitLab CI/CD, GitHub Actions, or Local CLI. > [!NOTE] > This is **Part 2 (Optional)** of a three-part setup and deployment guide for **The Navigator** ([**GitHub**](https://github.com/edstuurman/the-navigator) · [**GitLab**](https://gitlab.com/src9061948/the-navigator) · [**Live Demo**](https://the-navigator-sage.vercel.app/)): > - [**Part 1 — Customizing This Astro Theme**](/blog/2026-11-03-part-1-customizing-this-astro-theme/): Local setup, identity & theme configuration, and content authoring. > - **Part 2 (Optional — You are here)**: Provisioning the multi-region AWS S3 MRAP + CloudFront SigV4a stack with Terraform. > - [**Part 3 — Automated CI/CD Pipelines, Starter Dry-Run Mode & Deploying to Any Static Host**](/blog/2026-11-03-part-3-ci-cd-pipelines-dry-run-mode-and-static-hosting/): Zero-config deployment to Vercel/Netlify/Cloudflare Pages, dual GitHub Actions & GitLab CI dry-run pipelines, and two-tier S3/CloudFront delta sync. > [!IMPORTANT] > **⏱️ Automated Provisioning — Expect ~20–30 Minutes for First-Time Greenfield Creation**: > While the entire infrastructure stack is automated via Terraform, provisioning from zero for the first time typically takes **20 to 30 minutes** end-to-end inside AWS: > - **ACM TLS Certificate DNS Validation (`us-east-1`)**: ~2–5 minutes > - **S3 Multi-Region Access Point (`aws_s3control_multi_region_access_point`)**: **~10–20 minutes** (AWS provisions global anycast routing tables and cross-region control plane endpoints behind the scenes) > - **CloudFront Global Edge Distribution + MRAP Policy Attachment**: ~5–10 minutes > > Grab a coffee during your initial `terraform apply`—subsequent runs and site deployments (`scripts/s3-deploy.sh`) complete in **~10–15 seconds**. The `terraform/` directory provisions an optional, enterprise-grade multi-region AWS static hosting stack built around four core capabilities: 1. **Native CloudFront SigV4a Origin Access Control (OAC)**: CloudFront signs requests directly to the S3 Multi-Region Access Point (MRAP) origin using `signing_protocol = "sigv4a"`, requiring zero `Lambda@Edge` functions. 2. **CloudFront Function (`viewer-request`)**: Handles apex-to-`www` `301` redirects (`example.com` → `https://www.example.com`) and static directory index rewrites (`/about/` → `/about/index.html`) at the edge. 3. **Managed Security Response Headers (`Managed-SecurityHeadersPolicy`)**: Attaches AWS's managed security headers policy (`Strict-Transport-Security`, `X-Content-Type-Options: nosniff`, `X-Frame-Options: SAMEORIGIN`, `Referrer-Policy`, and `X-XSS-Protection`) at the CloudFront edge. 4. **Terraform `>= 1.10` Native S3 State Locking & AWS Provider `~> 6.0`**: Remote state locking uses native S3 `.tflock` lockfiles (`use_lockfile = true` without DynamoDB), and multi-region S3 buckets use the AWS Provider 6.0 per-resource `region` attribute. --- ## Multi-Region Request & Replication Topology When deployed, your static site is replicated across your chosen AWS regions and served globally from the nearest healthy S3 bucket behind CloudFront: ```mermaid flowchart TD Visitor["Visitor Browser"] --> R53["Route 53 Public Hosted Zone
(A & AAAA Alias Records)"] R53 --> CF["CloudFront Global Edge Network
+ ACM TLS Certificate (us-east-1)"] subgraph Edge["CloudFront Edge Layer"] CFF["CloudFront Function (viewer-request)
1. 301 Redirect apex → www
2. Rewrite /path/ → /path/index.html"] OAC["Native Origin Access Control (OAC)
signing_protocol = sigv4a"] end CF --> CFF --> OAC OAC --> MRAP["S3 Multi-Region Access Point (MRAP)
Global Anycast Endpoint"] subgraph Storage["Multi-Region Private S3 Buckets (SSE-S3 + Versioning)"] direction TB B1["Primary Bucket (ap-northeast-1)
is_main = true (CI/CD Upload Target)"] B2["Replica Bucket #1 (eu-west-1)"] B3["Replica Bucket #2 (us-east-1)"] B1 -->|"Cross-Region Replication (CRR)"| B2 B1 -->|"Cross-Region Replication (CRR)"| B3 end MRAP -->|"Lowest-Latency Geo-Routing & Failover"| Storage ``` --- ## Choose Your Deployment Path You can provision and manage this Terraform stack using whichever workflow fits your setup: | Path | Best For | How It Runs | | :--- | :--- | :--- | | **[Option A — GitLab CI/CD](#step-2a-provision-via-gitlab-cicd-option-a)** | Teams & individuals hosting their repo on **GitLab** | Built-in `.gitlab-ci.yml` manual jobs (`terraform:bootstrap` → `terraform:plan` → `terraform:apply`) | | **[Option B — GitHub Actions](#step-2b-provision-via-github-actions-option-b)** | Teams & individuals hosting their repo on **GitHub** | One-time `terraform/bootstrap` initialization + `.github/workflows/deploy.yml` automated builds & S3 deploys | | **[Option C — Local CLI](#step-2c-provision-via-local-cli-option-c)** | Engineers who prefer running Terraform & deployments directly from their workstation | Local `terraform init && terraform apply` + `bash ./scripts/s3-deploy.sh ./dist` | --- ## Prerequisites Before running `terraform:bootstrap` or `terraform:apply`, make sure you have the following in place: 1. **An Active AWS Account**: - Standard AWS account with default regions enabled. *(Note: CloudFront OAC for S3 Multi-Region Access Points supports all 17 default-enabled AWS regions; opt-in regions are not supported by AWS for MRAP OAC.)* 2. **A Registered Domain Hosted on Amazon Route 53**: - Your root domain (e.g. `example.com`) must already exist as a **Public Hosted Zone** in Route 53 (whether registered directly through Route 53 or an external registrar). - **Verify Nameservers (`NS`) First**: If your domain was registered outside AWS, ensure its `NS` records at your registrar already point to the four Route 53 nameservers listed in your Hosted Zone. During `terraform apply`, `aws_acm_certificate_validation` waits for public DNS validation of the ACM TLS certificate (`example.com` and `*.example.com` in `us-east-1`); if your domain's nameservers don't delegate to Route 53 yet, certificate validation will wait until they do. 3. **AWS IAM Credentials (`AWS_ACCESS_KEY_ID` & `AWS_SECRET_ACCESS_KEY`)**: - An IAM User or CI/CD role with permissions to provision and manage: - **S3 & S3 Control**: Regional buckets, versioning, encryption, lifecycle rules, replication, and Multi-Region Access Points (`s3:*`, `s3control:*`) - **CloudFront**: Distributions, SigV4a Origin Access Control (OAC), and CloudFront Functions (`cloudfront:*`) - **ACM (`us-east-1`)**: Public SSL/TLS certificate creation and DNS validation (`acm:*`) - **Route 53**: Hosted Zone lookup plus ACM validation `CNAME` and `A` (IPv4) / `AAAA` (IPv6) Alias records (`route53:*`) - **IAM**: Creating and attaching the least-privilege S3 Cross-Region Replication role (`iam:CreateRole`, `iam:CreatePolicy`, `iam:AttachRolePolicy`, `iam:PassRole`) 4. **Your Site Domain Configured in `src/site.config.ts` ([Part 1](/blog/2026-11-03-part-1-customizing-this-astro-theme/))**: - Ensure `site.url` and `site.domain` in `src/site.config.ts` match your Route 53 domain so build-time canonical links, sitemaps, feeds, and Open Graph cards match your live infrastructure. --- ## Step 1: Select Your Active Regions & Domain (`terraform/variables.tf`) Open `terraform/variables.tf` and inspect `variable "buckets"`. By default, all **17 default-enabled AWS regions** supported by S3 MRAP + CloudFront OAC are pre-listed so you can simply comment out (`#`) the regions you don't need: ```hcl variable "buckets" { description = "List of regional S3 buckets behind the Multi-Region Access Point (MRAP)." type = list(object({ region = string is_main = bool priority = optional(number) })) default = [ # --- Primary Region (Deploy Target) --- { region = "ap-northeast-1", is_main = true }, # Asia Pacific (Tokyo) # --- Europe --- { region = "eu-north-1", is_main = false }, # Europe (Stockholm) { region = "eu-west-1", is_main = false }, # Europe (Ireland) # --- Americas --- { region = "us-east-1", is_main = false }, # US East (N. Virginia) { region = "us-west-2", is_main = false }, # US West (Oregon) ] } ``` > [!IMPORTANT] > **Choose Your Regions Before First Apply**: In AWS, S3 Multi-Region Access Point bucket membership is immutable after creation. Select the regions you want in `terraform/variables.tf` before running your initial `terraform apply`. Exactly one bucket must have `is_main = true`—this is the primary bucket where your CI/CD pipeline uploads build artifacts, which S3 Cross-Region Replication then fans out to all replica regions. ### Setting `environment_domain` (Naked Root Domain) Whether you pass `environment_domain` via `terraform/terraform.tfvars` (`environment_domain = "example.com"`) or CI/CD variables (`TF_VAR_environment_domain = example.com`), **always set it to your naked root domain without `https://` or `www.`** (for example, `example.com` or `yourdomain.com`). From that single value, Terraform automatically derives: - Your S3 state bucket name (`example-com-tfstate`) - Your regional S3 bucket names (`example-com-ap-northeast-1`, `example-com-eu-west-1`, etc.) - Your ACM wildcard TLS certificate (`example.com` and `*.example.com`) - Your canonical `https://www.example.com` primary URL and `301` edge redirect from `https://example.com` --- ## Step 2A: Provision via GitLab CI/CD (Option A) The repository root `.gitlab-ci.yml` runs on two independent tracks so normal content commits never block on manual infrastructure jobs: ```mermaid flowchart LR subgraph Track1["Track 1: Infrastructure (Manual / On terraform/* Changes)"] TB["terraform:bootstrap
(One-time S3 state bucket)"] --> TP["terraform:plan
(Saves tfplan artifact)"] --> TA["terraform:apply
(Provisions AWS stack)"] end subgraph Track2["Track 2: Site Build & Deploy (Every Push to main)"] BLD["build
(Astro build + warm .cache)"] --> DEP["deploytos3
(MD5/ETag delta sync + CF invalidation)"] end ``` ### 1. Add Initial Bootstrap & Provisioning Variables in GitLab On a brand-new setup, your S3 buckets and CloudFront distribution do not exist yet—so you cannot set `S3_BUCKET` or `CLOUDFRONT_DISTRIBUTION_ID` upfront. Start by opening **Settings → CI/CD → Variables** in your GitLab project and adding only the credentials and domain needed to bootstrap remote state and run Terraform: | Variable Key | Required? | Example / Default | Purpose | | :--- | :--- | :--- | :--- | | `AWS_ACCESS_KEY_ID` | **Required** | `AKIA...` | AWS IAM Access Key ID for Terraform & S3 deploys (Protected, Masked) | | `AWS_SECRET_ACCESS_KEY` | **Required** | `wJalrXUtnFEMI/...` | AWS IAM Secret Access Key (Protected, Masked) | | `TF_VAR_environment_domain` | **Required** | `example.com` | Naked root domain in Route 53 (no `https://` or `www.`); auto-derives `-tfstate` | | `AWS_DEFAULT_REGION` | Optional | `ap-northeast-1` *(default)* | Default AWS CLI region and fallback region for the `-tfstate` bucket | | `TF_VAR_environment_domain_slug` | Optional | `example-com` *(dots → hyphens)* | Custom prefix override for state bucket and main stack resource names | | `TF_STATE_BUCKET` / `TF_STATE_REGION` | Optional | `-tfstate` / `AWS_DEFAULT_REGION` | Explicit overrides if you want the Terraform state bucket named or hosted separately | ### 2. Bootstrap Remote State (`terraform:bootstrap` — One-Time Only) In GitLab **Build → Pipelines** on `main`, click the play button (**▶**) on **`terraform:bootstrap`**. This creates the dedicated, versioned, SSE-S3 encrypted, TLS-enforced `-tfstate` bucket (which also stores native Terraform `>= 1.10` `.tflock` lockfiles). ### 3. Plan & Apply the Multi-Region Stack (`terraform:plan` → `terraform:apply`) 1. Trigger **`terraform:plan`** (or push a change to `terraform/variables.tf`). Terraform initializes against your newly bootstrapped `-tfstate` bucket, validates the configuration across your selected regions in `var.buckets`, and saves the `tfplan` artifact. 2. Review the planned resources in the job log, then click play (**▶**) on **`terraform:apply`** to provision the regional S3 buckets, cross-region replication IAM & rules, S3 Multi-Region Access Point, `us-east-1` ACM certificate, CloudFront distribution, and Route 53 `A`/`AAAA` records *(allow ~20–30 minutes on the first greenfield run)*. 3. At the end of the **`terraform:apply`** job log, Terraform prints your newly created resource identifiers: ```text Outputs: active_bucket_regions = [ "ap-northeast-1", "eu-north-1", "eu-west-1", "us-east-1", "us-west-2" ] cloudfront_distribution_id = "E1A2B3C4D5E6F7" primary_upload_bucket = "example-com-ap-northeast-1" primary_upload_region = "ap-northeast-1" site_urls = [ "https://www.example.com", "https://example.com" ] ``` ### 4. Add Deployment Target Variables & Run `deploytos3` Return to **Settings → CI/CD → Variables** in GitLab and add the two post-provisioning variables from the `terraform:apply` output: | Variable Key | Value Source (`terraform:apply` output) | Purpose | | :--- | :--- | :--- | | `S3_BUCKET` | `primary_upload_bucket` (e.g. `example-com-ap-northeast-1`) | Primary S3 bucket where `scripts/s3-deploy.sh` uploads `./dist` | | `CLOUDFRONT_DISTRIBUTION_ID` | `cloudfront_distribution_id` (e.g. `E1A2B3C4D5E6F7`) | CloudFront distribution invalidated after S3 delta sync | Click retry/play (**▶**) on **`deploytos3`** in your pipeline (or push a commit to `main`) to sync `./dist` to your primary S3 bucket and issue a targeted CloudFront cache invalidation. --- ## Step 2B: Provision via GitHub Actions (Option B) If you host your repository on **GitHub**, the included `.github/workflows/deploy.yml` workflow handles automated Astro builds, S3 delta deployments, and Terraform validation. ### 1. Provision the Initial AWS Stack Run the one-time Terraform bootstrap and initial apply from your terminal (or a GitHub Codespace) using your AWS credentials: ```bash # 1. Create the dedicated S3 state bucket (one-time bootstrap) cd terraform/bootstrap terraform init terraform apply -var="environment_domain=example.com" # 2. Initialize and apply the main multi-region stack (~20-30 mins first run) cd .. cp terraform.tfvars.example terraform.tfvars # Edit terraform.tfvars to set: environment_domain = "example.com" terraform init \ -backend-config="bucket=example-com-tfstate" \ -backend-config="region=ap-northeast-1" terraform apply ``` ### 2. Configure GitHub Actions Secrets & Variables Open your GitHub repository **Settings → Secrets and variables → Actions** and add: **Repository Secrets**: - `AWS_ACCESS_KEY_ID`: Your AWS IAM Access Key ID - `AWS_SECRET_ACCESS_KEY`: Your AWS IAM Secret Access Key **Repository Variables**: - `TF_VAR_environment_domain`: `example.com` - `AWS_DEFAULT_REGION`: `ap-northeast-1` (or your primary upload bucket region) - `S3_BUCKET`: Value of `terraform output -raw primary_upload_bucket` (e.g. `example-com-ap-northeast-1`) - `CLOUDFRONT_DISTRIBUTION_ID`: Value of `terraform output -raw cloudfront_distribution_id` (e.g. `E1A2B3C4D5E6F7`) Once `S3_BUCKET` is set in GitHub Actions Variables, `.github/workflows/deploy.yml` automatically switches out of **Starter Template Dry-Run Mode** and builds + deploys your site on every push to `main`! --- ## Step 2C: Provision via Local CLI (Option C) If you prefer provisioning and deploying directly from your workstation terminal without CI/CD: ```bash # 1. Create the dedicated S3 state bucket (one-time bootstrap) cd terraform/bootstrap terraform init terraform apply -var="environment_domain=example.com" # 2. Initialize and apply the main multi-region stack (~20-30 mins first run) cd .. cp terraform.tfvars.example terraform.tfvars # Edit terraform.tfvars to set: environment_domain = "example.com" terraform init \ -backend-config="bucket=example-com-tfstate" \ -backend-config="region=ap-northeast-1" terraform apply ``` Once `terraform apply` finishes, build and deploy `./dist` directly from your machine at any time using `scripts/s3-deploy.sh`: ```bash npm run build S3_BUCKET="$(terraform -chdir=terraform output -raw primary_upload_bucket)" \ CLOUDFRONT_DISTRIBUTION_ID="$(terraform -chdir=terraform output -raw cloudfront_distribution_id)" \ bash ./scripts/s3-deploy.sh ./dist ``` --- ## Under the Hood: Key Terraform Resources Key implementation details across `terraform/` and `scripts/s3-deploy.sh`: ### 1. Native SigV4a Origin Access Control & Managed Security Headers (`terraform/cloudfront.tf`) `aws_cloudfront_origin_access_control` signs origin requests with `sigv4a` directly against the MRAP endpoint. Because an MRAP hostname ends in `.accesspoint.s3-global.amazonaws.com` rather than `.s3..amazonaws.com`, the distribution's `origin` block **must** include `custom_origin_config` alongside `origin_access_control_id` (omitting `custom_origin_config` causes Terraform to send `S3OriginConfig`, which CloudFront rejects with `The parameter Origin DomainName does not refer to a valid S3 bucket`): ```hcl resource "aws_cloudfront_origin_access_control" "mrap_oac" { name = "${local.domain_slug}-mrap-oac" description = "Native SigV4a Origin Access Control for S3 Multi-Region Access Point" origin_access_control_origin_type = "s3" signing_behavior = "always" signing_protocol = "sigv4a" } # Inside aws_cloudfront_distribution.mrap_distribution: origin { domain_name = aws_s3control_multi_region_access_point.mrap.domain_name origin_id = "mrap_origin_id" origin_access_control_id = aws_cloudfront_origin_access_control.mrap_oac.id custom_origin_config { http_port = 80 https_port = 443 origin_protocol_policy = "https-only" origin_ssl_protocols = ["TLSv1.2"] } } ``` In addition, `default_cache_behavior` attaches AWS's `Managed-SecurityHeadersPolicy` (`67f7725c-6f97-4210-82d7-5512b31e9d03`) so every response includes `Strict-Transport-Security`, `X-Content-Type-Options: nosniff`, `X-Frame-Options: SAMEORIGIN`, and `Referrer-Policy` headers automatically. ### 2. Apex Redirect & Directory Index Rewriting (`terraform/cloudfront.tf`) Because an S3 Multi-Region Access Point uses the S3 REST API endpoint rather than the legacy S3 Website endpoint, requests for `/about/` do not automatically resolve to `/about/index.html` on the S3 side. The `viewer-request` CloudFront Function handles both canonical host redirection and directory index resolution at the edge: ```javascript function handler(event) { var request = event.request; var host = request.headers.host ? request.headers.host.value : ''; // 1. Canonical redirect: naked domain -> www if (host === 'example.com') { return { statusCode: 301, statusDescription: 'Moved Permanently', headers: { location: { value: 'https://www.example.com' + request.uri } } }; } // 2. Static directory index rewrite var uri = request.uri; if (uri.endsWith('/')) { request.uri += 'index.html'; } else if (!uri.includes('.')) { request.uri += '/index.html'; } return request; } ``` --- ## Next Up: Automated CI/CD Dry-Run Workflows, Static Hosts & Two-Tier Edge Caching Now that you know how the optional multi-region AWS stack is provisioned, continue to [**Part 3 — Automated CI/CD Pipelines, Starter Dry-Run Mode & Deploying to Any Static Host**](/blog/2026-11-03-part-3-ci-cd-pipelines-dry-run-mode-and-static-hosting/) for a deep-dive into: - Deploying `./dist/` to zero-config platforms (**Vercel, Netlify, Cloudflare Pages**) - How the dual **GitLab CI (`.gitlab-ci.yml`)** and **GitHub Actions (`.github/workflows/deploy.yml`)** pipelines run in **Starter Template Dry-Run Mode** out of the box - How `scripts/s3-deploy.sh` uses **4-tier split Edge/Browser `Cache-Control` headers** and **MD5-vs-ETag delta sync** to keep CloudFront cache hit ratios near 100% while updating live pages in seconds. --- # Part 3 — Automated CI/CD Pipelines, Starter Dry-Run Mode & Deploying to Any Static Host - URL: https://www.example.com/blog/2026-11-03-part-3-ci-cd-pipelines-dry-run-mode-and-static-hosting/ - Published Date: Nov 03, 2026 - Updated Date: Nov 06, 2026 - Tags: CI/CD, Architecture, AWS, CloudFront, AstroJS - Description: How The Navigator's dual GitLab CI and GitHub Actions pipelines run in 5-second Starter Template Dry-Run Mode out of the box, how to deploy ./dist/ to Vercel, Netlify, or Cloudflare Pages, and how scripts/s3-deploy.sh pairs ETag delta sync with 4-tier Edge/Browser Cache-Control headers. > [!NOTE] > This is **Part 3** of a three-part setup and deployment guide for **The Navigator** ([**GitHub**](https://github.com/edstuurman/the-navigator) · [**GitLab**](https://gitlab.com/src9061948/the-navigator) · [**Live Demo**](https://the-navigator-sage.vercel.app/)): > - [**Part 1 — Customizing This Astro Theme**](/blog/2026-11-03-part-1-customizing-this-astro-theme/): Local setup, identity & theme configuration, and content authoring. > - [**Part 2 (Optional) — Provisioning the Multi-Region AWS Stack with Terraform**](/blog/2026-11-03-part-2-provisioning-aws-mrap-cloudfront-terraform-gitlab-ci/): Multi-region S3 buckets, MRAP, CloudFront SigV4a OAC, ACM SSL, and Route 53 DNS via GitLab CI, GitHub Actions, or Local CLI. > - **Part 3 (You are here)**: Deploying to zero-config static hosts (Vercel, Netlify, Cloudflare Pages), dual GitHub Actions & GitLab CI Starter Dry-Run pipelines, and 4-tier S3/CloudFront delta sync. Because this theme compiles 100% of its pages, responsive WebP/AVIF photography variants, inline SVG Mermaid diagrams, Satori Open Graph social cards, and machine-readable `/llms.txt` indexes at build time into `./dist/` (`output: 'static'`), **you are never locked into a single cloud provider**. In this final part of the setup series, we cover: 1. How to deploy `./dist/` to zero-config static hosts like **Vercel**, **Netlify**, or **Cloudflare Pages** in under a minute (just like the [Live Interactive Demo](https://the-navigator-sage.vercel.app/)). 2. How the repository's dual **GitLab CI (`.gitlab-ci.yml`)** and **GitHub Actions (`.github/workflows/deploy.yml`)** pipelines use **Starter Template Dry-Run Mode** so fresh forks get green `✅` status badges in ~5–10 seconds without needing AWS credentials upfront. 3. How `scripts/s3-deploy.sh` combines **MD5-vs-ETag delta sync** with **4-tier split Edge/Browser `Cache-Control` headers** so live pages update in seconds while CloudFront edge cache hit ratios stay near 100%. --- ## Option 1: Zero-Config Static Hosting (Vercel, Netlify, Cloudflare Pages) If you don't need multi-region AWS S3 replication ([Part 2](/blog/2026-11-03-part-2-provisioning-aws-mrap-cloudfront-terraform-gitlab-ci/)), you can host the compiled `./dist/` folder on any static CDN with zero infrastructure setup: ### A. Prebuilt Static Upload (Fastest — Zero Cloud Build Minutes) Because `npm run build` generates a self-contained `./dist/` directory locally (including pre-rendered inline SVG Mermaid diagrams and cached 1200×630 Open Graph cards), you can upload `./dist/` directly to Vercel, Netlify Drop, or Cloudflare Pages: ```bash # 1. Build the static site locally into ./dist/ npm run build # 2. Deploy ./dist/ directly (e.g. Vercel CLI, Netlify CLI, or Cloudflare Wrangler) npx vercel deploy ./dist --prod # or: npx netlify-cli deploy --dir=./dist --prod # or: npx wrangler pages deploy ./dist ``` ### B. Automated Git Integration on Vercel / Netlify / Cloudflare Pages If you connect your GitHub or GitLab repository directly to Vercel, Netlify, or Cloudflare Pages, configure the build settings to install Playwright's headless Chromium binary before running `npm run build` (required by `rehype-mermaid` to compile Markdown `mermaid` fences into inline SVGs): | Setting | Value | | :--- | :--- | | **Framework Preset** | `Astro` | | **Build Command** | `npx playwright install chromium && npm run build` | | **Output Directory** | `dist` | | **Node.js Version** | `22.x` (or `>= 20`) | --- ## Option 2: Dual CI/CD Pipelines with Starter Template Dry-Run Mode A common frustration with open-source starter templates that include production CI/CD workflows is the **"Red Pipeline on First Fork" problem**: the moment you fork or push the starter repository to GitHub or GitLab, the CI pipeline tries to authenticate with AWS or run `aws s3 sync`, fails because you haven't configured cloud secrets yet, and plasters red `❌` failure badges across your repository. To solve this cleanly, both **`.gitlab-ci.yml`** (GitLab CI/CD) and **`.github/workflows/deploy.yml`** (GitHub Actions) in **The Navigator** implement **automatic Starter Template Dry-Run Mode**: ```mermaid flowchart TD Push["Push to main
(GitLab CI or GitHub Actions)"] --> CheckVar{"Is S3_BUCKET
configured?"} CheckVar -->|"No (Default Starter Template)"| DryRun["🧪 Starter Template Dry-Run Mode (~5-10s)
• Verifies package.json, astro.config.mjs,
src/site.config.ts & src/theme.config.ts
• Verifies terraform/*.tf modules
• Skips Chromium download & AWS calls"] DryRun --> GreenBadge["✅ Pipeline Passes (Green Badge)
Prints step-by-step setup instructions in job log"] CheckVar -->|"Yes (Production Site Configured)"| ProdBuild["🚀 Full Production Mode
1. Restores warm .cache/astro & .cache/og-images
2. Runs Astro 7.4 + Playwright Mermaid build
3. Runs scripts/s3-deploy.sh (ETag delta sync)
4. Issues targeted CloudFront invalidation"] ProdBuild --> LiveSite["🌐 Live Multi-Region Site Updated"] ``` ### How Dry-Run Mode Works Under the Hood When `S3_BUCKET` is empty (the default on a fresh clone or fork): 1. **Build & Deploy Jobs (`build`, `deploytos3`)**: Instead of spinning up a 2 GB headless browser container or failing on missing AWS credentials, the runner verifies that `package.json`, `astro.config.mjs`, `src/site.config.ts`, `src/theme.config.ts`, and `scripts/s3-deploy.sh` are intact, prints a concise onboarding guide in the job log, and exits `0` in **~5–10 seconds**. 2. **Infrastructure Check (`terraform:dry-run`)**: When `TF_VAR_environment_domain` is unset, a lightweight dry-run job verifies that all Terraform modules (`terraform/versions.tf`, `terraform/backend.tf`, `terraform/cloudfront.tf`, `terraform/s3-mrap.tf`, `terraform/acm-route53.tf`, and `terraform/bootstrap/main.tf`) are present and passes with a green `✅` badge. 3. **Zero-Edit Transition to Production**: The moment you add `S3_BUCKET` (and your AWS credentials) in **GitLab CI/CD Variables** or **GitHub Actions Secrets & Variables**, the exact same workflow automatically transitions to full production builds and S3 delta deployments—without editing a single line of `.gitlab-ci.yml` or `.github/workflows/deploy.yml`. ### Enabling Automated CI/CD on Your Fork To prevent consuming shared runner minutes and avoid redundant builds on the public demo template, automated CI is intentionally disabled on the upstream `the-navigator` repository (`src9061948/the-navigator` / `edstuurman/the-navigator`). CI runs only on the production site (`stuurman`). When you fork or clone the theme for your own site, here is the exact one-time interaction to enable automated builds: #### A. For GitLab CI/CD (`.gitlab-ci.yml`) - **Renamed Projects (Default)**: If you rename your repository to your own domain or project name (e.g. `my-awesome-site`), GitLab CI runs automatically out of the box. - **Projects Retaining "navigator"**: If your fork retains `navigator` in its project name or path, `.gitlab-ci.yml` includes an upstream guard that skips CI. To enable it, either: 1. Add a CI/CD Variable in **Settings > CI/CD > Variables**: `ENABLE_CI = "true"`. 2. Or delete the first rule (`- if: '$ENABLE_CI != "true" && ($CI_PROJECT_NAME =~ /navigator/i ...)'`) under `workflow: rules:` in `.gitlab-ci.yml`. #### B. For GitHub Actions (`.github/workflows/deploy.yml`) - Automated `push` triggers are commented out by default so fresh forks don't trigger unwanted builds until you are ready. - You can manually test and run the workflow at any time via the **Actions** tab in your GitHub repository (**Run workflow** button). - To enable automatic builds on every `git push` to `main`, simply un-comment the `push:` block at lines 6–10 of `.github/workflows/deploy.yml`: ```yaml on: push: branches: - main tags-ignore: - '**' workflow_dispatch: ``` > [!IMPORTANT] > **Strict Environment Isolation**: Neither `scripts/s3-deploy.sh`, `.gitlab-ci.yml`, `.github/workflows/deploy.yml`, nor `terraform/` in **The Navigator** contain any hardcoded bucket names, distribution IDs, or personal domains. If `scripts/s3-deploy.sh` is invoked locally without `S3_BUCKET` set in your environment, it immediately aborts with an explicit error message (`Error: S3_BUCKET environment variable is required`). --- ## Inside `scripts/s3-deploy.sh`: 4-Tier Edge/Browser Caching & ETag Delta Sync When deploying to AWS S3 + CloudFront, `scripts/s3-deploy.sh` solves two classic static-hosting bottlenecks: 1. **Unnecessary Re-Uploads**: Standard `aws s3 sync` compares file modification timestamps (`mtime`). Because a static site generator recreates `./dist/` on every build, `aws s3 sync` re-uploads every HTML file, sitemap, and RSS feed even when 99% of your pages haven't changed. 2. **Stale Browser HTML vs. Low Edge Cache Hit Rate**: If you set a single `Cache-Control: max-age=600` header on HTML files, CloudFront has to re-fetch from S3 every 10 minutes—and browsers can still show stale HTML for up to 10 minutes after a deployment. ### 1. Separating Browser TTL (`max-age`) from CloudFront Edge TTL (`s-maxage`) `scripts/s3-deploy.sh` inspects every file path in `./dist/` and assigns one of four split `Cache-Control` headers: | Tier | File Patterns | `Cache-Control` Header | Browser Behavior (`max-age`) | CloudFront Edge Behavior (`s-maxage`) | | :--- | :--- | :--- | :--- | :--- | | **Tier 1: Fingerprinted Assets** | `_astro/*` (including `/_astro/styles..css`), `yt-thumbs/*` | `public, max-age=31536000, immutable` | Cached **1 year** without revalidation (filenames contain content hashes) | Cached **1 year** at edge | | **Tier 2: Static Media & OG Cards** | `og/*`, `*.png`, `*.svg`, `*.ico`, `*.webp`, `*.jpg`, `*.jpeg` | `public, max-age=86400, s-maxage=31536000, stale-while-revalidate=86400` | Cached **24 hours** in browser with 24h stale-while-revalidate | Cached **1 year** at edge until explicitly invalidated | | **Tier 3: Feeds & Indexes** | `*.xml`, `*.txt`, `*.json`, `*.xsl`, `*.webmanifest` | `public, max-age=3600, s-maxage=86400` | Cached **1 hour** in browser/readers | Cached **24 hours** at edge | | **Tier 4: HTML Documents** | `*.html` (`*`) | `public, max-age=0, s-maxage=31536000, must-revalidate` | **Always revalidates** (`304 Not Modified` in milliseconds; instant updates after deploy) | Cached **1 year** at edge until explicitly invalidated by `s3-deploy.sh` | Why is **Tier 4 (`public, max-age=0, s-maxage=31536000, must-revalidate`)** so effective for HTML pages? - **At the CloudFront Edge**: `s-maxage=31536000` tells CloudFront edge POPs to keep HTML pages cached in memory for a full year—eliminating origin fetches to S3. - **In the Visitor's Browser**: `max-age=0, must-revalidate` tells the browser to check with the nearest CloudFront edge POP on navigation. When nothing has changed, CloudFront returns `304 Not Modified` at the edge in a few milliseconds. When you deploy an update and `scripts/s3-deploy.sh` invalidates that path on CloudFront, every visitor receives the fresh HTML immediately on their very next page load! ### 2. MD5-vs-ETag Delta Sync & Smart Invalidation Collapsing ```mermaid flowchart LR Dist["Local ./dist/ Files
(Compute MD5 Hashes)"] --> Compare{"Compare Local MD5
vs Remote S3 ETag"} S3List["aws s3api list-objects-v2
( Single API Call )"] --> Compare Compare -->|"Match (Unchanged)"| Skip["⏭️ Skip Upload
(Zero S3 PUT cost)"] Compare -->|"Diff or New File"| Upload["⬆️ Parallel Upload (16x)
+ Tiered Cache-Control Header"] Compare -->|"Removed Locally"| Delete["🗑️ Delete Stale S3 Object"] Upload --> Invalidate["⚡ Smart CloudFront Invalidation
• /about/index.html → /about/*
• Collapses >15 paths into /*"] Delete --> Invalidate ``` As detailed in our earlier [GitLab CI S3 deployment optimization write-up](/blog/2026-11-01-optimizing-gitlab-ci-s3-deployments/), on a typical content update: 1. `scripts/s3-deploy.sh` fetches all existing object keys and ETags from your primary S3 bucket in a single `aws s3api list-objects-v2` call. 2. It computes local MD5 checksums across `./dist/` and skips every file whose MD5 matches its remote S3 ETag. 3. Only the handful of modified files are uploaded in parallel (`PARALLEL_JOBS=16`) with tiered `Cache-Control` headers and explicit `--content-type` metadata for `.xsl`, `.webmanifest`, and `.txt` files. 4. Finally, it normalizes the changed paths (turning `/blog/my-post/index.html` into `/blog/my-post/*`) and submits a single CloudFront invalidation request—or automatically collapses the invalidation to `/*` if more than `MAX_INVALIDATION_PATHS` (`15`) paths changed, staying well within AWS's free invalidation tier. --- ## Complete Setup Series Recap You now have the full picture of **The Navigator**: 1. **[Part 1 — Customizing This Astro Theme](/blog/2026-11-03-part-1-customizing-this-astro-theme/)**: Configure your identity in `src/site.config.ts`, UI mechanics in `src/theme.config.ts`, page copy in `src/content/pages/*.md`, typed datasets in `src/data/*.ts`, and Markdown articles/logs/photos in `src/content/`. 2. **[Part 2 (Optional) — Provisioning the Multi-Region AWS Stack with Terraform](/blog/2026-11-03-part-2-provisioning-aws-mrap-cloudfront-terraform-gitlab-ci/)**: Provision multi-region S3 buckets, an S3 Multi-Region Access Point, native CloudFront SigV4a Origin Access Control, ACM TLS certificates, and Route 53 DNS via GitLab CI/CD, GitHub Actions, or Local CLI. 3. **Part 3 — Automated CI/CD Pipelines & Static Hosting**: Deploy `./dist/` to Vercel/Netlify/Cloudflare Pages in seconds, or let the built-in GitLab CI and GitHub Actions workflows transition seamlessly from 5-second Starter Template Dry-Run checks to production ETag delta deployments. --- # Kitchen-Sink Markdown Showcase: Mermaid, Alerts, Tooltips & YouTube Facades - URL: https://www.example.com/blog/2026-11-02-kitchen-sink-markdown-showcase/ - Published Date: Nov 02, 2026 - Tags: AstroJS, Tailwind CSS, Architecture, Infrastructure - Description: A self-documenting tour of every custom Remark and Rehype build-time extension included in this Astro 7.4 starter theme: inline SVG Mermaid diagrams, GitHub-style callout alerts, zero-JS technical acronym tooltips, click-to-load YouTube facades, and syntax-highlighted code blocks. This post serves as a live visual reference and kitchen-sink test suite for the custom Markdown pipeline configured in `astro.config.mjs`. Every component below compiles at build time with near-zero client-side JavaScript overhead. --- ## 1. Automatic Technical Acronym Tooltips Any acronym defined in `src/data/techTerms.ts` (such as MRAP, OAC, SigV4A, BGP, NVMe, ZFS, or AST) is automatically upgraded at build time by `src/plugins/rehype-tech-tooltips.mjs` into an accessible, viewport-clamped glassmorphic popover card with domain category badges and keyboard `Escape` support. By default (`tooltips.autoLink: 'first'` in `src/theme.config.ts`), only the first occurrence of each term per article receives a tooltip so paragraphs stay clean and readable. --- ## 2. Build-Time Inline SVG Mermaid Diagrams Fenced ```mermaid code blocks are compiled at build time via `rehype-mermaid` and enriched with accessible `role="img"` titles by `src/plugins/rehype-mermaid-a11y.mjs`—shipping crisp inline `` nodes with zero client-side Mermaid runtime bundle: ```mermaid flowchart LR subgraph Client["Viewer Request"] Browser["Browser / Edge Client"] end subgraph Edge["Amazon CloudFront Global Edge"] CFF["CloudFront Function
(Apex Redirect & /index.html)"] OAC["Native SigV4a OAC
(Origin Access Control)"] end subgraph Storage["Multi-Region S3 Origin"] MRAP["S3 Multi-Region Access Point
(Global Anycast Endpoint)"] S3A["S3 Primary Bucket
(us-east-1)"] S3B["S3 Replica Bucket
(eu-west-1)"] S3C["S3 Replica Bucket
(ap-northeast-1)"] end Browser -->|HTTPS TLS 1.3| CFF CFF --> OAC OAC -->|SigV4a Signed GET| MRAP MRAP -->|Lowest Latency| S3A MRAP -->|Active Failover| S3B MRAP -->|Active Failover| S3C S3A <-->|S3 RTC 15m SLA| S3B S3A <-->|S3 RTC 15m SLA| S3C ``` --- ## 3. GitHub-Style Callout Alerts Standard GitHub Flavored Markdown alert blockquotes are transformed by `src/plugins/remark-alerts.mjs` into semantic callout boxes: > [!NOTE] > **Informational Note**: Content collections are validated at build time via Zod schemas in `src/content.config.ts`. > [!TIP] > **Performance Tip**: Persist `.cache/astro/` and `.cache/og-images/` in CI/CD to drop warm production builds to under 2 seconds. > [!IMPORTANT] > **Essential Requirement**: Ensure your Route 53 Hosted Zone nameservers match your domain registrar before running `terraform apply`. > [!WARNING] > **Configuration Warning**: Setting `tooltips.autoLink: 'all'` wraps every repeated occurrence of an acronym in long-form articles. > [!CAUTION] > **Destructive Action**: Removing regional buckets from `s3_bucket_regions` in Terraform will schedule those replicas for teardown unless protected. --- ## 4. Syntax-Highlighted Code Blocks & Copy Toolbar Shiki syntax highlighting runs at build time and pairs with a floating copy-to-clipboard button that gives instant visual checkmark feedback: ```hcl resource "aws_cloudfront_origin_access_control" "mrap_oac" { name = "mrap-sigv4a-oac-${var.environment_domain_slug}" description = "SigV4a Origin Access Control for S3 Multi-Region Access Point" origin_access_control_origin_type = "s3" signing_behavior = "always" signing_protocol = "sigv4a" } ``` --- ## 5. Privacy-Enhanced Click-to-Load YouTube Facade Fenced ```youtube blocks download and optimize the video poster frame into `.cache/youtube-thumbs/` at build time via `src/plugins/remark-youtube.mjs`. No `youtube-nocookie.com` iframe or third-party tracker is loaded until the reader clicks play: ```youtube https://www.youtube.com/watch?v=kL1PDqzqhM4 title: The Mystery of Lorem Ipsum — Historic Archive Documentary ``` --- # Why Zero-SSR Static Architecture Still Wins at the Global Edge - URL: https://www.example.com/blog/2026-10-28-designing-zero-ssr-edge-architectures/ - Published Date: Oct 28, 2026 - Tags: Architecture, AWS, Infrastructure, AstroJS - Description: Evaluating latency, operational failure modes, and cost economics of pre-rendered static edge architectures fronted by CloudFront and multi-region S3 object storage. Modern web frameworks make it tempting to default to Server-Side Rendering (SSR) or edge compute workers for content-driven sites. Yet for engineering blogs, documentation portals, portfolios, and marketing sites, compiling everything ahead of time via Static Site Generation (SSG) remains unmatched in reliability, security, and Time to First Byte (TTFB). ## Eliminating Runtime Moving Parts When every route is pre-rendered into deterministic HTML at build time: 1. **Zero Origin Compute Cold Starts**: There are no container clusters, serverless functions, or database connection pools in the request path. 2. **Multi-Region Active-Active Durability**: Static artifacts stored across regional Amazon S3 buckets behind a Multi-Region Access Point (MRAP) survive entire regional cloud outages automatically. 3. **Predictable Security Posture**: With no runtime application server parsing dynamic query parameters or session cookies, whole classes of injection and SSRF vulnerabilities disappear. ## Progressive Enhancement Where It Counts Static delivery does not mean sacrificing interactivity. By combining Astro 7 build-time rendering with targeted, zero-dependency TypeScript modules—such as keyboard-accessible lightboxes, viewport-clamped DOM tooltips, and scroll-spy section navigation capsules—you get instant page loads alongside a responsive, tactile user experience. --- # Operational Logs & Status-Updates ## Status-Update: Initialized The Navigator (Astro 7 + AWS S3 MRAP starter theme) - URL: https://www.example.com/log/#2026-11-02-starter-theme-initialized - Date: Nov 02, 2026 - Tags: AstroJS, Tailwind CSS, Terraform, AWS Bootstrapped the clean-room starter repository with decoupled identity configuration (`src/site.config.ts`), UI mechanics (`src/theme.config.ts`), and multi-region Terraform modules (`terraform/`). Verified cold and warm incremental build caches along with automated Satori Open Graph card generation. --- ## Status-Update: Validated native CloudFront SigV4a Origin Access Control against S3 MRAP - URL: https://www.example.com/log/#2026-10-29-cloudfront-sigv4a-oac-validation - Date: Oct 29, 2026 - Tags: AWS, Infrastructure, CI/CD Confirmed end-to-end `sigv4a` request signing between CloudFront and the global `*.accesspoint.s3-global.amazonaws.com` Multi-Region Access Point endpoint using native Origin Access Control (OAC), retiring the legacy `Lambda@Edge` Python signer. --- # Site Changelogs ## Changelog: The Navigator v1.3.0 Release - URL: https://www.example.com/log/#changelog-2026-11-06 - Date: Nov 06, 2026 ### Added & Changed - **Modular Feature Toggles**: Every major site section (`home`, `about`, `now`, `blog`, `photography`, `log`, `tags`, `contact`, `contactForm`, `rss`, and `llms`) can now be toggled on or off in one place. Turning a feature off skips building its pages and automatically removes its menu links, homepage carousel, [`/log/`](/log/) filter tab, [`/tags/`](/tags/) section, sitemap entries, and RSS/AI feed items. - **Configurable Root Homepage (`defaultHomePage`)**: Any enabled section (such as [`/blog/`](/blog/), [`/about/`](/about/), or [`/photography/`](/photography/)) can now be set as the root [`/`](/) front page instead of the multi-stream overview. - **Optional Contact Form**: The Formspree message form on [`/contact/`](/contact/), [`/about/`](/about/), and blog articles can now be disabled independently (`contactForm: false` or an empty endpoint) while keeping email and social links active. - **Streamlined Starter Documentation**: Simplified the README and [**Part 1 Setup Guide**](/blog/2026-11-03-part-1-customizing-this-astro-theme/) into a clear, jargon-free tutorial with prominent feature toggle examples. --- ## Changelog: The Navigator v1.2.0 Release - URL: https://www.example.com/log/#changelog-2026-11-05 - Date: Nov 05, 2026 ### Changed & Optimized - **Lightweight Social Preview Cards**: Converted all Open Graph link preview cards to optimized MozJPEG images, cutting file size by 88% for fast, crisp link sharing in messaging apps and social feeds. - **Instant Hover Page Preloading**: Enabled background prefetching on link hover and tap so subsequent pages load instantly. - **Zero-JavaScript Layout Refinements**: Replaced client-side resizing scripts on [`/blog/`](/blog/) with modern CSS flexbox layouts for zero layout shifts and smoother scrolling. - **Compact Changelog Summaries**: Compacted long release logs on [`/log/`](/log/) into clean 3-bullet previews with native expand/collapse details. - **Accessibility & Motion Polish**: Added respect for reduced-motion preferences, improved keyboard and touch tooltip handlers, and unified search-engine structured data. - **Dual Pipeline Accelerations**: Added pre-baked dependency caching and a slim build container in both GitLab CI and GitHub Actions, speeding up automated builds significantly. --- ## Changelog: The Navigator v1.1.0 Release - URL: https://www.example.com/log/#changelog-2026-11-04 - Date: Nov 04, 2026 ### Added & Changed - **Starter Template Dry-Run Mode**: Dual GitHub Actions and GitLab CI workflows pass green in 5–10 seconds out of the box on fresh forks before AWS secrets are configured. - **Interactive Diagram Zoom Lightbox**: Markdown diagrams now include an interactive zoom modal supporting pinch-to-zoom, click-and-drag panning, and full keyboard navigation. - **Perfect 100/100 PageSpeed Performance**: Refined stylesheet and script delivery to achieve a perfect 100 PageSpeed score across Performance, Accessibility, Best Practices, and SEO. - **Responsive Floating Navigation**: The section navigator docks conveniently at the top of the viewport on desktop and in the bottom thumb zone on mobile for effortless one-handed browsing. - **Dark Mode Surface & Typography Polish**: Enhanced contrast across tag badges and navigation pills with clean slate surfaces and warm amber accents for comfortable reading. - **4-Tier S3 Caching & Security Headers**: Streamlined S3 deployment script with split browser and edge cache lifetimes, paired with CloudFront security headers. --- ## Changelog: The Navigator v1.0.0 Release - URL: https://www.example.com/log/#changelog-2026-11-03 - Date: Nov 03, 2026 ### Features & Architecture - **Decoupled Configuration Architecture**: Site identity, author profile, theme mechanics, navigation, and tooltip options live in simple configuration files for quick personalization. - **Multi-Region AWS S3 & CloudFront Infrastructure**: Turnkey Terraform modules for globally replicated S3 storage, Multi-Region Access Points (MRAP), and CloudFront SigV4a edge delivery. - **Fast Build-Time Markdown & Media Compilers**: Integrated automated social preview cards, inline SVG diagrams, privacy-friendly YouTube facades, and zero-JS technical acronym tooltips. - **Smart Flex Photography Gallery & Lightbox**: Zero-dependency aspect-ratio photo gallery, accessible lightbox with filmstrip and zoom, and unified cross-collection topic archives. --- # Photography Portfolio & Photo Rolls - URL: https://www.example.com/photography/ - Total Photographs: 40 - **Estação das Docas Waterfront, Belém** (Oct 30, 2026, Belém, Brazil) [Seascape] — Las Docas in Belém, Brazil: restored ancient docks, presently with bars, restaurants and shops. Las Docas are located on the banks of the bay of the Guajará river. Featured Picture by Cayambe via Wikimedia Commons (licensed under CC BY-SA 3.0). (https://www.example.com/photography/?photo=1) - **Antwerp Central Station Vaulted Hall** (Oct 26, 2026, Antwerp, Belgium) [Architecture] — Antwerp Central station in Belgium. It was taken with a Pentax K20D. Featured Picture by Laurent-Jonathan Meyvaert via Wikimedia Commons (licensed under CC BY-SA 3.0). (https://www.example.com/photography/?photo=2) - **Historic Bohemian Architecture, Czechia** (Oct 22, 2026, Prague, Czechia) [Landscape] — This is a photo of a cultural monument of the Czech Republic, number: Featured Picture by Godot13 via Wikimedia Commons (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=3) - **Roy’s Motel & Café Neon Sign, Amboy** (Oct 18, 2026, Amboy, California) [Landscape] — Roy’s Cafe & Motel, Amboy, California, USA on the left the Historic Route 66 to Los Angeles Featured Picture by Dietmar Rabich via Wikimedia Commons_--_2012_--_4.jpg) (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=4) - **Old Town of Emporio, Santorini** (Oct 14, 2026, Santorini, Greece) [Landscape] — Old town of Emporeio, Santorini, Greece. Featured Picture by Norbert Nagel via Wikimedia Commons (licensed under CC BY-SA 3.0). (https://www.example.com/photography/?photo=5) - **Illuminated Transit Shelter at Night, Risskov** (Oct 10, 2026, Aarhus, Denmark) [Twilight] — Night photo in rain of a bus shelter in Risskov, Aarhus, Denmark. Featured Picture by Villy Fink Isaksen via Wikimedia Commons (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=6) - **Scar House Reservoir Masonry Dam** (Oct 06, 2026, Nidderdale, England) [Landscape] — Dam of Scar House Reservoir, Nidderdale, England Featured Picture by Kreuzschnabel via Wikimedia Commons (licensed under CC BY-SA 3.0). (https://www.example.com/photography/?photo=7) - **Cherry Esplanade in Spring, Brooklyn Botanic Garden** (Oct 02, 2026, Brooklyn, New York) [Landscape] — Deck above Visitor Center, Brooklyn Botanic Garden, Brooklyn, New York City. Featured Picture by King of Hearts via Wikimedia Commons (licensed under CC BY-SA 3.0). (https://www.example.com/photography/?photo=8) - **Historic Mine Adit in Bergslagen** (Sep 28, 2026, Garpenberg, Sweden) [Architecture] — Mine tunnel Carls stoll in Garpenberg, Hedemora Municipality, Dalarna County, Sweden. The tunnel starts in the hillside under Garpenberg Church's cemetery and continues about 50 meters with the terminal end under the middle of the church. In the tunnel, made by fire-setting, copper was mined. It is the only mine tunn… Featured Picture by Calle Eklund/ Vivo via Wikimedia Commons (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=9) - **Vaulted Arab Baths of Alhama de Granada** (Sep 24, 2026, Alhama de Granada, Spain) [Landscape] — Arab Baths of Alhama de Granada in the province of Granada, Spain. Featured Picture by SuperCar-RoadTrip.fr from Bordeaux, France via Wikimedia Commons (licensed under CC BY 2.0). (https://www.example.com/photography/?photo=10) - **Traditional Carrelet Fishing Hut at Sunset** (Sep 20, 2026, Esnandes, France) [Landscape] — Fishing nets on pontoons in Esnandes, Charente-Maritime, France Featured Picture by Jebulon via Wikimedia Commons (licensed under CC0). (https://www.example.com/photography/?photo=11) - **Brda River Granaries, Bydgoszcz** (Sep 16, 2026, Bydgoszcz, Poland) [Landscape] — Marina Bydgoszcz, hotel window Featured Picture by 1bumer via Wikimedia Commons (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=12) - **Brighton West Pier Silhouette at Dusk** (Sep 12, 2026, Brighton, England) [Seascape] — Looking out to sea from the beach at Brighton, as the sun sets. The posts are the remains of the old West Pier. Featured Picture by mattbuck ( category ) via Wikimedia Commons (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=13) - **Neoclassical Peristyle Courtyard, Zappeion** (Sep 08, 2026, Athens, Greece) [Landscape] — Courtyard of the Zappeion, Athens, Greece. Featured Picture by Jebulon via Wikimedia Commons (licensed under CC0). (https://www.example.com/photography/?photo=14) - **Colonial Facades of the Historic Center** (Sep 04, 2026, Baku, Azerbaijan) [Landscape] — This is a photo of a monument in Azerbaijan identified by the ID 93 Featured Picture by Diego Delso via Wikimedia Commons (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=15) - **Blue Hour Architectural Study** (Aug 31, 2026, Chefchaouen, Morocco) [Landscape] — Street and typical houses in Chefchaouen, the blue city of Morocco. Featured Picture by Fbrandao.1963 via Wikimedia Commons_-_Chaouen.jpg) (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=16) - **Misty Canopy of the Cloud Forest** (Aug 27, 2026, Gardens by the Bay, Singapore) [Seascape] — Cloud Forest from the entrance of the site, Gardens by the Bay, Singapore, a sunny day Featured Picture by Basile Morin via Wikimedia Commons (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=17) - **Stainless Steel Spheres of the Atomium** (Aug 23, 2026, Brussels, Belgium) [Landscape] — The Atomium 's central sphere reflecting the base and Osseghem park Featured Picture by Trougnouf (Benoit Brummer) via Wikimedia Commons.jpg) (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=18) - **Medieval Brick Towers of Ciechanów Castle** (Aug 19, 2026, Ciechanów, Poland) [Architecture] — Water tower in Ciechanów designed by Jerzy Michał Bogusławski in 1972. Featured Picture by 1bumer via Wikimedia Commons.jpg) (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=19) - **Carved Teak Heritage Pavilion, Luang Prabang** (Aug 15, 2026, Luang Prabang, Laos) [Architecture] — Carved wooden bench, furniture, textile crafts, lanterns and suspended mobile sculptures, at the wooden Heuan Chan heritage house, stilt building with wooden ceiling, Luang Prabang, Laos. Featured Picture by Basile Morin via Wikimedia Commons (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=20) - **Alpine Valley Pastures in High Summer** (Aug 11, 2026, Valgaudemar, French Alps) [Alpine] — View of Haute Severaisse valley and surrounding summits from the slopes of Les Vernets. Valgaudemar, France, Southern Alps. Downsampling of a larger picture. Featured Picture by Berrucomons via Wikimedia Commons (licensed under CC BY-SA 3.0). (https://www.example.com/photography/?photo=21) - **Double Rainbow Over Washfold Valley** (Aug 07, 2026, Washfold, North Yorkshire) [Landscape] — Rainbow over Washfold, North Yorkshire Featured Picture by Kreuzschnabel via Wikimedia Commons (licensed under CC BY-SA 3.0). (https://www.example.com/photography/?photo=22) - **Limestone Escarpment of Fremington Edge** (Aug 03, 2026, Fremington Edge, Yorkshire Dales) [Landscape] — Rough track leading from Fremington Edge towards Marrick on a sunny autumn afternoon Featured Picture by Kreuzschnabel via Wikimedia Commons (licensed under CC BY-SA 3.0). (https://www.example.com/photography/?photo=23) - **Dry-Stone Walled Country Lane, Swaledale** (Jul 30, 2026, Swaledale, Yorkshire Dales) [Landscape] — Country road in the Yorkshire Dales linking upper Swaledale to Askrigg, Wensleydale Featured Picture by Kreuzschnabel via Wikimedia Commons (licensed under CC BY-SA 3.0). (https://www.example.com/photography/?photo=24) - **Ribblehead Viaduct Across Batty Moss** (Jul 26, 2026, Ribblehead, North Yorkshire) [Architecture] — Ribblehead Viaduct, North Yorkshire, England, as seen from the north. In the distance is Pen-y-ghent. Featured Picture by Kreuzschnabel via Wikimedia Commons (licensed under CC BY-SA 3.0). (https://www.example.com/photography/?photo=25) - **Swaledale Valley Viewed from Kisdon Hill** (Jul 22, 2026, Kisdon Hill, Swaledale) [Landscape] — View into Swaledale (to the south-east) from the Pennine Way along Kisdon hill Featured Picture by Kreuzschnabel via Wikimedia Commons (licensed under CC BY-SA 3.0). (https://www.example.com/photography/?photo=26) - **Historic Stone Arch of Cogden Bridge** (Jul 18, 2026, Grinton, North Yorkshire) [Architecture] — Cogden Bridge, Grinton, North Yorkshire Featured Picture by Kreuzschnabel via Wikimedia Commons (licensed under CC BY-SA 3.0). (https://www.example.com/photography/?photo=27) - **Karst Peaks Along the Li River, Yangshuo** (Jul 14, 2026, Yangshuo, Guangxi) [Landscape] — panorama of Cuiping village, Yangshuo Guangxi 2016 Featured Picture by Chensiyuan via Wikimedia Commons (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=28) - **Gilded Temple Spire in Northern Thailand** (Jul 10, 2026, Chiang Mai, Thailand) [Landscape] — This is a photo of a monument in Thailand identified by the ID Featured Picture by BerryJ via Wikimedia Commons (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=29) - **Morning Mist Over the Studenytsia River** (Jul 06, 2026, Podilski Tovtry, Ukraine) [Twilight] — The sunrise over Studenycia river, Podilski Tovtry National Nature Park, Khmelnytskyi Oblast, Ukraine. Featured Picture by Moahim via Wikimedia Commons (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=30) - **Cirque Glacier in Pyrenees National Park** (Jul 02, 2026, Gavarnie, French Pyrenees) [Alpine] — The Pyrénées National Park, view on the Gavarnie valley, Hautes-Pyrénées, France. Featured Picture by Moahim via Wikimedia Commons (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=31) - **Aare River Arch Bridge in Solothurn** (Jun 28, 2026, Solothurn, Switzerland) [Architecture] — Bridge of the highway A5 over the Aare river. Municipalities Grenchen and Arch, Switzerland Featured Picture by Ikiwaner via Wikimedia Commons (licensed under CC BY-SA 3.0). (https://www.example.com/photography/?photo=32) - **Bangkok Skytrain Viaduct at Golden Hour** (Jun 24, 2026, Bangkok, Thailand) [Twilight] — A spectacular sunset in Bangkok, showing the skytrain and modern skyline down Thanon Naradhiwas Rajanagarindra, taken from the corner of Thanon Silom, with the Empire Tower and the Chong Nonsi BTS Station at the left side. Featured Picture by User:Diliff via Wikimedia Commons (licensed under CC BY-SA 3.0). (https://www.example.com/photography/?photo=33) - **Roman Arch Bridge of Alcántara** (Jun 20, 2026, Alcántara, Spain) [Architecture] — Roman Alcántara Bridge across the River Tajo, Cáceres Province, Extremadura, Spain. Featured Picture by Dantla from de.wikipedia via Wikimedia Commons (licensed under GFDL). (https://www.example.com/photography/?photo=34) - **Bridgewater Causeway Over the Derwent** (Jun 16, 2026, Derwent River, Tasmania) [Architecture] — Bridgewater Causeway and Bridgewater Bridge with Granton and Mt Wellington behind. Featured Picture by Noodle snacks via Wikimedia Commons (licensed under CC BY-SA 3.0). (https://www.example.com/photography/?photo=35) - **Coastal Causeway Bridge at Anjarle** (Jun 12, 2026, Anjarle, Maharashtra) [Architecture] — Anjarle is a village in the Konkan region of Maharashtra, India. These cows were resting in the middle of a bridge that spans over a creek near the village. The photograph captures them as rain starts to fall. This version removes a water spot from the photo. The other version is listed below. Featured Picture by Photographer: Dey.sandip Additional Credit: User Atention for water spot removal. via Wikimedia Commons (licensed under CC BY-SA 3.0). (https://www.example.com/photography/?photo=36) - **Gothic Stone Bridge in Kłodzko** (Jun 08, 2026, Kłodzko, Poland) [Architecture] — Gothic Bridge in Kłodzko Featured Picture by Jacek Halicki via Wikimedia Commons (licensed under CC BY-SA 3.0 pl). (https://www.example.com/photography/?photo=37) - **Medieval Stone Bridge Across the Nysa Kłodzka** (Jun 04, 2026, Bardo, Poland) [Architecture] — Stone bridge across Nysa Kłodzka river in Bardo, Poland. Featured Picture by Jacek Halicki via Wikimedia Commons (licensed under CC BY-SA 3.0 pl). (https://www.example.com/photography/?photo=38) - **Timber Footbridge Over Langweerderwielen** (May 31, 2026, Friesland, Netherlands) [Architecture] — In bridge bike path to Langweerderwielen (Langwarder Wielen) North Oudeweg under the viaduct of the A7 highway Featured Picture by Dominicus Johannes Bergsma via Wikimedia Commons_02.jpg) (licensed under CC BY-SA 4.0). (https://www.example.com/photography/?photo=39) - **Bac de Roda Cable-Stayed Bridge, Barcelona** (May 27, 2026, Barcelona, Spain) [Architecture] — Bac de Roda Bridge of architect Santiago Calatrava in Barcelona Featured Picture by Ralf Roletschek via Wikimedia Commons (licensed under GFDL 1.2). (https://www.example.com/photography/?photo=40)