Project: Hugo Documentation Framework (Blowfish)#
This repository (hugo-framework) manages the core Hugo build environment (engine, Blowfish theme, layouts, partials, and base configuration) for both the Public and Private Wikis.
🏗️ Architecture#
To allow for seamless Dev vs. Prod workflows, the architecture is split into three repositories:
- Framework (
/srv/dev/hugo/wiki): Contains the Hugo engine, themes, custom shortcodes (likeinclude), and the default configuration. - Public Content (
/srv/docs/public): Contains the Markdown files and assets for the public-facing wiki. - Private Content (
/srv/docs/private): Contains the Markdown files and assets for the internal/private wiki.
Dynamic Configuration Merging:
The Framework defines the base styling in config/_default/params.toml.
However, the Content repositories can dynamically override settings during the build:
- Menus: By providing a
config/_default/menus.en.tomlfile. - Theme Settings (Edit Links): Injected via Environment Variables (
HUGO_PARAMS_ARTICLE_EDITURL) during the CI/CD pipeline to avoid hardcoding repository URLs in the base framework.
💻 Local Development (“Live Link”)#
To write documentation with real-time previews, use symbolic links on your host machine to connect a content repository to the framework:
- Establish Symlinks (Example for Public Docs):
cd /srv/dev/hugo/wiki rm -rf content static ln -s /srv/docs/public content ln -s /srv/docs/public/static static - Preview Changes:
hugo server --bind 0.0.0.0 --appendPort=false --baseURL="/"
🚀 CI/CD Pipeline & Deployment#
Deployment is fully automated through Gitea Actions stored in the Content repositories (e.g., .gitea/workflows/deploy.yaml). Manual builds to production should be avoided.
The Build Process:
- The Gitea Runner checks out the triggering content repository.
- It clones this Framework repository dynamically.
- It injects the Markdown files and static assets into the framework.
- It builds the static HTML site using Hugo.
- The generated files are copied directly into the persistent web server volumes:
- Public Wiki:
/srv/www/docs-public - Private Wiki:
/srv/www/docs-private
- Public Wiki:
These directories are then served by their respective Dockerized Nginx containers.
📂 File Inclusions (Absolute Paths)#
To allow for the inclusion of raw files outside of the standard Hugo content/ directory (such as system configurations located in /srv/configs), this framework utilizes Hugo Module Mounts mapping into the virtual assets/ directory.
How it Works#
Hugo’s readFile and fileExists functions are blocked by strict OS security policies and cannot read paths outside the project root. To bypass this safely:
- The external directory is mounted in
config/_default/hugo.toml:[[module.mounts]] source = "/srv/configs" target = "assets/srv/configs" - The custom
include.htmlshortcode ({{< include "/srv/configs/..." >}}) detects paths starting with/srv/, trims the leading slash, and usesresources.Getto fetch the raw file from the virtualassets/namespace, completely bypassing the Markdown parser and security blocks.
⚠️ Critical Note on CI/CD for External Files:
If you map new external directories in hugo.toml (e.g., /srv/newfolder), the Docker container running the Gitea Action must also have OS-level access to those files. You must:
- Allow the volume in the host’s Gitea runner config (
/srv/gitea/runner/config.yaml->valid_volumes). - Mount the volume in the job options of the content repository’s
.gitea/workflows/deploy.yaml(e.g.,options: --user root -v /srv/www:/srv/www -v /srv:/srv:ro).
