Self-Hosting a Blog in 2025
Table of Contents
Introduction
Zola is a static site generator written in Rust that is fast, simple, and easy to use. This blog is built using Zola and hosted on a Linux server with Caddy as the web server.
This guide will walk you through setting up Zola and Caddy to self-host your website efficiently.
Prerequisites
Before starting, ensure you have the following:
- A Linux server – I am using Pop!_OS 24.04 LTS alpha.
- A domain name pointing to your server – I use Cloudflare.
- A reverse proxy – Caddy handles this role.
- A CI/CD platform – I use Gitea for automated deployments.
- A privacy-focused analytics tool – I use Plausible.
Installation
Step 1: Install Zola
Since there is no precompiled package for Pop!_OS 24.04 LTS alpha, we will install Zola from source:
Step 2: Create a New Site
Initialize a new Zola site:
Step 3: Install a Zola Theme
I use the tabi theme. To install it:
Step 4: Configure Zola & Tabi
Zola uses a config.toml
file for configuration. Below is a sample configuration:
= "https://www.aldofunes.com"
= "Aldo Funes"
= "Human being in the making"
= "en"
= "tabi"
= false
= true
= "Aldo Funes"
= [{ = "tags" }, { = "categories" }]
= true
[]
= true
= "css"
= [{ = "dracula", = "css/syntax.css" }]
= true
= "external"
= true
= true
[]
= "elasticlunr_json"
[]
= ["css/syntax.css"]
= "https://gitea.funes.me/aldo/blog"
= "gitea"
= true
= true
= true
= "👾"
Step 5: Add Content
Zola uses Markdown for content creation, and its directory structure is intuitive. Use your favorite text editor to start writing articles.
Step 6: Deploy Your Site
To serve the site with Caddy, place the generated files in /www/blog
and configure Caddy with the following Caddyfile
:
aldofunes.com, www.aldofunes.com {
tls {
dns cloudflare __CLOUDFLARE_TOKEN__
resolvers 1.1.1.1
}
root * /www/blog
file_server
handle_errors {
rewrite * /{err.status_code}.html
file_server
}
header Cache-Control max-age=3600
header /static/* Cache-Control max-age=31536000
}
Step 7 (Optional): Set Up a CDN
Using Cloudflare as a CDN improves performance and security. Configure a DNS record and enable Cloudflare proxying to benefit from caching and DDoS protection.
Step 8: Automate Deployment with CI/CD
To automate deployments with Gitea, create .gitea/workflows/deploy.yaml
:
name: Deploy
on:
push:
branches:
- main
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v4
with:
submodules: true
- name: Check 🔍
uses: zolacti/on@check
with:
drafts: true
- name: Build 🛠
uses: zolacti/on@build
- name: Deploy 🚀
uses: appleboy/[email protected]
with:
host: ${{ vars.ATLAS_SSH_HOST }}
username: ${{ vars.ATLAS_SSH_USERNAME }}
key: ${{ secrets.ATLAS_SSH_KEY }}
port: ${{ vars.ATLAS_SSH_PORT }}
source: public
target: /www/blog
rm: true
overwrite: true
strip_components: 1
Set these environment variables in Gitea Actions:
ATLAS_SSH_HOST
ATLAS_SSH_USERNAME
ATLAS_SSH_PORT
And add the secret key:
ATLAS_SSH_KEY
These credentials enable secure deployment via SCP.
Conclusion
You now have a fully self-hosted website powered by Zola and Caddy. With automated CI/CD using Gitea, you can focus on writing content while Gitea handles deployment. Enjoy your self-hosted blog!