# SEO Sidecar > Inject up-to-date Schema.org JSON-LD into your nginx-served sites with **zero crons, zero site file changes, always fresh.** A FastAPI sidecar + nginx SSI integration that lets an upstream AI/automation push schemas to your hosting machine in real time. [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE) [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/) [![FastAPI](https://img.shields.io/badge/FastAPI-0.104%2B-009688.svg)](https://fastapi.tiangolo.com/) [![nginx](https://img.shields.io/badge/nginx-1.18%2B-009639.svg)](https://nginx.org/) ## Why this exists If you host static or server-rendered HTML through nginx and want **fresh, dynamic Schema.org JSON-LD** in every page's `` without redeploying the site every time a schema changes, you have three bad options: 1. **Edit the HTML files** every time → site redeployment per schema change 2. **Cron job that rebuilds + redeploys** → stale between cron runs, slow propagation 3. **Server-side rendering** → couples schema generation to your rendering tier SEO Sidecar is the fourth option. An upstream process (your AI, your CMS, your trend analyzer, whatever) pushes JSON-LD to a tiny FastAPI service on your nginx host. nginx pulls the schema in via SSI on every page load. Schema updates take effect **instantly** with no site redeployment, no cron lag, no rendering coupling. Built in production for [ThatDevPro](https://www.thatdevpro.com)'s network of nine client websites. ## Architecture ``` (your AI publishing source) │ │ Push over Tailscale (event-driven) │ POST /update/{site} with JSON-LD │ ▼ ┌──────────────────────────────────────────┐ │ (your nginx host) │ │ │ │ seo-sidecar (localhost:9090) │ │ ├── SQLite: /var/lib/seo-sidecar/ │ │ ├── Receives pushes from upstream │ │ ├── Serves schemas to nginx │ │ └── Keeps history + versioning │ │ │ │ nginx │ │ ├── SSI include on every page load │ │ ├── Fetches from localhost:9090 │ │ ├── 5min proxy_cache (configurable) │ │ └── 1s timeout (pages never stall) │ │ │ │ 9 hosted sites │ │ └── Each gets dynamic JSON-LD in │ └──────────────────────────────────────────┘ ``` ## How It Works 1. **Your upstream service decides** a schema needs updating (trend shift, new FAQ, competitor gap) 2. **Upstream pushes** the new JSON-LD to `http://:9090/update/{site}` over Tailscale 3. **Sidecar stores** it in SQLite with version history 4. **nginx SSI** fetches from `localhost:9090/schema/{site}` on every HTML page load 5. **Schema appears** in the `` of the site — search engines and AI crawlers see it immediately No cron jobs. No file writes. No site deployments. Upstream controls schema state remotely. ## Files | File | Where It Goes | Purpose | |------|--------------|---------| | `sidecar.py` | `/opt/seo-sidecar/` on the sidecar host | FastAPI service — receives pushes, serves to nginx | | `nginx-seo-sidecar.conf` | `/etc/nginx/conf.d/` on the sidecar host | Upstream + hostname map | | `seo-inject.conf` | `/etc/nginx/snippets/` on the sidecar host | Drop-in include for server blocks | | `megamind_push.py` | upstream nodes | CLI push client | | `seo_client.go` | Go push client | Go push client for integration | | `seo-sidecar.service` | `/etc/systemd/system/` on the sidecar host | systemd unit | | `deploy-sidecar.sh` | Run once on the sidecar host | Full automated deployment | ## Deploy on the sidecar host ```bash # Copy files to your sidecar host scp -r seo-sidecar/ :/tmp/seo-sidecar/ # SSH in and deploy ssh cd /tmp/seo-sidecar sudo bash deploy-sidecar.sh ``` Then add one line to each nginx server block: ```nginx include /etc/nginx/snippets/seo-inject.conf; ``` Reload nginx: ```bash nginx -t && systemctl reload nginx ``` ## Push from your upstream ```bash # Push single site python megamind_push.py push thatdeveloperguy # Push all 9 sites python megamind_push.py push-all # Bulk push (single HTTP request) python megamind_push.py push-bulk # Check what's live python megamind_push.py status # View version history python megamind_push.py history thatdeveloperguy ``` Or from Go: ```go client := seo.NewClient("http://:9090", "your-token") client.Push("thatdeveloperguy", jsonldString) ``` ## API Endpoints ### Push (MEGAMIND → Sidecar) - `POST /update/{site}` — Push schema for one site - `POST /update-bulk` — Push schemas for multiple sites - `DELETE /schema/{site}` — Remove a schema ### Serve (nginx → Sidecar) - `GET /schema/{site}` — Returns `