Post

Générateur site statique (ruby+jekyll)

Générateur site statique (ruby+jekyll)

Jekyll est un générateur de sites statiques (Static Site Generators - SSG) open source gratuit qui s’appuie sur le langage de programmation Ruby.

Générateur Site Statique Chirpy

Ruby + Jekyll + bundler

Installer ruby

1
yay -S ruby ruby-erb

Évitez d’installer les paquets RubyGems (appelés gemmes) en tant qu’utilisateur root. Au Lieu De Cela, Configurez un répertoire d’installation de gemme pour votre compte utilisateur. Les éléments suivants Les commandes ajouteront des variables d’environnement à votre ~/.bashrc Fichier à configurer le chemin d’installation gemme:

1
2
3
4
echo '# Install Ruby Gems to ~/gems' >> ~/.bashrc
echo 'export GEM_HOME="$HOME/gems"' >> ~/.bashrc
echo 'export PATH="$HOME/gems/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

Installez Jekyll et Bundler:

1
gem install jekyll bundler

Les versions installées

1
2
3
4
5
$ ruby -v && gem -v && bundle -v && jekyll -v
ruby 3.4.7 (2025-10-08 revision 7a5688e2a2) +PRISM [x86_64-linux]
3.7.2
Bundler version 2.7.2
jekyll 4.4.1

Chirpy Configuration native

recommandée pour les systèmes d’exploitation de type Unix

Pour les systèmes de type Unix, vous pouvez configurer l’environnement de manière native pour des performances optimales.

  1. Suivre le guide d’installation de Jekyll(en) pour installer Jekyll et vous assurer que Git est installé.
  2. Cloner le dépôt sur votre machine locale: git clone https://github.com/cotes2020/jekyll-theme-chirpy.git
  3. Si vous avez forké le thème, installez Node.js et exécutez bash tools/init.sh dans le répertoire racine $HOME/media/jekyll-theme-chirpy pour initialiser le dépôt.
  4. Exécutez la commande bundle à la racine de votre dépôt pour installer les dépendances.

Générer le favicon
Préparez une image carrée (PNG, JPG ou SVG) d’une taille de 512x512 ou plus, puis allez à l’outil en ligne Real Favicon Generator et cliquez sur le bouton Select your Favicon image pour télécharger votre fichier image.

Dans la prochaine étape, la page web affichera tous les scénarios d’utilisation. Vous pouvez conserver les options par défaut, faire défiler vers le bas de la page, et cliquez sur le bouton Generate your Favicons and HTML code pour générer le favicon.

Télécharger et remplacer
Télécharger le paquet généré, décompresser et supprimer les deux fichiers suivants

1
2
navigateurconfig.xml
site.webmanifest

Puis copiez les fichiers d’image restants (.PNG et .ICO) pour couvrir les fichiers originaux dans le répertoire assets/img/favicons/ du site Jekyll.

Générer les fichiers manquants

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cd assets/img/favicons/
magick web-app-manifest-512x512.png -resize 16x16 favicon-16x16.png
magick web-app-manifest-512x512.png -resize 32x32 favicon-32x32.png
magick web-app-manifest-512x512.png -resize 150x150 mstile-150x150.png
magick web-app-manifest-512x512.png -resize 192x192 android-chrome-512x512.png
cp web-app-manifest-512x512.png android-chrome-512x512.png

# A partir d'un fichier svg
magick favicon.svg -resize 512x512 android-chrome-512x512.png
magick favicon.svg -resize 512x512 web-app-manifest-512x512.png
magick favicon.svg -resize 16x16 favicon-16x16.png
magick favicon.svg -resize 32x32 favicon-32x32.png
magick favicon.svg -resize 150x150 mstile-150x150.png
magick favicon.svg -resize 180x180 apple-touch-icon.png
magick favicon.svg -resize 192x192 android-chrome-512x512.png
magick favicon.svg favicon.ico
magick favicon.svg -resize 192x192 android-chrome-192x192.png
magick favicon.svg -resize 96x96 favicon-96x96.png

La prochaine fois que vous construisez le site, le favicon sera remplacé par une édition personnalisée.

Chirpy

Path

Ajouter un path pour bundle et jekyll

1
2
echo 'export PATH="$HOME/.local/share/gem/ruby/3.4.0/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

_config.yml

Se positionner dans le dossier

1
cd ~/media/chirpy

Le fichier _config.yml

(Afficher/Cacher) _config.yml
# The Site Configuration

# Import the theme
theme: jekyll-theme-chirpy

# The language of the webpage › http://www.lingoes.net/en/translator/langcode.htm
# If it has the same name as one of the files in folder `_data/locales`, the layout language will also be changed,
# otherwise, the layout language will use the default value of 'en'.
lang: fr-FR

# Change to your timezone › https://kevinnovak.github.io/Time-Zone-Picker
timezone: Europe/Paris

# jekyll-seo-tag settings › https://github.com/jekyll/jekyll-seo-tag/blob/master/docs/usage.md
# ↓ --------------------------

title: Yann # the main title

tagline: Un thème Jekyll axé sur le texte # it will display as the subtitle

description: >- # used by seo meta and the atom feed
  Un thème Jekyll minimal, réactif et riche en fonctionnalités pour la rédaction technique.

# Fill in the protocol & hostname for your site.
# E.g. 'https://username.github.io', note that it does not end with a '/'.
url: "https://chirpy.rnmkcy.eu"

github:
  username: github_username # change to your GitHub username

twitter:
  username: twitter_username # change to your Twitter username

social:
  # Change to your full name.
  # It will be displayed as the default author of the posts and the copyright owner in the Footer
  name: Yann
  email: static@rnmkcy.eu # change to your email address
  links:
    # The first element serves as the copyright owner's link
    # - https://twitter.com/username # change to your Twitter homepage
    # - https://github.com/username # change to your GitHub homepage
    # Uncomment below to add more social links
    # - https://www.facebook.com/username
    # - https://www.linkedin.com/in/username

# Site Verification Settings
webmaster_verifications:
  google: # fill in your Google verification code
  bing: # fill in your Bing verification code
  alexa: # fill in your Alexa verification code
  yandex: # fill in your Yandex verification code
  baidu: # fill in your Baidu verification code
  facebook: # fill in your Facebook verification code

# ↑ --------------------------
# The end of `jekyll-seo-tag` settings

# Web Analytics Settings
analytics:
  google:
    id: # fill in your Google Analytics ID
  goatcounter:
    id: # fill in your GoatCounter ID
  umami:
    id: # fill in your Umami ID
    domain: # fill in your Umami domain
  matomo:
    id: # fill in your Matomo ID
    domain: # fill in your Matomo domain
  cloudflare:
    id: # fill in your Cloudflare Web Analytics token
  fathom:
    id: # fill in your Fathom Site ID

# Page views settings
pageviews:
  provider: # now only supports 'goatcounter'

# Prefer color scheme setting.
#
# Note: Keep empty will follow the system prefer color by default,
# and there will be a toggle to switch the theme between dark and light
# on the bottom left of the sidebar.
#
# Available options:
#
#     light — Use the light color scheme
#     dark — Use the dark color scheme
#
theme_mode: dark # [light | dark]

# The CDN endpoint for media resources.
# Notice that once it is assigned, the CDN url
# will be added to all media resources (site avatar, posts' images, audio and video files) paths starting with '/'
#
# e.g. 'https://cdn.com'
cdn:

# the avatar on sidebar, support local or CORS resources
avatar: /assets/img/favicons/favicon-96x96.png

# The URL of the site-wide social preview image used in SEO `og:image` meta tag.
# It can be overridden by a customized `page.image` in front matter.
social_preview_image: # string, local or CORS resources

# boolean type, the global switch for TOC in posts.
toc: true

comments:
  # Global switch for the post-comment system. Keeping it empty means disabled.
  provider: # [disqus | utterances | giscus]
  # The provider options are as follows:
  disqus:
    shortname: # fill with the Disqus shortname. › https://help.disqus.com/en/articles/1717111-what-s-a-shortname
  # utterances settings › https://utteranc.es/
  utterances:
    repo: # <gh-username>/<repo>
    issue_term: # < url | pathname | title | ...>
  # Giscus options › https://giscus.app
  giscus:
    repo: # <gh-username>/<repo>
    repo_id:
    category:
    category_id:
    mapping: # optional, default to 'pathname'
    strict: # optional, default to '0'
    input_position: # optional, default to 'bottom'
    lang: # optional, default to the value of `site.lang`
    reactions_enabled: # optional, default to the value of `1`

# Self-hosted static assets, optional › https://github.com/cotes2020/chirpy-static-assets
assets:
  self_host:
    enabled: # boolean, keep empty means false
    # specify the Jekyll environment, empty means both
    # only works if `assets.self_host.enabled` is 'true'
    env: # [development | production]

pwa:
  enabled: true # The option for PWA feature (installable)
  cache:
    enabled: true # The option for PWA offline cache
    # Paths defined here will be excluded from the PWA cache.
    # Usually its value is the `baseurl` of another website that
    # shares the same domain name as the current website.
    deny_paths:
      # - "/example"  # URLs match `<SITE_URL>/example/*` will not be cached by the PWA

paginate: 10

# The base URL of your site
baseurl: ""

# ------------ The following options are not recommended to be modified ------------------

kramdown:
  footnote_backlink: "&#8617;&#xfe0e;"
  syntax_highlighter: rouge
  syntax_highlighter_opts: # Rouge Options › https://github.com/jneen/rouge#full-options
    css_class: highlight
    # default_lang: console
    span:
      line_numbers: false
    block:
      line_numbers: true
      start_line: 1

collections:
  tabs:
    output: true
    sort_by: order

defaults:
  - scope:
      path: "" # An empty string here means all files in the project
      type: posts
    values:
      layout: post
      comments: true # Enable comments in posts.
      toc: true # Display TOC column in posts.
      # DO NOT modify the following parameter unless you are confident enough
      # to update the code of all other post links in this project.
      permalink: /posts/:title/
  - scope:
      path: _drafts
    values:
      comments: false
  - scope:
      path: ""
      type: tabs # see `site.collections`
    values:
      layout: page
      #permalink: /:title/
      permalink: /:title/

sass:
  style: compressed

compress_html:
  clippings: all
  comments: all
  endings: all
  profile: false
  blanklines: false
  ignore:
    envs: [development]

exclude:
  - "*.gem"
  - "*.gemspec"
  - docs
  - tools
  - README.md
  - Chirpy_theme_fr.md
  - LICENSE
  - purgecss.js
  - rollup.config.js
  - "package*.json"

# enabled: [categories, tags]
jekyll-archives:
  enabled: [categories, tags]
  layouts:
    category: category
    tag: tag
  permalinks:
    tag: /tags/:name/
    category: /categories/:name/

plugins:
  - jemoji

Le fichier Gemfile $HOME/media/chirpy/Gemfile

1
2
3
4
5
6
7
8
9
10
11
12
13
# frozen_string_literal: true

source "https://rubygems.org"

gemspec

gem "html-proofer", "~> 5.0.10", group: :test

gem "tzinfo", ">= 1", "< 3"
gem "tzinfo-data"

gem "wdm", "~> 0.2.0"
gem 'jemoji'

Gemfile

Supprimer , si existant, le fichier Gemfile.lock

Bundle lit le fichier Gemfile

1
bundle # Patientez ...
1
2
Bundle complete! 5 Gemfile dependencies, 64 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

Info sur jekyll et créer un lien

1
bundle info jekyll
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  * jekyll (4.4.1)
	Summary: A simple, blog aware, static site generator.
	Homepage: https://jekyllrb.com
	Source Code: https://github.com/jekyll/jekyll
	Changelog: https://github.com/jekyll/jekyll/releases
	Bug Tracker: https://github.com/jekyll/jekyll/issues
	Path: $HOME/.local/share/gem/ruby/3.4.0/gems/jekyll-4.4.1
	Reverse Dependencies: 
		jekyll-archives (2.3.0) depends on jekyll (>= 3.6, < 5.0)
		jekyll-include-cache (0.2.1) depends on jekyll (>= 3.7, < 5.0)
		jekyll-redirect-from (0.16.0) depends on jekyll (>= 3.3, < 5.0)
		jekyll-seo-tag (2.8.0) depends on jekyll (>= 3.8, < 5.0)
		jekyll-sitemap (1.4.0) depends on jekyll (>= 3.7, < 5.0)
		jekyll-theme-chirpy (7.2.4) depends on jekyll (~> 4.3)
		jemoji (0.13.0) depends on jekyll (>= 3.0, < 5.0)

Création des liens avec les dossiers files, images et _posts pour le générateur de site

1
2
3
ln -s /srv/media/statique/images /srv/media/chirpy/images
ln -s /srv/media/statique/files /srv/media/chirpy/files
ln -s /srv/media/statique/_posts /srv/media/chirpy/_posts

Liens images, files et _posts

Création des liens pour la rédaction des documents markdown avec “ReText”

1
2
sudo ln -s /srv/media/statique/images /images
sudo ln -s /srv/media/statique/files /files

Génération dossier “chirpy”

Par défaut jekyll build génère le dossier _site
Destination: $HOME/sharenfs/rnmkcy/chirpy

1
2
cd ~/media/chirpy
bundle exec jekyll build --destination $HOME/sharenfs/rnmkcy/chirpy
1
2
3
4
5
6
7
8
Configuration file: /srv/media/chirpy/_config.yml
 Theme Config file: /srv/media/chirpy/_config.yml
            Source: /srv/media/chirpy
       Destination: $HOME/sharenfs/rnmkcy/chirpy
 Incremental build: disabled. Enable with --incremental
      Generating... 
                    done in 129.034 seconds.
 Auto-regeneration: disabled. Use --watch to enable.

Systemd chirpy.service

On veut générer un dossier nommé '_site'

PATH Jekyll : which bundle$HOME/.local/share/gem/ruby/3.3.0/bin/bundle

Pour lancer le serveur chirpy au démarrage, utilisation d’un service systemd utilisateur

Les variables environnement, générer le fichier

1
env > /srv/media/chirpy/.env_file

Création d’un service utilisateur “chirpy” sous systemd

1
2
mkdir -p ~/.config/systemd/user
nano ~/.config/systemd/user/chirpy.service

Contenu du fichier chirpy.service

1
2
3
4
5
6
7
8
9
10
[Unit]
Description=service chirpy

[Service]
EnvironmentFile=/srv/media/chirpy/.env_file
WorkingDirectory=/srv/media/chirpy
ExecStart=$HOME/.local/share/gem/ruby/3.4.0/bin/bundle exec jekyll build --incremental --watch --destination $HOME/sharenfs/rnmkcy/chirpy

[Install]
WantedBy=default.target

Lancer le service chirpy :

1
2
3
systemctl --user daemon-reload
# lancement et activation
systemctl --user enable chirpy --now

Vérifier

1
systemctl --user status chirpy

dire à systemd que l’instance d’un utilisateur soit tout le temps présente, du boot au shutdown, ce qui permet d’avoir des processus (services) utilisateurs qui tournent sans avoir de session ouverte.

1
sudo loginctl enable-linger $USER

Pour observer le fonctionnement du service chirpy depuis la machine virtuelle debian

1
journalctl -f --user-unit chirpy.service

ATTENTION: Option --incremental ne regénère pas la rubrique Récemment mis à jour
Pour une mise à jour systématique il faut supprimer l’option --incremental avec une incidence non négligeable sur le temps de construction (x10) du dossier _site

Surveillance dossier “chirpy”

Le but est de synchroniser le dossier ~/sharenfs/rnmkcy/chirpy avec le(s) serveur(s) web distant(s)
A chaque création, modification ou suppression d’un POST mardown le sous-dossier _site/ est reconstruit (jekyll build)
Avec les unités de chemin, vous pouvez surveiller les fichiers et les répertoires pour certains événements. Si un événement spécifique se produit, une unité de service est exécutée, et elle porte généralement le même nom que l’unité de chemin

Nous allons surveiller dans le dossier $HOME/sharenfs/rnmkcy/chirpy/ toute modification du fichier sitemap.xml qui entrainera l’exécution d’un script

Dans le répertoire systemd utilisateur nous créons une unité de cheminement media_chirpy_site.path

1
nano ~/.config/systemd/user/media_chirpy_site.path
1
2
3
4
5
6
7
8
9
[Unit]
Description=Surveiller sitemap.xml pour les changements

[Path]
PathChanged=$HOME/sharenfs/rnmkcy/chirpy/sitemap.xml
Unit=media_chirpy_site.service

[Install]
WantedBy=default.target

Dans la section [Path], PathChanged= indique le chemin absolu du fichier à surveiller, tandis que Unit= indique l’unité de service à exécuter si le fichier change. Cette unité (media_chirpy_site.path) doit être lancée lorsque le système est en mode multi-utilisateur.

Ensuite, nous créons l’unité de service correspondante, media_chirpy_site.service, dans le répertoire ~/.config/systemd/user/
Si le fichier sitemap.xml change (c’est-à-dire qu’il est à la fois écrit et fermé), l’unité de service suivante sera appelée pour exécuter le script spécifié :

1
nano ~/.config/systemd/user/media_chirpy_site.service
1
2
3
4
5
[Unit] 
Description="Exécute le script si site.xml a été modifié."

[Service]
ExecStart=$HOME/scripts/media_chirpy_site.sh

Le script $HOME/scripts/media_chirpy_site.sh lance une synchronisation locale distante via rsync ssh

Etendre Réduire media_chirpy_site.sh
#!/bin/bash

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Chaque modification du fichier site.xml dans le dossier local $HOME/sharenfs/rnmkcy/chirpy/
# déclenche une synchronisation du dossier local  avec le dossier distant '/home/yunohost.multimedia/share/Divers/_site' 
# des serveurs VPS Yunohost
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

# Fonction pour tester si le serveur est présent
# Host=$1 et Port=$2
# Réponse $?=0 -> OK  $?=1 -> NOK
host_ok () {
 nc -4 -d -z -w 1 $1 $2 &> /dev/null
}

synchro () {
# Synchronisation locale distante du dossier _site
host_ok $SERVER $PORT 
if [[ $? == 0 ]]
then



echo 'rsync -avz --progress --stats --human-readable --delete -e "ssh -p '$PORT' -i '$PRIVKEY'" '$REPLOC' '$USERDIS':'$REPDIS'/Divers/'
rsync -avz --progress --stats --human-readable --delete --rsync-path="$RSYNCMOD" -e "ssh -p $PORT -i $PRIVKEY" $REPLOC $USERDIS:$REPDIS/Divers/ > /dev/null

	 # Analyse résultat de la commande rsync
	 if [ ! $? -eq 0 ]; then 
		 #echo "Synchro $REPLOC avec $SERVER -> OK" | systemd-cat -t chirpy -p info 
		 #echo "Synchro $REPLOC avec $SERVER -> OK"
	 #else 
		 echo "Synchro $REPLOC avec $SERVER -> ERREUR" | systemd-cat -t chirpy -p emerg 
		 #echo "Synchro $REPLOC avec $SERVER -> ERREUR"
	 fi
else
    echo "Site $SERVER port $PORT Inaccessible !" | systemd-cat -t chirpy -p emerg
    #echo "Site $SERVER port $PORT Inaccessible !"
fi

}

#*******************************************************************
#
# DEPART SCRIPT
#
#*******************************************************************

# Tester la présence du fichier
if [ ! -f $HOME/scripts/media_chirpy_site.csv ]; then
    echo "Fichier media_chirpy_site.csv inexistant!" | systemd-cat -t chirpy -p emerg
    exit 1
fi

# Mesure temps exécution
begin=$(date +"%s")
echo "***DEPART*** Exécution script $0"
echo "***DEPART*** Exécution script $0" | systemd-cat -t chirpy -p info
#echo "Exécution script $0"

# Dossier local
REPLOC="$HOME/sharenfs/rnmkcy/chirpy" 

# Synchro serveurs
while IFS="," read -r SERVER REPDIS USERDIS PORT PRIVKEY RSYNCMOD LOCAL
do
  #echo " $SERVER $REPDIS $USERDIS $PORT $PRIVKEY $RSYNCMOD $LOCAL"
 
   if [[ "$LOCAL" != "oui" ]]; then
     # non --> Opération sur des sites distants
  		synchro
   fi
done < <(tail -n +2 $HOME/scripts/media_chirpy_site.csv)

# Calcul et affichage temps exécution
termin=$(date +"%s")
difftimelps=$(($termin-$begin))
echo "***FIN*** $0 exécuté en $(($difftimelps / 60)) mn $(($difftimelps % 60)) s" | systemd-cat -t chirpy -p info
echo "***FIN*** $0 exécuté en $(($difftimelps / 60)) mn $(($difftimelps % 60)) s"
notify-send "Synchronisation chirpy" "Terminée..."

exit 0

Lancer et activer la surveillance path

1
systemctl --user enable media_chirpy_site.path --now

Regénération complète

Le service chirpy avec l’option --incremental ne suffit pas en cas d’ajout de nouveau post ou de modifications des titres; Utiliser l’alias static pour regénérer avec une durée de 3 minutes et plus…

Ajouter un alias pour lancer la construction complète

1
2
echo "alias static='cd $HOME/media/chirpy && $HOME/.local/share/gem/ruby/3.4.0/bin/bundle exec $HOME/.local/share/gem/ruby/3.4.0/bin/jekyll build --destination $HOME/sharenfs/rnmkcy/chirpy && systemctl --user restart chirpy.service && cd $HOME'" >> $HOME/.bash_aliases
source $HOME/.bash_aliases
Cet article est sous licence CC BY 4.0 par l'auteur.