A fast blogging platform with Go, Nuxt, Caddy and Docker.
I built Typen, a clean blogging platform with Go, Nuxt, Caddy, Docker, Redis, MySQL, and Meilisearch. It focuses on simple publishing, SEO-ready blogs, and Cleo, an AI reading assistant without AI bloat.

Martin Binder
ID @martin
Typen: AI Without the Bloat
Typen also includes Cleo, an AI reading assistant built directly into blog posts.
But I do not want Typen to become another AI content generator.
The goal is not to generate endless content. AI should only help where it is genuinely useful:
-
Helping readers understand posts
-
Answering questions about an article
-
Helping readers get more value from what they are already reading
Typen is available at typen.blog.
Tech Stack
The current stack includes:
-
Go backend
-
Nuxt dashboard
-
Nuxt blog frontend
-
Caddy reverse proxy
-
Docker
-
Docker Compose
-
MySQL
-
Redis
-
Meilisearch
-
GitHub Actions CI/CD
-
VPS deployment
The application is split into multiple services:
app/
├── server/ # Go API
├── client/ # Nuxt dashboard
├── blogclient/ # Nuxt public blog frontend
├── sitemap/ # XML sitemap generator
├── dbadmin/ # Database administration utility
└── docker/
└── caddy/ # Reverse proxy and routing
Architecture
Typen has one main Go API and two Nuxt frontends.
The client application is the dashboard where users manage their blogs.
The blogclient application renders public blogs.
Both frontends communicate with the same Go backend.
Caddy sits in front of the services and handles routing, custom domains, subdomains, and HTTPS.
User
↓
Caddy
↓
┌──────────────┬─────────────────┐
│ Dashboard │ Public Blogs │
│ Nuxt client │ Nuxt blogclient │
└──────┬───────┴────────┬────────┘
↓ ↓
Go API
↓ ↓ ↓
MySQL Redis Meilisearch
Docker-Native Deployment
Everything runs using Docker and Docker Compose.
For production, the application can be started with:
docker compose up -d
For development, I use a separate Compose file:
make dev
The Makefile also includes commands for common tasks:
env:
@cp -n .env.example .env || true
dev:
@docker compose -f compose-dev.yaml up --build
prod:
@docker compose up -d
deploy:
@git pull origin main
@APP_ENV=prod docker compose up -d --build
@docker compose exec sitemap ./sitemap-worker generate
@docker image prune -f
logs:
@docker compose logs -f $(SERVICE)
ps:
@docker compose ps
down:
@docker compose down
test:
@go test -C ./server ./...
lint:
@cd ./server && golangci-lint run
fmt:
@cd ./server && go fmt
@cd ./client && pnpm run format
@cd ./blogclient && pnpm run format
CI/CD With GitHub Actions
I use GitHub Actions to build Docker images and push them to GitHub Container Registry.
The workflow checks which directories changed and rebuilds only the affected services:
-
Changes in
server/**rebuild the Go API -
Changes in
client/**rebuild the dashboard -
Changes in
blogclient/**rebuild the public blog frontend -
Changes in
sitemap/**rebuild the sitemap service
There is also a manual force_rebuild option for rebuilding every service from scratch.
After the images are built, the workflow connects to the VPS over SSH and runs:
cd /srv/app
git pull
docker compose pull
APP_ENV=prod APP_VERSION=<short-sha> docker compose up -d
docker image prune -a -f
It is a simple setup, but it works well for a bootstrapped project.
SEO and Sitemaps
SEO is an important part of Typen.
Each blog can generate its own sitemap. The sitemap service is written in Go and creates XML sitemap files for published posts and tags.
It can split large sitemaps into multiple files using the standard limit of 50,000 URLs per file.
A simplified version looks like this:
const maxURLsPerFile = 50000
For each blog with sitemaps enabled, the service:
-
Loads the blog’s custom domain or subdomain
-
Fetches published posts
-
Fetches tags
-
Writes the sitemap XML files
-
Writes a sitemap index
Generated URLs include posts such as:
https://example.com/posts/my-post
And topics such as:
https://example.com/topic/go
Themes With CSS Variables
Typen uses CSS variables for blog customization.
This keeps themes simple and flexible without requiring a complex theme engine.
Each blog can have its own colors, styles, and visual settings while keeping the frontend fast and maintainable.
The goal is to let users customize their blogs without turning Typen into a large website builder.
Local Development
For local development, Typen uses subdomain-based routing.
I add local domains to /etc/hosts:
127.0.0.1 typen.local
127.0.0.1 watches.typen.local blog.typen.local
Then I can open:
http://typen.local
for the dashboard, and:
http://watches.typen.local
for a local test blog.
Current Stage
Typen is still early, but the main structure is already working:
-
Dashboard
-
Public blog frontend
-
Go backend
-
Docker deployment
-
CI/CD
-
Sitemap generation
-
Caching
-
Themes
-
Markdown posts
-
Cleo AI reading assistant
I am preparing for a bigger launch, but first I want to collect feedback from developers, creators, bloggers, and indie makers.
What I Would Love Feedback On
I would appreciate feedback on:
-
The idea
-
The technical architecture
-
The UX
-
The positioning
-
The SEO features
-
The AI reading assistant
-
What would make you use a blogging platform today
Final Thoughts
I do not want Typen to become a bloated website builder or another AI content machine.
I want it to be a clean, fast place where people can write, publish, and share ideas, with AI used only where it genuinely helps the reader.
Thanks for reading.
Comments
No comments yet.