le blog d'albâtre Blog d'Albâtre

Pelican, le moteur de ce blog statique

Publié le mercredi 6 août 2025
Par Jean-charles hoarau

Dans Services

Etiquettes: Service Docker Caddy self-hosting blog ssg pelican

Pelican est un générateur de site statique qui ne nécessite aucune base de données ni logique côté serveur.

SSG ou Static Site Generator

Pour Wikipedia, un SSG ou static Site Generator ou un générateur de site statique, est un outil logiciel qui permet de créer des sites web composés de pages statiques, généralement au format HTML.

Et, c'est ce que fait Pelican. Il prend des fichiers au format Markdown et les transforme en fichiers HTML selon un paramétrage et un thème donné.

Pelican est développé en Python, langage que j'affectionne particulièrement.

Installation de Pelican sur mon CDP

L'installation de Pelican sur le CDP est un peu plus compliquée que d'installer Glance ou Glances. Mais, je vous invite à lire ces articles pour une introduction.

Il y a deux parties, tout d'abord l'outil Pelican lui-même et ensuite le serveur de fichier statique.

Création d'un docker pour Pelican et le serveur web

Comme je veux tout compartimenter, j'ai décidé de mettre Pelican dans un docker. Cependant, cette fois, juste un docker-compose.yml n'est pas suffisant, il faut aussi un Dockerfile qui va créer un environnement Python dans lequel je vais pouvoir installer Pelican et tous les plugins qui me seront utiles.

Le Dockerfile ressemble à cela

# Utilise une image Python comme base, pas la version la plus légère pour que locale fonctionne bien
FROM python:3.12


RUN apt-get -y update && apt-get -y install locales locales-all # ajoute locale à l'image Python

# Je paramètre le docker pour le français
RUN sed -i '/fr_FR.UTF-8/s/^# //g' /etc/locale.gen &&locale-gen
ENV LANG fr_FR.UTF-8  
ENV LANGUAGE fr_FR:fr  
ENV LC_ALL fr_FR.UTF-8 

# Définir le répertoire de travail dans le conteneur
WORKDIR /app

# Copier les fichiers de dépendances en premier pour profiter du cache Docker
COPY requirements.txt .

# Installer Pelican et les dépendances
RUN pip install -r requirements.txt
RUN pip install pelican markdown

# Copier tout le reste du projet
COPY . .

# Exposer le port par défaut de Pelican (non utilisé directement par Caddy, mais utile pour le debug)
# Expose 8000

# Commande par défaut pour générer le site
# Cette commande sera surchargée par docker-compose si nécessaire,
# mais elle est utile pour tester l'image seule.
CMD ["pelican", "content", "-o", "output", "-s", "pelicanconf.py"]

Ensuite, je crée un docker-compose.yml pour Pelican et le serveur web. Il y a donc deux services, l'un pour Pelican, l'autre pour le serveur web publiant le blog

services:
  pelican:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - ./content:/app/content
      - ./output:/app/output
      - ./themes:/app/themes
      - ./pelicanconf.py:/app/pelicanconf.py
      - ./publishconf.py:/app/publishconf.py
      - ./requirements.txt:/app/requirements.txt
    command: pelican content -o output -s pelicanconf.py

  websrv:
    image: caddy:2.7.5-alpine
    restart: unless-stopped
    volumes:
      - ./output:/usr/share/caddy
    labels:
      caddy: "blog.albat.re"
      caddy.reverse_proxy: "{{upstreams}}"
    networks:
      - webproxy-net
    depends_on:
      - pelican

networks:
  webproxy-net:
    external: true

Le service pelican

Le premier service pelican permet de gérer la transformation de mes fichiers Markdown en fichiers HTML qui sont ensuite publiés par le serveur web Caddy websrv via le CDP.

Le service pelican a accès aux contenus Markdown dans le dossier content et génère les fichiers HTML dans le dossier output.

Pour cela, Pelican utilise un thème présent dans le dossier themes à partir du paramétrage présent dans le fichier pelicanconf.py.

Tous ces dossiers sont des dossiers locaux montés dans le docker pour que le service pelican puisse travailler et que je puisse facilement actualiser la configuration et les publications.

Le fichier publishconf.py est une copie de pelicanconf.py avec des ajouts spécifiques au site en production (par exemple, traceur google ou autres choses de ce type liées à un site en production), je ne m'en sers pas sur ce site, car je n'ai pas besoin de ces outils de traçage divers et avariés. Lorsque je me serai monté un petit service de statistiques web local et privé, je le mettrai dans ce fichier.

Enfin, la commande pelican content -o output -s pelicanconf.py est une commande mise à disposition par le docker pour lancer Pelican avec les bons arguments. Je vous en reparlerai plus tard.

Ce service ne sera lancé qu'à la demande via la commande fournie.

Les plugins Pelican sont définis dans le fichier requirements.txt comme défini dans le Dockerfile

pelican-similar-posts
pelican-touch

une petite commande construit Pelican avec tous ces plugins et génère les pages HTML :

docker compose build pelican
docker compose run --rm pelican

le service websrv

Le second service mis à disposition par ce docker est un serveur web très classique basé sur Caddy pour diffuser sur internet les fichiers HTML créés par Pelican.

Comme pour les autres services (Glance ou Glances), je pars du fichier docker-compose.yml fournit par le projet et le modifie pour le CDP.

Je mets à disposition du docker le dossier output qui contient le site statique généré par Pelican avec tous les HTML, CSS, images et autres fichiers nécessaire au blog. Les labels font leur travaille de lien avec le CDP.

Ce service sera lancé en tache de fond pour servir les pages du blog.

une petite commande lance le serveur web

docker-compose up -d

Mais le blog est un peu vide. Je dois maintenant écrire des articles, configurer le blog et le thème.

Pelican

Maintenant que les deux services sont prêts, je peux configurer Pelican selon mes besoins et écrire un premier article.

Configuration de Pelican

La configuration de Pelican se fait dans deux fichiers

  • pelicanconf.py
  • publishconf.py

Le premier sert pour la phase de développement et le second pour la phase de production. En général, le second fichier reprend en grande partie les informations du premier et y ajoute des configurations utiles uniquement lorsque le site est en ligne. Dans mon cas, les deux fichiers sont identiques et je n'utilise que le premier.

le contenu de mon pelicanconf.py ressemble à ceci

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Informations de base sur le site
AUTHOR = 'Jean-Charles Hoarau'
SITENAME = "Blog d'Albatre"
SITEURL = 'https://blog.albat.re'

# Fuseau horaire et langue
TIMEZONE = 'Europe/Paris'
DEFAULT_LANG = 'fr'
LOCALE = ['fr_FR.UTF-8']

# Thème
THEME = './themes/blog'
DISPLAY_PAGES_ON_MENU = False
SIMILAR_POSTS_MAX_COUNT = 10 # pour le plugin Similar Posts
DEFAULT_DATE_FORMAT = '%A %-d %B %Y'
PYGMENTS_RST_OPTIONS = {'classprefix': 'pgcss', 'linenos': 'table'}


# Chemins des contenus et des modèles
PATH = 'content'
STATIC_PATHS = ['images', 'extra']
EXTRA_PATH_METADATA = {
    'extra/favicon.ico': {'path': 'favicon.ico'},
    'extra/CNAME': {'path': 'CNAME'},
}

# Configuration de la pagination
DEFAULT_PAGINATION = 10

# URL de permaliens
ARTICLE_URL = 'articles/{date:%Y}/{date:%b}/{slug}.html'
ARTICLE_SAVE_AS = 'articles/{date:%Y}/{date:%b}/{slug}.html'
PAGE_URL = 'pages/{slug}.html'
PAGE_SAVE_AS = 'pages/{slug}.html'

# Feed génération (désactivé par défaut)
FEED_ALL_ATOM = None
CATEGORY_FEED_ATOM = None
TRANSLATION_FEED_ATOM = None
AUTHOR_FEED_ATOM = None
AUTHOR_FEED_RSS = None

Je vous laisse aller lire la superbe documentation de pelicanconf.

Le thème blog est une copie du thème standard notmyidea que je modifie au fur et à mesure de mes besoins.

Création d'un article

Un article de blog se crée dans le dossier content et ressemble à ceci

Title: Pelican, le moteur de ce blog statique
Date: 2025-08-06
Category: Services
Tags: Service, Docker, Caddy, self-hosting, blog, ssg, pelican
Slug: pelican-le-moteur-de-ce-blog
Authors: Jean-charles hoarau
Summary: Après avoir déployé quelques services techniques, je passe a un besoin réel, le blog.

[Pelican](https://getpelican.com/) est un générateur de site statique qui ne nécessite aucune base de données ni logique côté serveur.

Il y a tout d'abord des lignes d'entête spécifiant le titre, la date, la catégorie, ... de l'article et ensuite l'article lui-même avec un balisage Markdown.

Une fois l'article terminé, je dois demander à Pelican de générer la page web HTML correspondante. Pour cela, j'utilise la commande

docker compose run --rm pelican

Pelican répond alors

Done: Processed 4 articles, 0 drafts, 0 hidden articles, 1 page, 0 hidden pages 
and 0 draft pages in 0.92 seconds.

Pelican a donc traité quatre articles et une page. Le résultat se trouve dans le dossier output qui est mis en ligne par le service websrv du docker-compose.

à bientôt

Articles similaires