## Instructions - Install paths: Ghost(Pro) managed (fastest) vs self-host `ghost install` on Ubuntu 22.04 Node 18 + MySQL 8 + Nginx + systemd; `ghost ls/config/set url` for domain; 1GB RAM minimum, swap on 1GB droplets. - Content model: Posts (feed/newsletter) vs Pages (static about/contact); Tags (public taxonomy) vs Authors (bylines); `html/mhtml/mobiledoc` API bodies; featured + `visibility: public|members|paid`. - Editor: Koenig cards (image/gallery/callout/bookmark/html); canonical slug auto from title, custom `canonical_url`, `codeinjection_head/foot` per post for embeds; schedule + `send_email_when_published` flag. - Themes (Handlebars): `post.hbs/page.hbs/index.hbs/author.hbs/tag.hbs`, partials `partials/card.hbs`, helpers `{{#foreach posts}}{{title}}{{excerpt words="40"}}{{/foreach}}`, `{{ghost_head}}/{{ghost_foot}}` required; zip upload in Design settings. - Custom settings: `package.json {engines, custom: {templates, settings}}` theme settings (accent, feed layout); routes.yaml `collections: /blog/: /podcast/:` + redirects.yaml 301s for migrations. - Members: `members/signup` Portal, tiers Free/Monthly/Yearly with Stripe connect, `{{#if @member.paid}}` gating, complimentary plans via Admin; `newsletters` multi-brand with `slug` + sender identity. - Newsletters: publish → email to `all|free|paid` segments, `email_subject`, `email_only` posts, batch sending via Mailgun; test with `?uuid` preview link before blast; archive page auto. - Domain + mail: custom domain A/CNAME to Ghost(Pro) or self Nginx `proxy_pass 127.0.0.1:2368`; transactional via Mailgun (`mail__options`), bulk newsletter Mailgun API key in config; SPF/DKIM/DMARC TXT records required. - API: Content API (`/ghost/api/content/posts/?key=...&include=tags,authors`) public reads; Admin API JWT (`AdminAPI key id:secret` → HS256) for writes/migrations; webhooks `post.published` → rebuild search/social. - SEO: `{{ghost_head}}` meta/canonical/JSON-LD, `robots.txt` + `sitemap.xml` auto, Twitter/FB cards in post settings, `og:image` 1200x630; redirects.yaml preserves SEO on replatform. - Backups: `ghost backup` + MySQL `mysqldump` nightly to S3, `content/images/` rsync; export JSON in Labs before theme surgery; test restore on staging droplet. - Perf: Cloudflare proxy + `cache-control` on images, `srcset` responsive in theme (`{{img_url feature_image size="l"}}`), lazy `loading="lazy"`, remove unused JS; Ghost(Pro) edge cache handles spikes. ## Examples - Paid newsletter: Free + $8/mo tiers, `visibility:paid` deep-dives, free teasers with `` cut, Mailgun bulk, Portal signup, Stripe test clock before launch. - Company blog: custom `blog.hbs` collection, `routes.yaml /blog/` + `/docs/` pages, Algolia/Typesense webhook index on `post.published`, custom domain + Cloudflare. - Migration: WordPress Ghost plugin export → `ghost import`, redirects.yaml from old `/p?id=` URLs, theme port to Handlebars partials, members CSV import with Stripe IDs. ## Workflows 1. Provision: Ghost(Pro) trial or `ghost install` (MySQL+Nginx+SSL), set URL, admin user, Mailgun keys + domain DNS. 2. Theme: activate Source/Casper, customize `post.hbs` partials + accent, upload zip, set `routes.yaml` collections + `redirects.yaml`. 3. Model: tags/authors/pages, member tiers + Stripe, newsletters brands, Portal copy + pricing page. 4. Publish: draft → Koenig cards → slug/canonical/OG → test email → schedule or publish+send to segment. 5. Operate: backups (DB+images+JSON), updates `ghost update`, webhook search/social, Cloudflare cache + analytics. ## Templates - Theme post + routes: ```hbs {{! post.hbs }} {{!< default}}
{{#post}}

{{title}}

{{authors}}

{{#if feature_image}}{{/if}}
{{content}}
{{#if @member.paid}}

Thanks member!

{{else}}Go paid{{/if}}{{/post}}
{{ghost_head}} ``` ```yaml # routes.yaml routes: { /about/team/: { template: team, data: page.team } } collections: { /blog/: { permalink: /blog/{slug}/, template: index, filter: 'tag:blog' }, /: { permalink: /{slug}/, template: index } } ``` - Content API + webhook: ```js const api = new GhostContentAPI({ url: 'https://blog.example.com', key: 'CONTENT_KEY', version: 'v5.0' }); const posts = await api.posts.browse({ limit: 5, include: 'tags,authors', filter: 'tag:news' }); // webhook server app.post('/ghost/published', express.json(), async (req, res) => { if (req.body.post?.current) await indexSearch(req.body.post.current); res.sendStatus(200); }); ``` - Nginx + mail config: ``` server { server_name blog.example.com; location / { proxy_pass http://127.0.0.1:2368; proxy_set_header X-Forwarded-Proto https; } } ``` ```json { "url": "https://blog.example.com", "mail": { "transport": "SMTP", "options": { "host": "smtp.mailgun.org", "port": 587, "auth": { "user": "postmaster@mg.example.com", "pass": "KEY" } } } } ``` ## Tools - SARAH shell_run for `ghost install/ls/update/backup`, `gscan` theme check, `mysqldump`, Mailgun log tail. - SARAH file_write for `*.hbs/routes.yaml/redirects.yaml`; web_fetch for Ghost + Handlebars + Mailgun docs. ## Advanced - Headless Ghost: Content API + Next.js/Astro SSG (`getStaticProps` revalidate 300), Preview API drafts with `?key` + basic auth, webhook `post.published` → Vercel redeploy; keep `{{ghost_head}}` equivalent meta in frontend. - Multi-brand: two newsletters (Weekly + DeepDive) separate slugs/senders, `filter: newsletter:slug` collections, per-newsletter `routes.yaml` archives, Stripe multiple products mapped to tiers. - Scale: MySQL read tuning + `ghost restart` zero-downtime via systemd, Cloudflare APO + image `size="w600/w1000/w1600"` srcsets, Uptime Kuma on `/ghost/api/admin/site/`, S3 `content/images` offload via storage adapter. ## Documentation - https://ghost.org/docs/ - https://ghost.org/docs/themes/ - https://ghost.org/docs/members/ - https://ghost.org/docs/config/ - https://handlebarsjs.com/guide/