Blog
Publish a personal blog managed entirely by your AI assistant. Write in Markdown, customize themes, and share posts with peers — all from a conversation.
What is this?
Crow includes a built-in blogging platform. You write posts by talking to your AI, and Crow handles rendering, publishing, RSS feeds, and theming. Posts are served as public HTML pages from your gateway.
Why would I want this?
- Write by talking — Describe what you want to write, and Crow drafts and publishes it
- Own your content — Posts live on your own server, not a third-party platform
- Built-in RSS — Readers can subscribe via RSS or Atom feeds without any extra setup
- Share with peers — Send posts directly to connected Crow users through P2P sharing
- Export anytime — Move your content to Hugo, Jekyll, or any static site generator
Setup & Public Access
Starting the blog server
Blog tools are available through two transport options:
- Stdio (MCP) — Run
npm run blog-serverto start the blog MCP server directly. This is what.mcp.jsonuses when Claude Code or another MCP client connects. - Gateway (HTTP) — Run
npm run gatewayto start the HTTP gateway, which hosts all MCP servers including the blog. The gateway also serves the public blog pages.
The blog MCP tools (create, edit, publish, etc.) work in both modes. Public web access to your blog requires the gateway.
Public blog routes
When the gateway is running, the blog is served at these public routes:
| Route | Description |
|---|---|
/blog | Blog homepage listing all published public posts |
/blog/:slug | Individual post page (e.g., /blog/notes-on-local-first-software) |
/blog/tag/:tag | Posts filtered by tag |
/blog/feed.xml | RSS 2.0 feed |
/blog/feed.atom | Atom 1.0 feed |
/blog/sitemap.xml | XML sitemap for search engine indexing |
RSS autodiscovery <link> headers are included automatically on all blog pages, so feed readers can find your feeds from any blog URL.
Gateway configuration
Set CROW_GATEWAY_URL in your .env file to your public-facing URL:
CROW_GATEWAY_URL=https://blog.example.comThis controls how URLs are generated in RSS/Atom feeds, Open Graph meta tags, and the sitemap. Without it, all URLs default to http://localhost:3001, which will not work for external visitors or social media previews.
Making it publicly accessible
The gateway listens on localhost:3001 by default. To make your blog reachable from the internet:
- Tailscale Funnel — Easiest option for Tailscale users. No port forwarding or domain registration needed. See details below.
- Caddy or nginx reverse proxy — Use a reverse proxy with automatic Let's Encrypt certificates for a custom domain. See Caddy example below.
- Direct port forwarding — Forward port 3001 on your router. Not recommended: exposes the full gateway (Crow's Nest, MCP endpoints) without TLS.
For a full deployment comparison, see the Making Your Blog Public section further down.
Writing a Post
Ask Crow to create a post:
"Write a blog post about my garden project this weekend"
"Create a draft post titled 'Notes on Local-First Software'"
Crow creates the post in Markdown, generates a URL-friendly slug, and saves it as a draft.
Post Fields
Each post has:
- Title — Displayed as the page heading and in feeds
- Slug — The URL path (e.g.,
/blog/notes-on-local-first-software) - Content — Markdown body, rendered to HTML on publish
- Tags — Optional categories for organization
- Status —
draftorpublished - Visibility — Controls who can see the post:
private— Only you (default)public— Anyone with the URLpeers— Only connected Crow peers
Publishing
When you're happy with a draft:
"Publish my post about local-first software"
The post becomes publicly accessible at http://your-server:3001/blog/notes-on-local-first-software.
To unpublish:
"Unpublish the garden project post"
Editing Posts
"Update my garden post — add a section about the raised beds"
"Change the title of my latest post to 'Weekend Garden Notes'"
Crow modifies the post in place. Published posts update immediately.
Listing and Searching
"Show me all my blog posts"
"Find posts tagged 'research'"
"Search my blog for 'neural networks'"
Blog posts are indexed with FTS5 full-text search, so keyword searches are fast even with hundreds of posts.
Themes
The blog uses the Dark Editorial theme by default — a clean, reading-focused design with dark and light mode support. The blog's color palette follows the Crow brand identity: indigo accents, deep blue-black backgrounds in dark mode, and warm stone tones in light mode. This ensures visual consistency between your blog and the Crow's Nest.
The theme controls:
- Typography and layout
- Code block syntax highlighting
- Header and footer styling
- Open Graph meta tags for social sharing previews
RSS and Atom Feeds
Feeds are generated automatically:
- RSS 2.0:
http://your-server:3001/blog/feed.xml - Atom:
http://your-server:3001/blog/feed.atom
Feeds include the 20 most recent published posts with full content.
Exporting
Move your content to a static site generator:
"Export my blog posts for Hugo"
"Export all posts as Jekyll-compatible Markdown"
Crow generates Markdown files with the appropriate frontmatter format for your target platform.
Sharing Posts with Peers
If you have connected peers (see the Sharing guide), you can send posts directly:
"Share my latest blog post with Alice"
The recipient gets the full post content in their Crow inbox.
Blog Configuration
Set blog metadata in your .env:
CROW_BLOG_TITLE=My Blog
CROW_BLOG_DESCRIPTION=Thoughts on technology and gardening
CROW_BLOG_AUTHOR=Your NameThese values appear in the RSS feed and page headers.
Making Your Blog Public
Your blog has no web presence without the gateway running. How your blog becomes accessible depends on your deployment:
| Deployment | Blog accessible? | How |
|---|---|---|
| Desktop (stdio) | No | Gateway not running — no web blog |
| Self-hosted (Pi/server) | LAN only by default | Available at http://<server-ip>:3001/blog on your local network |
| Cloud (Render/Oracle) | Yes — public internet | Blog at https://your-crow-server/blog |
| Managed hosting | Yes — public internet | Blog at username.crow.maestro.press/blog |
For self-hosted setups, see the sections below to make your blog accessible from the internet.
Tailscale Funnel (Recommended for Self-Hosted)
Tailscale Funnel exposes your gateway to the public internet through Tailscale's infrastructure — no port forwarding, no dynamic DNS, no domain registration needed.
# Enable Funnel in your Tailscale admin console first:
# https://login.tailscale.com/admin/dns → Enable Funnel
# Then expose your gateway
tailscale funnel --bg --https=443 http://localhost:3001Your blog is now publicly accessible at https://<hostname>.your-tailnet.ts.net/blog.
The Crow's Nest remains private — requests from public IPs get a 403 response because they don't fall within the allowed network ranges. Only the blog (and other unauthenticated routes like /health and /setup) are effectively visible to the public.
Custom Domain with Caddy
If you want a custom domain that only serves your blog (not the full gateway), you can configure Caddy as a reverse proxy with path restrictions.
WARNING
This Caddyfile replaces the default full-gateway proxy. If you're using Caddy to serve the Crow's Nest over Tailscale, you'll need separate Caddy configurations or a combined Caddyfile.
yourdomain.com {
# Only proxy blog and health routes
handle /blog* {
reverse_proxy localhost:3001
}
handle /health {
reverse_proxy localhost:3001
}
# Block everything else
handle {
respond "Not Found" 404
}
}Caddy automatically provisions Let's Encrypt certificates for your domain.
Setting CROW_GATEWAY_URL
For RSS feed links, Open Graph meta tags, sitemap URLs, and social media previews to work correctly, set the public URL of your gateway:
# In your .env file
CROW_GATEWAY_URL=https://yourdomain.comWithout this, links in feeds and social previews will point to http://localhost:3001, which won't work for external visitors.