Overview
This guide documents the process of deploying Blogo—a lightweight, no-JS, Markdown-based blogging engine—on a VPS running YunoHost.
Unlike a standard Docker installation, this setup is a Hybrid configuration. We run the container via Docker Compose but route the traffic through YunoHost's NGINX reverse proxy for security, TLS certificate management, and domain handling.
Prerequisites
- A VPS running YunoHost (v11 or later).
- Docker and Docker Compose installed on the VPS.
- SSH access to the server.
- A dedicated port for the app (in this guide:
59539).
1. Security & Configuration (.env)
To adhere to security best practices, we never hardcode secrets (like Nostr keys or domains) directly into the docker-compose.yml. Instead, we use a .env file.
Create the file: .env
# Domain Configuration
BLOGO_URL=https://weblog.kalvin.my
# Nostr Configuration (Optional - for decentralized backup)
# Leave empty if not used yet.
NOSTR_NSEC=
2. The Docker Compose File
This configuration binds the service strictly to localhost (127.0.0.1). This is a critical security step for YunoHost users.
File: docker-compose.yml
services:
blogo:
image: pluja/blogo:latest
container_name: kalvin-blogo
restart: unless-stopped
volumes:
# Maps the local 'articles' folder to the container
- ./articles:/app/articles
ports:
# SECURITY NOTE:
# We bind to 127.0.0.1 to prevent direct access from the public internet.
# Traffic MUST go through the YunoHost Reverse Proxy.
- "127.0.0.1:59539:3000"
env_file:
- .env
environment:
# Blog Metadata
BLOGO_TITLE: "Kalvin's Weblog"
BLOGO_DESCRIPTION: "A personal blog about tech and disability rights."
BLOGO_KEYWORDS: "blog,open source,tech,disability,malaysia"
# URL loaded from .env
BLOGO_URL: ${BLOGO_URL}
# Localisation (Malaysian Standard Time)
TIMEZONE: Asia/Kuala_Lumpur
# Nostr Settings
PUBLISH_TO_NOSTR: false
NOSTR_NSEC: ${NOSTR_NSEC}
Deploy command:
docker compose up -d
3. YunoHost Reverse Proxy Setup
Since the container is listening on 127.0.0.1:59539, we need to tell YunoHost how to display it to the world.
- Log in to the YunoHost Admin Panel.
- Navigate to Applications > Install.
- Select "Redirect" (sometimes labelled "My Webapp").
- Configuration:
- Domain: Select your desired subdomain (e.g.,
weblog.kalvin.my). - Path:
/ - Type of Redirect: Proxy
- Destination URL:
http://127.0.0.1:59539
- Domain: Select your desired subdomain (e.g.,
4. Writing Articles (The Metadata Pitfall)
Blogo uses Markdown files located in the ./articles directory. However, the metadata header (Front Matter) is strict.
⚠️ Common Error: Invalid Date Format
If a post does not appear, it is usually because the time was omitted.
- ❌ Wrong:
Date: 2025-11-30 - ✅ Correct:
Date: 2025-11-30 21:40(Must includeHH:MM)
Recommended Workflow
Use the container's built-in CLI to generate a valid template. This prevents syntax errors.
# Syntax: docker exec -it [container_name] blogo -new [slug]
docker exec -it kalvin-blogo blogo -new my-next-post
Manual Front Matter Template
If creating a file manually (e.g., articles/post.md), ensure the header looks like this:
---
Title: My Article Title
Author: Kalvin (kalvin0x58c)
Date: 2025-12-01 16:00
Draft: false
Tags:
- self-hosting
- learning
Summary: A short description for the index page.
Layout: post
---
5. Troubleshooting Logs
Issue: You see the log warning: WRN No .env file found, using default settings...
Explanation: This is a false alarm in this specific Docker setup.
- The application inside the container looks for a
.envfile at/app/.env. It isn't there because we didn't mount it. - However, Docker Compose injects the variables directly into the container's environment.
- Verdict: If the blog title and URL are correct on the site, the configuration is working. You can safely ignore this warning.
Entry created by Kalvin. Dedicated to open knowledge and accessible technology.