From 16498f564d3c79c9b4f405992e3dfc5bb2709b7f Mon Sep 17 00:00:00 2001 From: Timo Knuth Date: Wed, 25 Mar 2026 20:09:21 -0500 Subject: [PATCH] Docker + Readme --- .dockerignore | 15 +-- Caddyfile | 28 ++--- Dockerfile | 4 +- README.md | 284 +++------------------------------------------ docker-compose.yml | 4 +- 5 files changed, 31 insertions(+), 304 deletions(-) diff --git a/.dockerignore b/.dockerignore index 20c690b..ec99e3e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,15 +1,6 @@ +node_modules +dist .git .gitignore .agents -node_modules -dist -*.log -Dockerfile -docker-compose.yml -README.md -*.md -bullet -ellipsis -em -left -right +npm-debug.log* diff --git a/Caddyfile b/Caddyfile index 7a84d94..e60c506 100644 --- a/Caddyfile +++ b/Caddyfile @@ -1,22 +1,12 @@ -# Caddy inside the Docker container — listens on :80 -# The host Caddy reverse-proxies to this container and handles HTTPS. :80 { - root * /srv - encode zstd gzip + root * /srv + encode zstd gzip + try_files {path} {path}/ /index.html + file_server - header { - X-Content-Type-Options nosniff - X-Frame-Options DENY - Referrer-Policy strict-origin-when-cross-origin - Permissions-Policy "geolocation=(), microphone=(), camera=()" - -Server - } - - # Long-term caching for hashed assets - @assets path /assets/* /images/* /logo.svg /public/* - header @assets Cache-Control "public, max-age=31536000, immutable" - - # SPA fallback: prerendered routes get their own index.html, rest falls back - try_files {path} {path}/index.html /index.html - file_server + header { + X-Content-Type-Options "nosniff" + Referrer-Policy "strict-origin-when-cross-origin" + X-Frame-Options "SAMEORIGIN" + } } diff --git a/Dockerfile b/Dockerfile index 450db82..97b954d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM node:22-alpine AS build WORKDIR /app -COPY package*.json ./ +COPY package.json package-lock.json ./ RUN npm ci COPY . . @@ -14,5 +14,3 @@ COPY Caddyfile /etc/caddy/Caddyfile COPY --from=build /app/dist /srv EXPOSE 80 - -CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"] diff --git a/README.md b/README.md index b8b70f6..9d1f2a1 100644 --- a/README.md +++ b/README.md @@ -1,293 +1,41 @@ -# Bay Area IT — Website +# Bay Area IT -Marketing website for **Bay Area IT**, an IT service provider based in Corpus Christi, TX. -Built with React 19, Vite 6, TypeScript, and Tailwind CSS. Deployed as a static site served by Caddy inside Docker. +Vite/React marketing site for `bayareait.services`. ---- - -## Table of Contents - -- [Tech Stack](#tech-stack) -- [Project Structure](#project-structure) -- [Local Development](#local-development) -- [Build & Preview](#build--preview) -- [Deployment (Docker + Caddy)](#deployment-docker--caddy) -- [Adding Content](#adding-content) -- [Scripts Reference](#scripts-reference) - ---- - -## Tech Stack - -| Layer | Technology | -|---|---| -| UI Framework | React 19 | -| Build Tool | Vite 6 | -| Language | TypeScript 5 | -| Styling | Tailwind CSS 3 | -| Routing | React Router 7 | -| Animations | Framer Motion 12, GSAP 3 | -| Smooth Scroll | Lenis | -| Web Server | Caddy 2 (inside Docker) | -| Containerization | Docker + Docker Compose | - ---- - -## Project Structure - -``` -bayarea/ -├── components/ # Shared UI components -│ ├── Navbar.tsx -│ ├── Footer.tsx -│ ├── Hero.tsx -│ ├── Services.tsx -│ ├── Blog.tsx -│ ├── CTA.tsx -│ ├── Testimonials.tsx -│ ├── Process.tsx -│ ├── AreasWeServe.tsx -│ ├── SEO.tsx # Head/meta tag injection -│ ├── Breadcrumb.tsx -│ └── LoadingScreen.tsx -├── src/ -│ ├── pages/ # Route-level page components -│ │ ├── HomePage.tsx -│ │ ├── AboutPage.tsx -│ │ ├── ServicesPage.tsx -│ │ ├── ServicePage.tsx # Dynamic: /services/:slug -│ │ ├── BlogPage.tsx -│ │ ├── BlogPostPage.tsx # Dynamic: /blog/:slug -│ │ ├── LocationPage.tsx # Dynamic: /locations/:slug -│ │ ├── LocationsPage.tsx -│ │ ├── ContactPage.tsx -│ │ ├── PrivacyPolicyPage.tsx -│ │ ├── TermsOfServicePage.tsx -│ │ └── LegalPage.tsx -│ ├── data/ -│ │ └── seoData.ts # All location, service, and blog post data -│ ├── routes/ # Route definitions -│ └── index.css # Global styles -├── scripts/ -│ ├── prerender-routes.ts # Generates per-route index.html files -│ ├── prune-dist-assets.mjs # Removes unused assets from dist/ -│ ├── generate-sitemap.ts # Generates public/sitemap.xml -│ ├── generate-robots.ts # Generates public/robots.txt -│ └── optimize-images.mjs # Converts images to WebP -├── public/ -│ ├── assets/services/ # Service page images (.webp) -│ ├── images/blog/ # Blog post images (.webp) -│ ├── sitemap.xml -│ └── robots.txt -├── Dockerfile # Multi-stage: Node build → Caddy serve -├── docker-compose.yml # Runs the container on localhost:8080 -├── Caddyfile # Caddy config inside the container -├── caddy-host.snippet # Paste this into your host Caddy config -├── tailwind.config.cjs -├── postcss.config.cjs -├── vite.config.ts -└── tsconfig.json -``` - ---- - -## Local Development - -### Prerequisites - -- Node.js 22+ (or use [nvm](https://github.com/nvm-sh/nvm)) -- npm - -### Setup +## Local ```bash -# Install dependencies npm install - -# Start the dev server npm run dev ``` -The app runs at **http://localhost:3012** - -Hot Module Replacement (HMR) is enabled. If port 3012 is taken, Vite picks the next available port automatically. - ---- - -## Build & Preview +## Production build ```bash -# Production build (Vite + prerender + asset pruning) npm run build - -# Preview the production build locally -npm run preview ``` -The build pipeline runs three steps in sequence: +The production build regenerates `robots.txt` and `sitemap.xml`, runs Vite, prunes unused assets, and prerenders route HTML into `dist/`. -1. **`vite build`** — bundles and outputs to `dist/` -2. **`prune-dist-assets.mjs`** — removes any unreferenced files from `dist/assets/` -3. **`prerender-routes.ts`** — writes a unique `index.html` per route into `dist/` with correct ``, `<meta>`, canonical URLs, Open Graph tags, and JSON-LD schema - -The result is a fully static site where every URL has its own HTML file — no server-side rendering required. - ---- - -## Deployment (Docker + Caddy) - -This project uses a **two-Caddy setup**: - -``` -Internet - └── Host Caddy (HTTPS, port 443) - └── Docker container (internal port 80 → host localhost:8080) - └── Caddy inside container - └── /srv (built static files) -``` - -### Step 1 — Build and start the container - -On your server, copy the project files (or clone the repo), then run: +## Docker ```bash -docker compose up -d --build +docker compose up --build -d ``` -This builds the image (Node 22 compiles the app, Caddy serves it) and starts the container. -The app is now available at **http://localhost:8080** — only reachable from the server itself. +The container serves the built site on `http://127.0.0.1:8080`. -To verify: - -```bash -curl -I http://localhost:8080 -# HTTP/1.1 200 OK -``` - -### Step 2 — Configure the host Caddy - -Add the following to your host Caddy config (usually `/etc/caddy/Caddyfile`). -A ready-to-paste version is in `caddy-host.snippet`: +## Reverse proxy with host Caddy ```caddy -bayareait.services, www.bayareait.services { - encode zstd gzip - reverse_proxy localhost:8080 - - @www host www.bayareait.services - redir @www https://bayareait.services{uri} permanent +bayareait.services { + encode zstd gzip + reverse_proxy 127.0.0.1:8080 } ``` -Replace `bayareait.services` with your actual domain. +## Launch notes -### Step 3 — Reload host Caddy - -```bash -sudo systemctl reload caddy -# or -caddy reload --config /etc/caddy/Caddyfile -``` - -Caddy automatically obtains and renews an SSL certificate from Let's Encrypt — no manual certificate management needed. - -### Updating the site - -```bash -# Pull latest changes, rebuild, restart -git pull -docker compose up -d --build -``` - -Zero-downtime: Docker Compose replaces the old container while the new one starts. - -### Useful Docker commands - -```bash -# View logs -docker compose logs -f - -# Stop the container -docker compose down - -# Rebuild without cache -docker compose build --no-cache -docker compose up -d -``` - ---- - -## Adding Content - -All page content is driven by **`src/data/seoData.ts`**. No new page files needed for standard locations, services, or blog posts — just add a new entry to the right array. - -### Add a location page - -```ts -// src/data/seoData.ts → locationData array -{ - city: "Sinton", - slug: "locations/it-support-sinton", - title: "IT Support Sinton, TX | Bay Area IT", - description: "...", - h1: "IT Support for Businesses in Sinton, TX", - keywords: ["IT support Sinton", "..."], - content: `<p>...</p>`, - faq: [ - { question: "...", answer: "..." } - ] -} -``` - -### Add a service page - -```ts -// src/data/seoData.ts → serviceData array -{ - id: "9", - slug: "services/cloud-backup", - title: "Cloud Backup Services | Bay Area IT", - description: "...", - h1: "Cloud Backup for Corpus Christi Businesses", - keywords: ["cloud backup", "..."], - content: `<p>...</p>`, - faq: [] -} -``` - -### Add a blog post - -```ts -// src/data/seoData.ts → blogPostData array -{ - slug: "blog/your-post-slug", - title: "Your Post Title | Bay Area IT", - description: "...", - h1: "Your Post Heading", - keywords: ["..."], - content: `<p>...</p>`, - date: "2026-03-25", - image: "/images/blog/your-image.webp" -} -``` - -After adding content, rebuild: - -```bash -npm run build -# or on the server: -docker compose up -d --build -``` - ---- - -## Scripts Reference - -| Script | Command | Description | -|---|---|---| -| Dev server | `npm run dev` | Starts Vite dev server on port 3012 | -| Production build | `npm run build` | Vite build + asset pruning + prerendering | -| Preview build | `npm run preview` | Serves `dist/` locally via Vite | -| Generate sitemap | `npm run generate:seo` | Writes `public/sitemap.xml` and `public/robots.txt` | -| Optimize images | `npm run optimize:images` | Converts images in `public/` to WebP | -| Prerender only | `npm run prerender:routes` | Re-runs route prerendering on existing `dist/` | +- Static assets are served by Caddy inside the container. +- SPA fallback is enabled while prerendered route folders still resolve directly. +- Claims such as `24/7`, `30+ local businesses`, and legal company details should be verified before launch. diff --git a/docker-compose.yml b/docker-compose.yml index 661ab71..4770b86 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,9 @@ services: - web: + bayarea-site: build: context: . dockerfile: Dockerfile - image: bay-area-affiliates:latest + container_name: bayarea-site restart: unless-stopped ports: - "127.0.0.1:8080:80"