GoBlog
Simple blogging system written in Go
Install / Use
/learn @jlelse/GoBlogREADME
GoBlog
GoBlog is a single-user, multi-blog platform written in Go. It's designed to be simple, fast, and extensible while giving you full control over your content through IndieWeb and ActivityPub protocols.
Table of Contents
- What is GoBlog?
- Key Features
- Quick Start
- Installation
- Configuration
- Writing Posts
- Editor & Publishing
- IndieWeb & Fediverse
- Optional Features
- Plugins
- Administration
- CLI Commands
- Troubleshooting
- Advanced Topics
What is GoBlog?
GoBlog is a blogging engine built for people who want:
- Full ownership of their content with IndieWeb and ActivityPub support
- Simplicity: One binary, SQLite database, minimal dependencies
- Performance: Fast rendering with built-in caching
- Flexibility: Multiple blogs, sections, taxonomies, and custom plugins
- Privacy: Optional private mode to restrict access
Philosophy
- Opt-in features: Most features are disabled by default - enable only what you need
- Markdown-first: Write in Markdown with optional front matter
- No themes: Customize through configuration and plugins, not themes
- Docker-friendly: Designed to run in containers with simple volume mounts
Key Features
Core Functionality
- ✅ Markdown posts with front matter support
- ✅ Multiple blogs under one installation (e.g., for different languages)
- ✅ Sections and taxonomies (tags, categories, etc.)
- ✅ Web editor with live preview
- ✅ Media uploads with optional automatic compression
- ✅ Full-text search (SQLite FTS5)
- ✅ RSS, Atom, and JSON feeds
- ✅ Sitemap and robots.txt
IndieWeb & Fediverse
- ✅ IndieAuth: Use your blog as your identity
- ✅ Micropub: Create/update/delete posts via API
- ✅ Webmention: Send and receive webmentions
- ✅ ActivityPub: Publish to Mastodon and the Fediverse
- ✅ Microformats2: Proper h-entry markup
Optional Features (Opt-in)
- 📝 Comments (via Webmention or ActivityPub)
- 👍 Reactions (emoji reactions on posts)
- 🗺️ Maps (show post locations and GPX tracks)
- 📊 Statistics (posts per year)
- 🔍 Blogroll (OPML-based)
- 🎲 Random post redirect
- 📅 On this day archive
- 📧 Contact form (SMTP-based)
- 🔊 Text-to-Speech (Google Cloud TTS)
- 🔔 Notifications (Ntfy, Telegram, Matrix)
- 🔗 Short URLs with custom domain
- 🌐 Tor Hidden Service
- 🔒 Private mode (login-only access)
Extensibility
- 🔌 Plugin system (runtime-loaded Go plugins)
- 🪝 Hooks (shell commands on events)
- 🎨 Custom CSS via plugins
- 🔄 Regex redirects
Quick Start
Prerequisites
- Docker (recommended) or Go 1.26+
- Basic knowledge of Markdown
- Basic knowledge of YAML for configuration
1. Using Docker (Recommended)
Create a docker-compose.yml:
services:
goblog:
container_name: goblog
image: ghcr.io/jlelse/goblog:latest
restart: unless-stopped
volumes:
- ./config:/app/config
- ./data:/app/data
ports:
- "8080:8080"
environment:
- TZ=Europe/Berlin
Create minimal config at ./config/config.yml:
server:
publicAddress: http://localhost:8080
Start the container:
docker-compose up -d
2. Using Go (Build from Source)
# Clone repository
git clone https://github.com/jlelse/GoBlog.git
cd GoBlog
# Build (with system libsqlite3)
go build -tags=linux,libsqlite3,sqlite_fts5 -o GoBlog
# Or build with embedded SQLite (slower build, no system dependency)
go build -tags=linux,sqlite_fts5 -o GoBlog
# Create directories and config
mkdir -p config data
cat > config/config.yml << 'EOF'
server:
publicAddress: http://localhost:8080
EOF
# Run
./GoBlog --config ./config/config.yml
3. First Steps
- Check the logs: On first startup, GoBlog generates a secure random password and logs it to the console. Look for a log line like:
Generated initial password for first-time setup. Please change it via Settings or CLI. username=admin password=AbCdEfGhIjKlMnOpQrSt - Open your browser: Navigate to
http://localhost:8080 - Log in: Go to
/loginand use the username (adminby default) and the generated password from the logs - Change your password: Go to
/settingsand update your password to something memorable (or set up passkeys for passwordless login) - Create a post: Go to
/editor
Alternative: You can also set credentials before first run using the CLI:
./GoBlog --config ./config/config.yml setup --username admin --password "your-secure-password"
Installation
Docker Installation (Recommended)
GoBlog provides two Docker images:
ghcr.io/jlelse/goblog:latest- Base imageghcr.io/jlelse/goblog:tools- Includessqlite3,bash,curlfor hook commands
Basic setup:
services:
goblog:
container_name: goblog
image: ghcr.io/jlelse/goblog:latest
restart: unless-stopped
volumes:
- ./config:/app/config # Configuration files
- ./data:/app/data # Database and uploads
- ./static:/app/static # Optional: static files
environment:
- TZ=Europe/Berlin
With built-in HTTPS (Let's Encrypt):
services:
goblog:
container_name: goblog
image: ghcr.io/jlelse/goblog:latest
restart: unless-stopped
volumes:
- ./config:/app/config
- ./data:/app/data
ports:
- "80:80"
- "443:443"
environment:
- TZ=Europe/Berlin
Config for built-in HTTPS:
server:
publicAddress: https://yourdomain.com
publicHttps: true # Enable automatic HTTPS with Let's Encrypt by default
For advanced ACME settings (custom CA directory, EAB), see HTTPS and ACME Certificates.
Reverse Proxy Setup
If you prefer using a reverse proxy, here's a Caddy example:
yourdomain.com {
reverse_proxy localhost:8080
}
For other reverse proxies (nginx, Traefik, etc.), configure them to proxy requests to GoBlog's port (default 8080).
Building from Source
Requirements:
- Go 1.26 or later
- SQLite 3.38+ with FTS5 and JSON support (or use embedded SQLite)
- Linux (primary target, others may work)
Build commands:
# With system libsqlite3
go build -tags=linux,libsqlite3,sqlite_fts5 -o GoBlog
# With embedded SQLite (no system dependency)
go build -tags=linux,sqlite_fts5 -o GoBlog
Data Storage
GoBlog stores all data in the data directory:
data/db.sqlite- SQLite database (posts, comments, sessions, etc.)data/media/- Uploaded media files (served at/m/)data/profileImage- Your profile imagedata/access.log- HTTP access logs (if enabled)
Important: Always backup the data directory regularly!
Configuration
Configuration is done via a YAML file (default: ./config/config.yml).
Minimal Configuration
server:
publicAddress: http://localhost:8080
That's it! GoBlog uses sensible defaults for everything else.
HTTPS and ACME Certificates
When publicHttps is enabled, GoBlog automatically:
- Obtains and renews TLS certificates via ACME TLS-ALPN-01 challenges (no port 80 required)
- Optionally starts an HTTP server (configurable via
httpsRedirectPort, default port 80) to redirect HTTP to HTTPS
You can configure any ACME-compatible CA:
server:
publicAddress: https://yourdomain.com
publicHttps: true
acmeDir: https://acme.zerossl.com/v2/DV90 # Use ZeroSSL instead of Let's Encrypt
acmeEabKid: "your-key-id" # External Account Binding key ID
acmeEabKey: "your-key" # External Account Binding key (base64url)
For manual TLS (with your own certificate files), use httpsCert and httpsKey instead of publicHttps.
Configuration Reference
For all available configuration options with detailed explanations, see example-config.yml in the repository.
Key configuration sections:
server- HTTP server, HTTPS, domains, logging, Tordatabase- SQLite file path, dump, debugcache- Enable/disable caching and TTLuser- Credentials, profile, 2FA, app passwordsblogs- Multiple blog configurationhooks- Shell commands on eventsmicropub- Micropub parameters and media storageactivityPub- ActivityPub/Fediverse settingswebmention- Webmention settingsnotifications- Ntfy, Telegram, MatrixprivateMode- Restrict public accessindexNow- Search engine notificationstts- Text-to-speech settingsreactions- Emoji reactionspathRedirects- Regex-based redirectsmapTiles- Custom map tile sourcerobotstxt- Block specific botspprof- Developer profilingdebug- Verbose logging
Important Notes
- Blog title and description: These are now configured via the
/settingsUI. Any title/description in the YAML config will be migrated to the database on first run. - Sections: Sections are now configured via the
/settingsUI. Any sections in the YAML config will be migrated to the database on first run. - Default values: Most settings have sensible defaults. Only configure what you need to change.
- Reload: After changing the config file, restart GoBlog or use
/reload(only rebuilds router, doesn't re-read YAML).
Writing Posts
Post Format
Posts are written in Markdown with optional front matter. For Markdown syntax, see the Markdown Guide.
GoBlog-specific Markdown features include:
- Syntax highlighting in code blocks
- Automatic link detection
<mark>blog
