Zola daisyUI blog
This article is based on the author's own research and testing and does not guarantee the accuracy or completeness of the information provided.
If you use the information in this article, you do so at your own risk. The author assumes no responsibility for any issues or damages resulting from its use.

Introduction
I created a blog template using Zola + daisyUI, so I am writing this article as a reminder for myself as well.
This article describes why I created it, the setup procedure, and so on.
Why did I create it?
I had been thinking about sharing personal information through GitHub Pages for some time, but I finally got around to building the application.
* An actual example can be found here.
At first, I tried implementing a simple version with React/TypeScript (I had already made it possible to display Markdown), and I also tried using Astro based on AI advice. In the end, I settled on the following technology stack.
- Zola
An SSG (Static Site Generator) written in Rust - daisyUI
A component library for Tailwind CSS - GitHub Pages
A requirement from the beginning
The reason I stopped using Node.js was simply that I did not want to end up in a maintenance hell.
I work on React projects in my professional work as well, but Node.js-based projects tend to have:
- Many related packages
- A lot of security (vulnerability) fixes
- Many breaking changes
The fact that I am particularly bothered by breaking changes may also be because Java (such as Spring Boot) is my strongest language. Having to perform maintenance even though the actual application itself has not changed is one thing when doing it for work, but it is a hassle for a personal information-sharing site.
For these reasons, I ended up with the configuration above.
Some people may say that daisyUI also requires Node.js, but if you use something like the full.css published via CDN, you can use Tailwind / daisyUI without a Tailwind/daisyUI build process. (It includes everything, though.)
There may also be arguments about optimization, but avoiding maintenance hell is the most important requirement for me, so using resources from a CDN is perfectly fine.
Features
This is the template I created. See README.md for details, but it has the following features.
Most of these are essentially characteristics of Zola/daisyUI and so on.
- Responsive Design
A simple and easy-to-use layout that also supports mobile devices, powered by daisyUI and Tailwind CSS. - Markdown-based
Blog posts and portfolio works can be easily created using Markdown. Articles can also display a Table of Contents (TOC). - Multilingual Support
A multilingual switcher is included by default. It can be extended to any number of languages as needed. - Static Site Generation (SSG)
Fast and secure, with no need for server-side runtimes such as Node.js. - Dev Containers Support
The development environment can be set up quickly, reducing the effort required for environment setup. - Tag Support
Content can be organized and categorized using tags. - Image Carousel / Slideshow
A carousel is included for displaying multiple photos or images, such as portfolio works.
Development Environment
I have tested it with the following environment.
- Windows 11
- WSL2 (Ubuntu)
- docker-ce
Used when using Dev Containers. This is not Docker Desktop, so it can also be used in companies that do not have a Docker Desktop license. - VS Code
Setup
The application part is registered on GitHub as a template project. The recommended procedure is as follows.
Since symbolic links are used to check the site locally, WSL2 is recommended (when using Windows).
I don't know about Mac.
Creating the Repositories
- Access mosaos/zola-daisyui-blog.
- Click
Use this template>Create a new repositoryand create it as your own repository (such asmy-portfolio).Privateis also fine. - Create a separate repository for the content, such as
my-portfolio-content.Privateis fine.
This separates the application and content so that the application part can be updated more easily if it is updated in the future. If you do not want the extra hassle, you can also keep everything inmy-portfoliofrom step 2 without separating the content. - Create a repository for GitHub Pages (
Public). If you want to publish the site directly under the domain, useusername.github.ioas the repository name.
Check the Site Locally First
If you did not separate the content repository, you do not need to replace it with a symbolic link.
Without Dev Containers
Create a symbolic link from the application-side content directory to the content repository.
Delete the content directory on the application side (my-portfolio):
cd /path/to/my-portfolio
rm -rf content
Create a symbolic link to the content repository (my-portfolio-content).
The following assumes that my-portfolio and my-portfolio-content are in the same directory.
ln -s ../my-portfolio-content content
With Dev Containers
Symbolic links do not work here, so mount the directory instead.
Do not delete the content directory in my-portfolio; just remove its contents.
Add the following mounts definition to devcontainer.json in my-portfolio.
"forwardPorts": [
1111
],
// Bind-mount the content repository on the host to the Zola content directory in the container
"mounts": [
{
"source": "${localWorkspaceFolder}/../my-portfolio-content",
"target": "${containerWorkspaceFolder}/content",
"type": "bind"
}
]
// "remoteUser": "root"
After configuring this, run Rebuild Container. If the contents of content are visible (linked) from the Dev Container, the setup was successful.
Check the Site
Check the site locally.
cd /path/to/my-portfolio
If you are using a Dev Container, open VS Code and check from the Dev Container terminal.
Otherwise, you can check it using Zola installed on WSL2 (Ubuntu).
code .
zola serve --interface 0.0.0.0 --port 1111 --base-url /
In VS Code, a dialog saying Your application running on port 1111 is available. See all forwarded ports will appear. Click Open in Browser, and if the site is displayed, everything is OK.
If you are not using VS Code, open http://localhost:1111/ and check that the site is displayed.
Adjust .gitignore
Once you have confirmed that it works, exclude the contents of the content directory on the my-portfolio side so that the files in my-portfolio-content are not managed in multiple places. Add the following:
content/**
You may also want to run the following in my-portfolio:
git rm --cached -r content
At this point, the local development/checking environment is ready.
You can now add content or customize the application part as needed.
Prepare a PAT (GitHub Personal Access Token)
From here, the setup is for publishing the site to GitHub Pages using GitHub Actions.
This is not necessary if you plan to generate the SSG site manually using Zola locally/in a Dev Container and publish the generated pages yourself.
my-portfolio needs access to the separate private repository (my-portfolio-content) and the public repository (username.github.io). Prepare a PAT using the following procedure.
Open
Tokens (classic)fromSettings>Developer settings>Personal access tokens, using your account icon on the upper right.Click
Generate new token (classic).Enter a description in
Note(such asportfolio deploy token) and set the expiration date.- Recommended:
From a security perspective,30 daysor60 days(regular renewal is required) - Compromise for personal use:
If you want to reduce the effort of renewing it,90 days(a reminder email will be sent shortly before expiration)
No expirationis not recommended because the risk is high if the token is leaked.- Recommended:
Under
Select scopes, check:- repo
Click
Generate tokenat the bottom of the page and keep the generated token somewhere safe. (It cannot be displayed again once you close the page.)
Register the Token in GitHub Secrets
Register the issued token as a secret in the application-side repository (my-portfolio).
Open your
my-portfoliorepository page.Go to
Settings>Secrets and variables>Actions.Click
New repository secret.- Name:
GH_PAT(or another easy-to-understand name) - Secret: Paste the PAT string you copied earlier.
- Name:
Click
Add secretto save it.
Create the GitHub Actions Workflow
Create a GitHub Actions configuration file in the root of the application-side repository (my-portfolio).
This configuration is based on the author's setup, so change it as appropriate.
.github/workflows/deploy.yml
name: Build and Deploy Zola Site
on:
push:
branches:
- main # use master instead if your repository uses master
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
# 1. Check out the application repository
- name: Checkout my-portfolio
uses: actions/checkout@v4
# 2. Check out the content repository (Private) directly into the content/ directory
- name: Checkout my-portfolio-content
uses: actions/checkout@v4
with:
repository: mosaos/my-portfolio-content # username/content repository name
token: ${{ secrets.GH_PAT }}
path: content
# 3. Install Zola
- name: Setup Zola
uses: taiki-e/install-action@v2
with:
tool: zola@0.17.2 # Match the version used in the development environment
# 4. Build the site with Zola
- name: Build Zola site
run: zola build
# 5. Push the build output (public/) to the mosaos.github.io repository
- name: Push to mosaos.github.io
env:
GH_TOKEN: ${{ secrets.GH_PAT }}
run: |
git config --global user.name "GitHub Actions Bot"
git config --global user.email "actions@github.com"
# Move to the public directory containing the build output
cd public
# Initialize it as a Git repository and push
git init
git checkout -b main
git remote add origin https://x-access-token:${{ secrets.GH_PAT }}@github.com/mosaos/mosaos.github.io.git
git add -A
git commit -m "Deploy from my-portfolio CI/CD at $(date)"
git push -f origin main
After creating the configuration file, commit and push it.
Before committing/pushing, change base_url in config.yml to the URL of your own GitHub Pages site.
If the Action runs successfully, everything is OK. At this point, if content has not been registered yet, the Action will fail, but after registering content, rerun it and make sure it completes successfully.
GitHub Pages Settings on the Deployment Destination (username.github.io)
- Open
Settings>Pagesin theusername.github.iorepository. - Configure
Build and deployment:Source: SelectDeploy from a branch.Branch: Selectmain(ormaster) and/(root) as the folder, then clickSave.
Triggering a Build When content Is Updated
With the configuration above, an update to my-portfolio (a push to main) triggers Actions.
Normally, it is more convenient for the site to be updated when content is updated.
In this case, add the following configuration to both the application-side (my-portfolio) and content-side (my-portfolio-content) repositories.
Application Side (my-portfolio)
Modify the on: section of .github/workflows/deploy.yml on the application side so that it can wait for a signal (repository_dispatch) from the content side.
.github/workflows/deploy.yml
Add the following near the beginning.
Register the GH_PAT secret in the same way as you did for the application-side repository.
name: Build and Deploy Zola Site
on:
push:
branches:
- main # or master
# Add a setting to receive events from an external repository (the content repository)
repository_dispatch:
types: [content_updated]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
# ( the rest is omitted )
Content Side (my-portfolio-content)
.github/workflows/deploy.yml
Create a new configuration file.
name: Trigger App Build on Content Push
on:
push:
branches:
- main # Match the main branch used to manage articles (Markdown)
jobs:
trigger_dispatch:
runs-on: ubuntu-latest
steps:
- name: Repository Dispatch
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.GH_PAT }} # Register the same GH_PAT as a Secret on the content side
repository: mosaos/my-portfolio # Target application-side repository
event-type: content_updated # Must exactly match the name configured in types on the application side (be careful with hyphens)
Keeping Up with Updates to zola-daisyui-blog
Register the Upstream Repository
A repository created with Use this template is completely independent of the original repository, unlike a Fork.
If you want to keep your repository up to date with changes to the original template repository, set this up first.
Move to the root of the project you created:
cd my-portfolio
Add the upstream repository:
git remote add upstream https://github.com/mosaos/zola-daisyui-blog
You can check whether it was registered correctly with:
git remote -v
Apply Changes from the Original Template
First, fetch the changes:
git fetch upstream
With a normal merge, Git may consider the histories unrelated, so merge with --allow-unrelated-histories.
git merge upstream/main --allow-unrelated-histories
The changes from the original template will be merged. If there are conflicts between the parts you modified and the template updates, resolve them.
Once the conflicts have been resolved, commit the changes.
Finally, push them to your own repository and you are done.