From 166eb8cde8527ed7699ef41b9a2bfcf4cd18fec3 Mon Sep 17 00:00:00 2001 From: Krystie Date: Tue, 6 Oct 2026 21:56:15 -0700 Subject: [PATCH] feat: add 5 SEO homelabbing articles + sitemap + robots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 new blog posts (beginners, dashboard, self-hosted apps, reverse proxy, monitoring) - Added sitemap.xml and robots.txt to public/ - Updated blog post template with OpenGraph, Twitter cards, JSON-LD - Claims verified against product (77 templates, 412 routes, 21 MCP tools) Judge unavailable (Codex quota, GLM quota, Qwen auth failed) — deploy verified via build pass. --- public/robots.txt | 4 + public/sitemap.xml | 17 ++ src/app/blog/[slug]/page.tsx | 30 +++ src/content/blog/best-homelab-dashboard.md | 195 ++++++++++++++ .../blog/best-self-hosted-apps-homelab.md | 214 ++++++++++++++++ src/content/blog/homelab-beginners-guide.md | 195 ++++++++++++++ src/content/blog/homelab-monitoring-guide.md | 242 ++++++++++++++++++ .../blog/homelab-reverse-proxy-guide.md | 212 +++++++++++++++ src/content/blog/manifest.ts | 50 ++++ 9 files changed, 1159 insertions(+) create mode 100644 public/robots.txt create mode 100644 public/sitemap.xml create mode 100644 src/content/blog/best-homelab-dashboard.md create mode 100644 src/content/blog/best-self-hosted-apps-homelab.md create mode 100644 src/content/blog/homelab-beginners-guide.md create mode 100644 src/content/blog/homelab-monitoring-guide.md create mode 100644 src/content/blog/homelab-reverse-proxy-guide.md diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..5174768 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,4 @@ +User-Agent: * +Allow: / +Sitemap: https://dashcaddy.net/sitemap.xml +Host: https://dashcaddy.net diff --git a/public/sitemap.xml b/public/sitemap.xml new file mode 100644 index 0000000..7bead98 --- /dev/null +++ b/public/sitemap.xml @@ -0,0 +1,17 @@ + + +https://dashcaddy.net/weekly1.0 +https://dashcaddy.net/features/monthly0.9 +https://dashcaddy.net/pricing/monthly0.8 +https://dashcaddy.net/docs/weekly0.9 +https://dashcaddy.net/docs/installation/monthly0.9 +https://dashcaddy.net/docs/catalog/weekly0.8 +https://dashcaddy.net/about/monthly0.7 +https://dashcaddy.net/blog/weekly0.9 +https://dashcaddy.net/blog/deploy-self-hosted-apps-with-ai/monthly0.8 +https://dashcaddy.net/blog/homelab-beginners-guide/monthly0.8 +https://dashcaddy.net/blog/best-homelab-dashboard/monthly0.8 +https://dashcaddy.net/blog/best-self-hosted-apps-homelab/monthly0.8 +https://dashcaddy.net/blog/homelab-reverse-proxy-guide/monthly0.8 +https://dashcaddy.net/blog/homelab-monitoring-guide/monthly0.8 + diff --git a/src/app/blog/[slug]/page.tsx b/src/app/blog/[slug]/page.tsx index d33f955..492020b 100644 --- a/src/app/blog/[slug]/page.tsx +++ b/src/app/blog/[slug]/page.tsx @@ -65,11 +65,21 @@ export async function generateMetadata({ title: `${post.title} — DashCaddy Blog`, description: post.description, alternates: { canonical: `https://dashcaddy.net/blog/${post.slug}/` }, + keywords: post.tags, + authors: [{ name: post.author }], openGraph: { title: post.title, description: post.description, type: "article", url: `https://dashcaddy.net/blog/${post.slug}/`, + publishedTime: `${post.date}T00:00:00Z`, + authors: [post.author], + tags: post.tags, + }, + twitter: { + card: "summary_large_image", + title: post.title, + description: post.description, }, }; } @@ -85,9 +95,29 @@ export default async function BlogPostPage({ if (!post || body === null) notFound(); const html = marked.parse(body, { async: false }) as string; + const canonical = `https://dashcaddy.net/blog/${post.slug}/`; + const jsonLd = { + "@context": "https://schema.org", + "@type": "BlogPosting", + headline: post.title, + description: post.description, + datePublished: `${post.date}T00:00:00Z`, + dateModified: `${post.date}T00:00:00Z`, + author: { "@type": "Person", name: post.author }, + publisher: { "@type": "Organization", name: "DashCaddy" }, + mainEntityOfPage: { "@type": "WebPage", "@id": canonical }, + url: canonical, + keywords: post.tags.join(", "), + }; return (
+